summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Schroeder <mls@suse.de>2014-05-15 14:48:30 +0200
committerMichael Schroeder <mls@suse.de>2014-05-15 14:48:30 +0200
commit3e66491a072e55bfb150092422dcfb374b97b630 (patch)
treed97c74a56bf779330685b26ca8fa8cae0c097601
parent77c0a018bfb0590b708141e5266b7cb0156ca639 (diff)
downloadlibsolv-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.i3
-rw-r--r--doc/libsolv-bindings.txt15
-rw-r--r--ext/testcase.c1
-rw-r--r--src/solver.c181
-rw-r--r--src/solver.h4
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 */