diff options
author | Michael Schroeder <mls@suse.de> | 2014-05-15 14:48:30 +0200 |
---|---|---|
committer | Michael Schroeder <mls@suse.de> | 2014-05-15 14:48:30 +0200 |
commit | 3e66491a072e55bfb150092422dcfb374b97b630 (patch) | |
tree | d97c74a56bf779330685b26ca8fa8cae0c097601 | |
parent | 77c0a018bfb0590b708141e5266b7cb0156ca639 (diff) | |
download | libsolv-3e66491a072e55bfb150092422dcfb374b97b630.tar.gz libsolv-3e66491a072e55bfb150092422dcfb374b97b630.tar.bz2 libsolv-3e66491a072e55bfb150092422dcfb374b97b630.zip |
add the SOLVER_FLAG_FOCUS_INSTALLED solver flag
Setting this flag means that the solver will prefer picking
a package version that fits the other installed packages
over updating installed packages.
-rw-r--r-- | bindings/solv.i | 3 | ||||
-rw-r--r-- | doc/libsolv-bindings.txt | 15 | ||||
-rw-r--r-- | ext/testcase.c | 1 | ||||
-rw-r--r-- | src/solver.c | 181 | ||||
-rw-r--r-- | src/solver.h | 4 |
5 files changed, 139 insertions, 65 deletions
diff --git a/bindings/solv.i b/bindings/solv.i index 3f88a8b..6816183 100644 --- a/bindings/solv.i +++ b/bindings/solv.i @@ -2758,6 +2758,9 @@ rb_eval_string( static const int SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE = SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE; static const int SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE = SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE; static const int SOLVER_FLAG_DUP_ALLOW_NAMECHANGE = SOLVER_FLAG_DUP_ALLOW_NAMECHANGE; + static const int SOLVER_FLAG_KEEP_ORPHANS = SOLVER_FLAG_KEEP_ORPHANS; + static const int SOLVER_FLAG_BREAK_ORPHANS = SOLVER_FLAG_BREAK_ORPHANS; + static const int SOLVER_FLAG_FOCUS_INSTALLED = SOLVER_FLAG_FOCUS_INSTALLED; static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED; static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE; diff --git a/doc/libsolv-bindings.txt b/doc/libsolv-bindings.txt index 5a65235..b4f5609 100644 --- a/doc/libsolv-bindings.txt +++ b/doc/libsolv-bindings.txt @@ -2081,6 +2081,21 @@ installed packages, which may conflict with the set policy. Do not enable auto-targeting up update and distupgrade jobs. See the section on targeted updates for more information. +*SOLVER_FLAG_KEEP_ORPHANS*:: +Do not allow orphaned packages to be deinstalled if they get +in the way of resolving other packages. + +*SOLVER_FLAG_BREAK_ORPHANS*:: +Ignore dependencies of orphaned packages that get in the way +of resolving non-orphaned ones. Setting the flag might result +in no longer working packages in case they are orphaned. + +*SOLVER_FLAG_FOCUS_INSTALLED*:: +Resolve installed packages before resolving the given job. +Setting this flag means that the solver will prefer picking +a package version that fits the other installed packages +over updating installed packages. + Basic rule types: *SOLVER_RULE_UNKNOWN*:: diff --git a/ext/testcase.c b/ext/testcase.c index 32547c8..3da7aff 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -104,6 +104,7 @@ static struct solverflags2str { { SOLVER_FLAG_DUP_ALLOW_NAMECHANGE, "dupallownamechange", 1 }, { SOLVER_FLAG_KEEP_ORPHANS, "keeporphans", 0 }, { SOLVER_FLAG_BREAK_ORPHANS, "breakorphans", 0 }, + { SOLVER_FLAG_FOCUS_INSTALLED, "focusinstalled", 0 }, { 0, 0, 0 } }; diff --git a/src/solver.c b/src/solver.c index 065cb7f..c519bea 100644 --- a/src/solver.c +++ b/src/solver.c @@ -1250,6 +1250,8 @@ revert(Solver *solv, int level) } if (solv->recommends_index > solv->decisionq.count) solv->recommends_index = -1; /* rebuild recommends/suggests maps */ + if (solv->decisionq.count < solv->decisioncnt_jobs) + solv->decisioncnt_jobs = 0; if (solv->decisionq.count < solv->decisioncnt_update) solv->decisioncnt_update = 0; if (solv->decisionq.count < solv->decisioncnt_keep) @@ -1448,7 +1450,9 @@ selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid break; } } - if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed) + /* if we're resolving job rules and didn't resolve the installed packages yet, + * do some special supplements ordering */ + if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed && !solv->focus_installed) reorder_dq_for_jobrules(solv, level, dq); if (dq->count > 1) { @@ -1527,6 +1531,83 @@ solver_create(Pool *pool) } +static int +resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq) +{ + Pool *pool = solv->pool; + int oldlevel = level; + int i, olevel; + Rule *r; + + POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); + if (!solv->decisioncnt_jobs) + solv->decisioncnt_jobs = solv->decisionq.count; + for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) + { + Id l, pp; + if (r->d < 0) /* ignore disabled rules */ + continue; + queue_empty(dq); + FOR_RULELITERALS(l, pp, r) + { + if (l < 0) + { + if (solv->decisionmap[-l] <= 0) + break; + } + else + { + if (solv->decisionmap[l] > 0) + break; + if (solv->decisionmap[l] == 0) + queue_push(dq, l); + } + } + if (l || !dq->count) + continue; + /* prune to installed if not updating */ + if (dq->count > 1 && solv->installed && !solv->updatemap_all && + !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE)) + { + int j, k; + for (j = k = 0; j < dq->count; j++) + { + Solvable *s = pool->solvables + dq->elements[j]; + if (s->repo == solv->installed) + { + dq->elements[k++] = dq->elements[j]; + if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start)) + { + k = 0; /* package wants to be updated, do not prune */ + break; + } + } + } + if (k) + dq->count = k; + } + olevel = level; + level = selectandinstall(solv, level, dq, disablerules, i); + if (level <= olevel) + { + if (level == 0) + return 0; /* unsolvable */ + if (level == olevel) + { + i--; + r--; + continue; /* try something else */ + } + if (level < oldlevel) + return level; + /* redo from start of jobrules */ + i = solv->jobrules - 1; + r = solv->rules + i; + } + } + return level; +} + /*------------------------------------------------------------------- * * solver_free @@ -1644,6 +1725,8 @@ solver_get_flag(Solver *solv, int flag) return solv->keep_orphans; case SOLVER_FLAG_BREAK_ORPHANS: return solv->break_orphans; + case SOLVER_FLAG_FOCUS_INSTALLED: + return solv->focus_installed; default: break; } @@ -1713,6 +1796,9 @@ solver_set_flag(Solver *solv, int flag, int value) case SOLVER_FLAG_BREAK_ORPHANS: solv->break_orphans = value; break; + case SOLVER_FLAG_FOCUS_INSTALLED: + solv->focus_installed = value; + break; default: break; } @@ -1992,74 +2078,27 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) } /* - * resolve jobs first + * resolve jobs first (unless focus_installed is set) */ - if (level < systemlevel) + if (level < systemlevel && !solv->focus_installed) { - POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); - for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) + olevel = level; + level = resolve_jobrules(solv, level, disablerules, &dq); + if (level < olevel) { - Id l; - if (r->d < 0) /* ignore disabled rules */ - continue; - queue_empty(&dq); - FOR_RULELITERALS(l, pp, r) - { - if (l < 0) - { - if (solv->decisionmap[-l] <= 0) - break; - } - else - { - if (solv->decisionmap[l] > 0) - break; - if (solv->decisionmap[l] == 0) - queue_push(&dq, l); - } - } - if (l || !dq.count) - continue; - /* prune to installed if not updating */ - if (dq.count > 1 && solv->installed && !solv->updatemap_all && - !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE)) - { - int j, k; - for (j = k = 0; j < dq.count; j++) - { - Solvable *s = pool->solvables + dq.elements[j]; - if (s->repo == solv->installed) - { - dq.elements[k++] = dq.elements[j]; - if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start)) - { - k = 0; /* package wants to be updated, do not prune */ - break; - } - } - } - if (k) - dq.count = k; - } - olevel = level; - level = selectandinstall(solv, level, &dq, disablerules, i); if (level == 0) - break; - if (level <= olevel) - break; + break; /* unsolvable */ + continue; } - if (level == 0) - break; /* unsolvable */ systemlevel = level + 1; - if (i < solv->jobrules_end) - continue; - if (!solv->decisioncnt_update) - solv->decisioncnt_update = solv->decisionq.count; } + /* * installed packages */ + if (!solv->decisioncnt_update) + solv->decisioncnt_update = solv->decisionq.count; if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) { Repo *installed = solv->installed; @@ -2232,6 +2271,19 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) if (!solv->decisioncnt_keep) solv->decisioncnt_keep = solv->decisionq.count; + if (level < systemlevel && solv->focus_installed) + { + olevel = level; + level = resolve_jobrules(solv, level, disablerules, &dq); + if (level < olevel) + { + if (level == 0) + break; /* unsolvable */ + continue; + } + systemlevel = level + 1; + } + if (level < systemlevel) systemlevel = level; @@ -2828,6 +2880,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) if (level == 0) { /* unsolvable */ + solv->decisioncnt_jobs = solv->decisionq.count; solv->decisioncnt_update = solv->decisionq.count; solv->decisioncnt_keep = solv->decisionq.count; solv->decisioncnt_resolve = solv->decisionq.count; @@ -3307,7 +3360,7 @@ solver_solve(Solver *solv, Queue *job) memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id)); queue_empty(&solv->decisionq); queue_empty(&solv->decisionq_why); - solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; + solv->decisioncnt_jobs = solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; queue_empty(&solv->learnt_why); queue_empty(&solv->learnt_pool); queue_empty(&solv->branches); @@ -4310,12 +4363,10 @@ solver_describe_decision(Solver *solv, Id p, Id *infop) if (why > 0) return SOLVER_REASON_UNIT_RULE; why = -why; + if (i == 0) + return SOLVER_REASON_KEEP_INSTALLED; /* the systemsolvable */ if (i < solv->decisioncnt_update) - { - if (i == 0) - return SOLVER_REASON_KEEP_INSTALLED; - return SOLVER_REASON_RESOLVE_JOB; - } + return SOLVER_REASON_RESOLVE_JOB; if (i < solv->decisioncnt_keep) { if (why == 0 && pp < 0) @@ -4324,6 +4375,8 @@ solver_describe_decision(Solver *solv, Id p, Id *infop) } if (i < solv->decisioncnt_resolve) { + if (solv->focus_installed && i >= solv->decisioncnt_jobs) + return SOLVER_REASON_RESOLVE_JOB; if (why == 0 && pp < 0) return SOLVER_REASON_CLEANDEPS_ERASE; return SOLVER_REASON_KEEP_INSTALLED; diff --git a/src/solver.h b/src/solver.h index c8f51fc..3d63b6f 100644 --- a/src/solver.h +++ b/src/solver.h @@ -109,6 +109,7 @@ struct _Solver { * > 0: level of decision when installed, * < 0: level of decision when conflict */ + int decisioncnt_jobs; int decisioncnt_update; int decisioncnt_keep; int decisioncnt_resolve; @@ -159,7 +160,7 @@ struct _Solver { int keepexplicitobsoletes; /* true: honor obsoletes during multiinstall */ int bestobeypolicy; /* true: stay in policy with the best rules */ int noautotarget; /* true: do not assume targeted for up/dup jobs that contain no installed solvable */ - + int focus_installed; /* true: resolve update rules first */ Map dupmap; /* dup these packages*/ int dupmap_all; /* dup all packages */ @@ -287,6 +288,7 @@ typedef struct _Solver Solver; #define SOLVER_FLAG_DUP_ALLOW_NAMECHANGE 17 #define SOLVER_FLAG_KEEP_ORPHANS 18 #define SOLVER_FLAG_BREAK_ORPHANS 19 +#define SOLVER_FLAG_FOCUS_INSTALLED 20 #define GET_USERINSTALLED_NAMES (1 << 0) /* package names instead if ids */ #define GET_USERINSTALLED_INVERTED (1 << 1) /* autoinstalled */ |