[PATCH setup 00/14] Use libsolv, solve all our problems... (WIP)
Jon Turney
jon.turney@dronecode.org.uk
Tue Jan 9 13:25:00 GMT 2018
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.
-------------- next part --------------
From a60bbd19aa5504e0e7da6722dc7f3b81ac3afd6b Mon Sep 17 00:00:00 2001
From: Jon Turney <jon.turney@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
More information about the Cygwin-apps
mailing list