On 24/12/2017 15:00, Ken Brown wrote:
On 12/13/2017 5:31 PM, Ken Brown wrote:
On 12/13/2017 1:05 PM, Achim Gratz wrote:
Ken Brown writes:
1. Uninstall A.
2. Don't uninstall B.
On the surface, it would seem that libsolv chose 2 by default, because
it returned an empty transaction list. This was reflected in the log
and was also clear when I selected 'Back'.
Yeah, I think what is actually happening here is that the solver returns
a partial solution, without the problematic transaction.
But yeah, there's no real concept of a default solution, so (lacking a
UI to choose, which I think is a bit out of scope for the moment), it's
up to us to define one.
I don't think there is a default in this case. I also see in zypper
that the order of the proposed solutions (there can be way more than two
if the dependencies are more complicated) is not always the same, so
there is no preference implied by the order as well.
Maybe we have to deal with this situation ourselves. Whenever a
problem involves a missing dependency, we could choose as default
solution the one that installs/keeps the dependent package, as is
currently done.
That solution unfortunately isn't always the one that causes the least
amount of transactions or even the least amount of breakage.
That may be true, but I still think it's a reasonable default. The
user doesn't have to accept it. Also, it's consistent with what setup
currently does, so it won't surprise anyone.
The attached patch attempts to implement my suggestion.
I came up with a slightly different solution of just picking the first
solution as a default.
After solving problems we also need to consider the 'install source for
everything I install' flag, which unfortunately requires quite a bit of
refactoring.
See attached.
From a60bbd19aa5504e0e7da6722dc7f3b81ac3afd6b Mon Sep 17 00:00:00 2001
From: Jon Turney <jon.tur...@dronecode.org.uk>
Date: Wed, 6 Dec 2017 17:52:45 +0000
Subject: [PATCH setup] Apply default solution(s)
Refactoring of SolverSolution::update() so we can apply the default
solution.
Also:
Break out logging of the task list, so we can show it in the "dependency
problems exists, but don't use the default solution, just do what I ask"
case.
Break out 'include-source' process, so it can have effect in the case where
dependency problems exist.
---
libsolv.cc | 83 ++++++++++++++++++++++++++++++++++++++++++++---------------
libsolv.h | 11 ++++++--
package_db.cc | 2 +-
prereq.cc | 28 ++++++++++++++++----
prereq.h | 4 +++
5 files changed, 99 insertions(+), 29 deletions(-)
diff --git a/libsolv.cc b/libsolv.cc
index 0fb39c7..34af50b 100644
--- a/libsolv.cc
+++ b/libsolv.cc
@@ -544,6 +544,7 @@ SolverTasks::setTasks()
{
// go through all packages, adding changed ones to the solver task list
packagedb db;
+ tasks.clear();
for (packagedb::packagecollection::iterator p = db.packages.begin ();
p != db.packages.end (); ++p)
@@ -602,6 +603,11 @@ SolverPool::use_test_packages(bool use_test_packages)
// A wrapper around the libsolv solver
// ---------------------------------------------------------------------------
+SolverSolution::SolverSolution(SolverPool &_pool) : pool(_pool), solv(NULL)
+{
+ queue_init(&job);
+}
+
SolverSolution::~SolverSolution()
{
clear();
@@ -615,6 +621,7 @@ SolverSolution::clear()
solver_free(solv);
solv = NULL;
}
+ queue_free(&job);
}
void
@@ -713,18 +720,9 @@ std::ostream &operator<<(std::ostream &stream,
return stream;
}
-bool
-SolverSolution::update(SolverTasks &tasks, updateMode update, bool
use_test_packages, bool include_source)
+void
+SolverSolution::tasksToJobs(SolverTasks &tasks, updateMode update, Queue &job)
{
- Log (LOG_PLAIN) << "solving: " << tasks.tasks.size() << " tasks," <<
- " update: " << (update ? "yes" : "no") << "," <<
- " use test packages: " << (use_test_packages ? "yes" : "no") << "," <<
- " include_source: " << (include_source ? "yes" : "no") << endLog;
-
- pool.use_test_packages(use_test_packages);
-
- Queue job;
- queue_init(&job);
// solver accepts a queue containing pairs of (cmd, id) tasks
// cmd is job and selection flags ORed together
for (SolverTasks::taskList::const_iterator i = tasks.tasks.begin();
@@ -745,11 +743,11 @@ SolverSolution::update(SolverTasks &tasks, updateMode
update, bool use_test_pack
// we don't know how to ask solver for this, so we just add the erase
// and install later
break;
- case SolverTasks::taskKeep:
- queue_push2(&job, SOLVER_LOCK | SOLVER_SOLVABLE, sv.id);
- break;
- case SolverTasks::taskSkip:
- queue_push2(&job, SOLVER_LOCK | SOLVER_SOLVABLE_NAME, sv.name_id());
+ case SolverTasks::taskKeep:
+ queue_push2(&job, SOLVER_LOCK | SOLVER_SOLVABLE, sv.id);
+ break;
+ case SolverTasks::taskSkip:
+ queue_push2(&job, SOLVER_LOCK | SOLVER_SOLVABLE_NAME, sv.name_id());
break;
default:
Log (LOG_PLAIN) << "unknown task " << (*i).second << endLog;
@@ -776,6 +774,19 @@ SolverSolution::update(SolverTasks &tasks, updateMode
update, bool use_test_pack
// Ask solver to check dependencies of installed packages.
queue_push2(&job, SOLVER_VERIFY | SOLVER_SOLVABLE_ALL, 0);
+}
+
+bool
+SolverSolution::update(SolverTasks &tasks, updateMode update, bool
use_test_packages)
+{
+ Log (LOG_PLAIN) << "solving: " << tasks.tasks.size() << " tasks," <<
+ " update: " << (update ? "yes" : "no") << "," <<
+ " use test packages: " << (use_test_packages ? "yes" : "no") << "," <<
endLog;
+
+ pool.use_test_packages(use_test_packages);
+
+ queue_free(&job);
+ tasksToJobs(tasks, update, job);
if (!solv)
solv = solver_create(pool.pool);
@@ -785,11 +796,18 @@ SolverSolution::update(SolverTasks &tasks, updateMode
update, bool use_test_pack
solver_set_flag(solv, SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE, 1);
solver_set_flag(solv, SOLVER_FLAG_DUP_ALLOW_DOWNGRADE, 1);
solver_solve(solv, &job);
- queue_free(&job);
int pcnt = solver_problem_count(solv);
solver_printdecisions(solv);
+ solutionToTransactionList();
+
+ return (pcnt == 0);
+}
+
+void
+SolverSolution::solutionToTransactionList()
+{
// get transactions for solution
Transaction *t = solver_create_transaction(solv);
transaction_order(t, 0);
@@ -797,7 +815,6 @@ SolverSolution::update(SolverTasks &tasks, updateMode
update, bool use_test_pack
// massage into SolverTransactions form
trans.clear();
-
for (int i = 0; i < t->steps.count; i++)
{
Id id = t->steps.elements[i];
@@ -806,6 +823,14 @@ SolverSolution::update(SolverTasks &tasks, updateMode
update, bool use_test_pack
trans.push_back(SolverTransaction(SolvableVersion(id, pool.pool), tt));
}
+ transaction_free(t);
+
+ dumpTransactionList();
+}
+
+void
+SolverSolution::augmentTasks(SolverTasks &tasks)
+{
// add install and remove tasks for anything marked as reinstall
for (SolverTasks::taskList::const_iterator i = tasks.tasks.begin();
i != tasks.tasks.end();
@@ -821,7 +846,11 @@ SolverSolution::update(SolverTasks &tasks, updateMode
update, bool use_test_pack
SolverTransaction::transInstall));
}
}
+}
+void
+SolverSolution::addSource(bool include_source)
+{
// if include_source mode is on, also install source for everything we are
// installing
if (include_source)
@@ -840,11 +869,15 @@ SolverSolution::update(SolverTasks &tasks, updateMode
update, bool use_test_pack
}
}
}
+}
+void
+SolverSolution::dumpTransactionList() const
+{
if (trans.size())
{
Log (LOG_PLAIN) << "Augmented Transaction List:" << endLog;
- for (SolverTransactionList::iterator i = trans.begin ();
+ for (SolverTransactionList::const_iterator i = trans.begin ();
i != trans.end ();
++i)
{
@@ -854,10 +887,17 @@ SolverSolution::update(SolverTasks &tasks, updateMode
update, bool use_test_pack
<< std::setw(20) << i->version.Canonical_version()
<< endLog;
}
}
+ else
+ Log (LOG_PLAIN) << "Augmented Transaction List: is empty" << endLog;
+}
- transaction_free(t);
+void SolverSolution::applyDefaultProblemSolutions()
+{
+ int pcnt = solver_problem_count(solv);
+ for (Id problem = 1; problem <= pcnt; problem++)
+ solver_take_solution(solv, problem, 1, &job);
- return (pcnt == 0);
+ solutionToTransactionList();
}
const SolverTransactionList &
@@ -891,6 +931,7 @@ SolverSolution::report() const
for (Id solution = 1; solution <= scnt; solution++)
{
r += "Solution " + std::to_string(solution) + "/" +
std::to_string(scnt);
+ if (solution == 1) r += " (default)";
r += "\n";
Id p, rp, element;
diff --git a/libsolv.h b/libsolv.h
index cddf76f..78b6881 100644
--- a/libsolv.h
+++ b/libsolv.h
@@ -236,7 +236,7 @@ typedef std::vector<SolverTransaction>
SolverTransactionList;
class SolverSolution
{
public:
- SolverSolution(SolverPool &_pool) : pool(_pool), solv(NULL) {};
+ SolverSolution(SolverPool &_pool);
~SolverSolution();
void clear();
@@ -252,16 +252,23 @@ class SolverSolution
updateBest, // update to best version
updateForce, // distupdate: downgrade if necessary to best version in repo
};
- bool update(SolverTasks &tasks, updateMode update, bool use_test_packages,
bool include_source);
+ bool update(SolverTasks &tasks, updateMode update, bool use_test_packages);
+ void augmentTasks(SolverTasks &tasks);
+ void addSource(bool include_source);
+ void applyDefaultProblemSolutions();
std::string report() const;
const SolverTransactionList &transactions() const;
+ void dumpTransactionList() const;
private:
static SolverTransaction::transType type(Transaction *trans, int pos);
+ void tasksToJobs(SolverTasks &tasks, updateMode update, Queue &job);
+ void solutionToTransactionList();
SolverPool &pool;
Solver *solv;
+ Queue job;
SolverTransactionList trans;
};
diff --git a/package_db.cc b/package_db.cc
index 92fe4f9..e2443bf 100644
--- a/package_db.cc
+++ b/package_db.cc
@@ -602,7 +602,7 @@ packagedb::fillMissingCategory ()
void
packagedb::defaultTrust (SolverTasks &q, SolverSolution::updateMode mode, bool
test)
{
- solution.update(q, mode, test, FALSE);
+ solution.update(q, mode, test);
// reflect that task list into packagedb
solution.trans2db();
diff --git a/prereq.cc b/prereq.cc
index bf7661a..5b3e785 100644
--- a/prereq.cc
+++ b/prereq.cc
@@ -90,6 +90,7 @@ long
PrereqPage::OnNext ()
{
HWND h = GetHWND ();
+ packagedb db;
if (!IsDlgButtonChecked (h, IDC_PREREQ_CHECK))
{
@@ -109,10 +110,16 @@ PrereqPage::OnNext ()
"NOTE! User refused the default solutions! "
"Expect some packages to give errors or not function at all." <<
endLog;
// Change the solver's transaction list to reflect the user's choices.
- packagedb db;
db.solution.db2trans();
}
}
+ else
+ {
+ db.solution.applyDefaultProblemSolutions();
+ }
+
+ PrereqChecker p;
+ p.finalize();
return whatNext();
}
@@ -157,8 +164,9 @@ PrereqPage::OnUnattended ()
// implements class PrereqChecker
// ---------------------------------------------------------------------------
-// instantiate the static member
+// instantiate the static members
bool PrereqChecker::use_test_packages;
+SolverTasks PrereqChecker::q;
bool
PrereqChecker::isMet ()
@@ -170,11 +178,19 @@ PrereqChecker::isMet ()
Progress.SetText3 ("");
// Create task list corresponding to current state of package database
- SolverTasks q;
q.setTasks();
- // apply solver to those tasks and global state (use test, include source)
- return db.solution.update(q, SolverSolution::keep, use_test_packages,
IncludeSource);
+ // apply solver to those tasks and global state (use test or not)
+ return db.solution.update(q, SolverSolution::keep, use_test_packages);
+}
+
+void
+PrereqChecker::finalize ()
+{
+ packagedb db;
+ db.solution.augmentTasks(q);
+ db.solution.addSource(IncludeSource);
+ db.solution.dumpTransactionList();
}
/* Formats problems and solutions as a string for display to the user. */
@@ -205,6 +221,8 @@ do_prereq_check_thread(HINSTANCE h, HWND owner)
if (p.isMet ())
{
+ p.finalize();
+
if (source == IDC_SOURCE_LOCALDIR)
Progress.SetActivateTask (WM_APP_START_INSTALL); // install
else
diff --git a/prereq.h b/prereq.h
index 5ae9323..f1561fa 100644
--- a/prereq.h
+++ b/prereq.h
@@ -40,10 +40,14 @@ public:
// formats 'unmet' as a string for display
void getUnmetString (std::string &s);
+ // finialize the transaction list
+ void finalize ();
+
static void setTestPackages (bool t) { use_test_packages = t; };
private:
static bool use_test_packages;
+ static SolverTasks q;
};
#endif /* SETUP_PREREQ_H */
--
2.15.1