This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "New approach to dependency solving".
The branch, master has been updated
via 37a54d8eaf7d7ec4ed798e6283ceae0901eb46ae (commit)
from 35a996fb2990eb685519ddf1530ba197f3b6190e (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 37a54d8eaf7d7ec4ed798e6283ceae0901eb46ae
Author: Michael Schroeder
Date: Mon Jan 19 16:01:18 2009 +0100
- add inferior arch handling
- add installcheck tool
- add support for repo local distupgrades
- add debian version compare function
-----------------------------------------------------------------------
Summary of changes and diff:
src/evr.c | 49 +++-
src/knownid.h | 2 +
src/pool.c | 7 +-
src/solver.c | 687 ++++++++++++++++++++++++++++++++----------
src/solver.h | 15 +-
src/solverdebug.c | 28 ++-
tests/solver/deptestomatic.c | 23 ++
tests/solver/yps.c | 6 +-
tools/CMakeLists.txt | 3 +
tools/installcheck.c | 314 +++++++++++++++++++
10 files changed, 968 insertions(+), 166 deletions(-)
create mode 100644 tools/installcheck.c
diff --git a/src/evr.c b/src/evr.c
index 28d16ca..b01adeb 100644
--- a/src/evr.c
+++ b/src/evr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, Novell Inc.
+ * Copyright (c) 2007-2009, Novell Inc.
*
* This program is licensed under the BSD license, read LICENSE.BSD
* for further information
@@ -16,6 +16,50 @@
#include "evr.h"
#include "pool.h"
+
+#ifdef DEBIAN_SEMANTICS
+
+int
+vercmp(const char *s1, const char *q1, const char *s2, const char *q2)
+{
+ int r, c1, c2;
+ while (1)
+ {
+ c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
+ c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
+ if ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
+ {
+ while (c1 == '0')
+ c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
+ while (c2 == '0')
+ c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
+ r = 0;
+ while ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
+ {
+ if (!r)
+ r = c1 - c2;
+ c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
+ c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
+ }
+ if (c1 >= '0' && c1 <= '9')
+ return 1;
+ if (c2 >= '0' && c2 <= '9')
+ return -1;
+ if (r)
+ return r < 0 ? -1 : 1;
+ }
+ c1 = c1 == '~' ? -1 : !c1 || (c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'Z') || (c1 >= 'a' && c1 <= 'z') ? c1 : c1 + 256;
+ c2 = c2 == '~' ? -1 : !c2 || (c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'Z') || (c2 >= 'a' && c2 <= 'z') ? c2 : c2 + 256;
+ r = c1 - c2;
+ if (r)
+ return r < 0 ? -1 : 1;
+ if (!c1)
+ return 0;
+ }
+}
+
+#else
+
int
vercmp(const char *s1, const char *q1, const char *s2, const char *q2)
{
@@ -73,6 +117,9 @@ vercmp(const char *s1, const char *q1, const char *s2, const char *q2)
return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
}
+#endif
+
+
/* edition (e:v-r) compare */
int
evrcmp_str(Pool *pool, const char *evr1, const char *evr2, int mode)
diff --git a/src/knownid.h b/src/knownid.h
index b2567ea..a2ee407 100644
--- a/src/knownid.h
+++ b/src/knownid.h
@@ -207,6 +207,8 @@ KNOWNID(DELTA_SEQ_NAME, "delta:seqname"),
KNOWNID(DELTA_SEQ_EVR, "delta:seqevr"),
KNOWNID(DELTA_SEQ_NUM, "delta:seqnum"),
+KNOWNID(NAMESPACE_PRODUCTBUDDY, "namespace:productbuddy"),
+
KNOWNID(ID_NUM_INTERNAL, 0)
#ifdef KNOWNID_INITIALIZE
diff --git a/src/pool.c b/src/pool.c
index 39b60b5..f35ca8f 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, Novell Inc.
+ * Copyright (c) 2007-2009, Novell Inc.
*
* This program is licensed under the BSD license, read LICENSE.BSD
* for further information
@@ -636,8 +636,13 @@ pool_addrelproviders(Pool *pool, Id d)
else
{
int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
+#ifdef DEBIAN_SEMANTICS
+ if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_COMPARE)))) != 0)
+ break;
+#else
if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
break;
+#endif
}
}
if (!pid)
diff --git a/src/solver.c b/src/solver.c
index fd547d5..71c957c 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -478,6 +478,26 @@ disableproblem(Solver *solv, Id v)
if (v > 0)
{
+ if (v >= solv->infarchrules && v < solv->infarchrules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[v].p].name;
+ while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
+ v--;
+ for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+ disablerule(solv, solv->rules + v);
+ return;
+ }
+ if (v >= solv->duprules && v < solv->duprules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[v].p].name;
+ while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
+ v--;
+ for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+ disablerule(solv, solv->rules + v);
+ return;
+ }
disablerule(solv, solv->rules + v);
return;
}
@@ -501,6 +521,26 @@ enableproblem(Solver *solv, Id v)
if (v > 0)
{
+ if (v >= solv->infarchrules && v < solv->infarchrules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[v].p].name;
+ while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
+ v--;
+ for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+ enablerule(solv, solv->rules + v);
+ return;
+ }
+ if (v >= solv->duprules && v < solv->duprules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[v].p].name;
+ while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
+ v--;
+ for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+ enablerule(solv, solv->rules + v);
+ return;
+ }
if (v >= solv->featurerules && v < solv->featurerules_end)
{
/* do not enable feature rule if update rule is enabled */
@@ -850,7 +890,10 @@ enableweakrules(Solver *solv)
/* FIXME: maybe also look at SOLVER_INSTALL|SOLVABLE_ONE_OF */
/*-------------------------------------------------------------------
- * disable update rules
+ * disable update rules depending on enabled job
+ * if jobidx is set we just disabled this job, so we may want
+ * to re-enable some rules
+ * otherwise we disable all update rules that conflict with some job.
*/
static void
@@ -863,10 +906,9 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
Repo *installed;
Rule *r;
Id lastjob = -1;
+ Map nolockrules;
installed = solv->installed;
- if (!installed)
- return;
if (jobidx != -1)
{
@@ -885,6 +927,7 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
}
}
/* go through all enabled job rules */
+ map_init(&nolockrules, pool->nsolvables);
MAPZERO(&solv->noupdate);
for (i = solv->jobrules; i < solv->jobrules_end; i++)
{
@@ -904,6 +947,14 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
if (select != SOLVER_SOLVABLE)
break;
s = pool->solvables + what;
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ Solvable *ps = pool->solvables + p;
+ if (ps->name == s->name)
+ MAPSET(&nolockrules, p);
+ }
+ if (!installed)
+ break;
if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, what))
break;
if (s->repo == installed)
@@ -918,22 +969,27 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
while ((obs = *obsp++) != 0)
FOR_PROVIDES(p, pp, obs)
{
- if (pool->solvables[p].repo != installed)
+ Solvable *ps = pool->solvables + p;
+ if (ps->repo != installed)
continue;
- if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p, obs))
+ if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
continue;
MAPSET(&solv->noupdate, p - installed->start);
}
}
FOR_PROVIDES(p, pp, s->name)
{
- if (!solv->implicitobsoleteusesprovides && pool->solvables[p].name != s->name)
+ Solvable *ps = pool->solvables + p;
+ if (ps->repo != installed)
+ continue;
+ if (!solv->implicitobsoleteusesprovides && ps->name != s->name)
continue;
- if (pool->solvables[p].repo == installed)
- MAPSET(&solv->noupdate, p - installed->start);
+ MAPSET(&solv->noupdate, p - installed->start);
}
break;
case SOLVER_ERASE:
+ if (!installed)
+ break;
FOR_JOB_SELECT(p, pp, select, what)
if (pool->solvables[p].repo == installed)
MAPSET(&solv->noupdate, p - installed->start);
@@ -951,6 +1007,35 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
how = job->elements[jobidx];
what = job->elements[jobidx + 1];
select = how & SOLVER_SELECTMASK;
+ if ((how & SOLVER_JOBMASK) == SOLVER_INSTALL && select == SOLVER_SOLVABLE)
+ {
+ /* check if we need to enable some lock rule */
+ for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
+ {
+ if (r->p != -what || r->d >= 0 || !MAPTST(&nolockrules, -r->p))
+ continue;
+ enablerule(solv, r);
+ IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
+ {
+ POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+ solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r);
+ }
+ }
+ for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
+ {
+ if (r->p != -what || r->d >= 0 || !MAPTST(&nolockrules, -r->p))
+ continue;
+ enablerule(solv, r);
+ IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
+ {
+ POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+ solver_printrule(solv, SAT_DEBUG_SOLUTIONS, r);
+ }
+ }
+ }
+ map_free(&nolockrules);
+ if (!installed)
+ return;
switch (how & SOLVER_JOBMASK)
{
case SOLVER_INSTALL:
@@ -1039,14 +1124,28 @@ disableupdaterules(Solver *solv, Queue *job, int jobidx)
return;
}
- for (i = 0; i < installed->nsolvables; i++)
+ for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
{
- r = solv->rules + solv->updaterules + i;
- if (r->d >= 0 && MAPTST(&solv->noupdate, i))
- disablerule(solv, r); /* was enabled, need to disable */
- r = solv->rules + solv->featurerules + i;
- if (r->d >= 0 && MAPTST(&solv->noupdate, i))
- disablerule(solv, r); /* was enabled, need to disable */
+ if (r->p < 0 && r->d >= 0 && MAPTST(&nolockrules, -r->p))
+ disablerule(solv, r); /* was enabled, need to disable */
+ }
+ for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
+ {
+ if (r->p < 0 && r->d >= 0 && MAPTST(&nolockrules, -r->p))
+ disablerule(solv, r); /* was enabled, need to disable */
+ }
+ map_free(&nolockrules);
+ if (installed)
+ {
+ for (i = 0; i < installed->nsolvables; i++)
+ {
+ r = solv->rules + solv->updaterules + i;
+ if (r->d >= 0 && MAPTST(&solv->noupdate, i))
+ disablerule(solv, r); /* was enabled, need to disable */
+ r = solv->rules + solv->featurerules + i;
+ if (r->d >= 0 && MAPTST(&solv->noupdate, i))
+ disablerule(solv, r); /* was enabled, need to disable */
+ }
}
}
@@ -1176,6 +1275,17 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
addrule(solv, -n, 0); /* uninstallable */
}
+ /* yet another SUSE hack, sigh */
+ if (pool->nscallback && !strncmp("product:", id2str(pool, s->name), 8))
+ {
+ Id buddy = pool->nscallback(pool, pool->nscallbackdata, NAMESPACE_PRODUCTBUDDY, n);
+ if (buddy > 0 && buddy != SYSTEMSOLVABLE && buddy != n && buddy < pool->nsolvables)
+ {
+ addrule(solv, n, -buddy);
+ addrule(solv, buddy, -n);
+ }
+ }
+
/*-----------------------------------------
* check requires of s
*/
@@ -1466,12 +1576,13 @@ finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
if (!qs->count)
{
if (allow_all)
- return 0;
+ return 0; /* orphaned, don't create feature rule */
+ /* check if this is an orphaned package */
policy_findupdatepackages(solv, s, qs, 1);
if (!qs->count)
- return 0; /* orphaned */
+ return 0; /* orphaned, don't create update rule */
qs->count = 0;
- return -SYSTEMSOLVABLE;
+ return -SYSTEMSOLVABLE; /* supported but not installable */
}
if (allow_all)
return s - pool->solvables;
@@ -1486,6 +1597,30 @@ finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
return -SYSTEMSOLVABLE;
}
+/* add packages from the dup repositories to the update candidates
+ * this isn't needed for the global dup mode as all packages are
+ * from dup repos in that case */
+static void
+addduppackages(Solver *solv, Solvable *s, Queue *qs)
+{
+ Queue dupqs;
+ Id p, dupqsbuf[64];
+ int i;
+ int oldnoupdateprovide = solv->noupdateprovide;
+
+ queue_init_buffer(&dupqs, dupqsbuf, sizeof(dupqsbuf)/sizeof(*dupqsbuf));
+ solv->noupdateprovide = 1;
+ policy_findupdatepackages(solv, s, &dupqs, 2);
+ solv->noupdateprovide = oldnoupdateprovide;
+ for (i = 0; i < dupqs.count; i++)
+ {
+ p = dupqs.elements[i];
+ if (MAPTST(&solv->dupmap, p))
+ queue_pushunique(qs, p);
+ }
+ queue_free(&dupqs);
+}
+
/*-------------------------------------------------------------------
*
* add rule for update
@@ -1511,6 +1646,9 @@ addupdaterule(Solver *solv, Solvable *s, int allow_all)
p = finddistupgradepackages(solv, s, &qs, allow_all);
else
policy_findupdatepackages(solv, s, &qs, allow_all);
+ if (!allow_all && !solv->distupgrade && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
+ addduppackages(solv, s, &qs);
+
if (!allow_all && qs.count && solv->noobsoletes.size)
{
int i, j;
@@ -2013,6 +2151,20 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp)
/* turn rule into problem */
if (why >= solv->jobrules && why < solv->jobrules_end)
why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
+ /* normalize dup/infarch rules */
+ if (why > solv->infarchrules && why < solv->infarchrules_end)
+ {
+ Id name = pool->solvables[-solv->rules[why].p].name;
+ while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
+ why--;
+ }
+ if (why > solv->duprules && why < solv->duprules_end)
+ {
+ Id name = pool->solvables[-solv->rules[why].p].name;
+ while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
+ why--;
+ }
+
/* return if problem already countains our rule */
if (solv->problems.count)
{
@@ -2429,6 +2581,10 @@ solver_free(Solver *solv)
map_free(&solv->weakrulemap);
map_free(&solv->noobsoletes);
+ map_free(&solv->updatemap);
+ map_free(&solv->dupmap);
+ map_free(&solv->dupinvolvedmap);
+
sat_free(solv->decisionmap);
sat_free(solv->rules);
sat_free(solv->watches);
@@ -2574,150 +2730,65 @@ run_solver(Solver *solv, int disablerules, int doweak)
if (level < systemlevel && solv->installed && solv->installed->nsolvables)
{
- if (!solv->updatesystem)
+ Repo *installed = solv->installed;
+ FOR_REPO_SOLVABLES(installed, i, s)
{
- /*
- * Normal run (non-updating)
- * Keep as many packages installed as possible
- */
- POOL_DEBUG(SAT_DEBUG_STATS, "installing old packages\n");
-
- for (i = solv->installed->start; i < solv->installed->end; i++)
- {
- s = pool->solvables + i;
-
- /* skip if not installed */
- if (s->repo != solv->installed)
- continue;
-
- /* skip if already decided */
- if (solv->decisionmap[i] != 0)
- continue;
-
- r = solv->rules + solv->updaterules + (i - solv->installed->start);
- if (!r->p) /* update rule == feature rule? */
- r = r - solv->updaterules + solv->featurerules;
- if (r->p != i) /* allowed to keep package? */
- continue;
-
- POOL_DEBUG(SAT_DEBUG_PROPAGATE, "keeping %s\n", solvable2str(pool, s));
-
- olevel = level;
- level = setpropagatelearn(solv, level, i, disablerules, r->p ? r - solv->rules : 0);
+ Rule *rr;
+ Id d;
- if (level == 0) /* unsolvable */
- {
- queue_free(&dq);
- queue_free(&dqs);
- return;
- }
- if (level <= olevel)
- break;
- }
- systemlevel = level + 1;
- if (i < solv->installed->end)
+ if (MAPTST(&solv->noupdate, i - installed->start))
continue;
- }
- else if (solv->noobsoletes.size && solv->multiversionupdaters)
- {
- /* see if we can multi-version install the newest package */
- for (i = solv->installed->start; i < solv->installed->end; i++)
+ if (solv->decisionmap[i] > 0)
+ continue;
+ r = solv->rules + solv->updaterules + (i - installed->start);
+ rr = r;
+ if (!rr->p || rr->d < 0) /* disabled -> look at feature rule */
+ rr -= solv->installed->end - solv->installed->start;
+ if (!rr->p) /* identical to update rule? */
+ rr = r;
+ if (!rr->p)
+ continue; /* orpaned package */
+
+ queue_empty(&dq);
+ if (solv->decisionmap[i] < 0 || solv->updatesystem || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i)
{
- Id d;
- s = pool->solvables + i;
- if (s->repo != solv->installed)
- continue;
- if (MAPTST(&solv->noupdate, i - solv->installed->start))
- continue;
- d = solv->multiversionupdaters[i - solv->installed->start];
- if (!d)
- continue;
- queue_empty(&dq);
- queue_push(&dq, i);
- while ((p = pool->whatprovidesdata[d++]) != 0)
- if (solv->decisionmap[p] >= 0)
- queue_push(&dq, p);
- policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
- p = dq.elements[0];
- if (p != i && solv->decisionmap[p] == 0)
+ if (solv->noobsoletes.size && solv->multiversionupdaters
+ && (d = solv->multiversionupdaters[i - installed->start]) != 0)
{
- r = solv->rules + solv->featurerules + (i - solv->installed->start);
- if (!r->p) /* update rule == feature rule? */
- r = r - solv->featurerules + solv->updaterules;
- olevel = level;
- POOL_DEBUG(SAT_DEBUG_POLICY, "installing (multi-version) %s\n", solvable2str(pool, pool->solvables + p));
- level = setpropagatelearn(solv, level, p, disablerules, r->p ? r - solv->rules : 0);
- if (level == 0)
+ /* special multiversion handling, make sure best version is chosen */
+ queue_push(&dq, i);
+ while ((p = pool->whatprovidesdata[d++]) != 0)
+ if (solv->decisionmap[p] >= 0)
+ queue_push(&dq, p);
+ policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
+ p = dq.elements[0];
+ if (p != i && solv->decisionmap[p] == 0)
{
- queue_free(&dq);
- queue_free(&dqs);
- return;
+ rr = solv->rules + solv->featurerules + (i - solv->installed->start);
+ if (!rr->p) /* update rule == feature rule? */
+ rr = rr - solv->featurerules + solv->updaterules;
+ dq.count = 1;
}
- if (level <= olevel)
- break;
+ else
+ dq.count = 0;
}
- p = i;
- /* now that the best version is installed, try to
- * keep the original one */
- if (solv->decisionmap[p]) /* already decided? */
- continue;
- r = solv->rules + solv->updaterules + (i - solv->installed->start);
- if (!r->p) /* update rule == feature rule? */
- r = r - solv->updaterules + solv->featurerules;
- if (r->p == p) /* allowed to keep package? */
+ else
{
- olevel = level;
- POOL_DEBUG(SAT_DEBUG_POLICY, "keeping (multi-version) %s\n", solvable2str(pool, pool->solvables + p));
- level = setpropagatelearn(solv, level, p, disablerules, r - solv->rules);
- if (level == 0)
+ /* update to best package */
+ FOR_RULELITERALS(p, dp, rr)
{
- queue_free(&dq);
- queue_free(&dqs);
- return;
+ if (solv->decisionmap[p] > 0)
+ {
+ dq.count = 0; /* already fulfilled */
+ break;
+ }
+ if (!solv->decisionmap[p])
+ queue_push(&dq, p);
}
- if (level <= olevel)
- break;
}
}
- systemlevel = level + 1;
- if (i < solv->installed->end)
- continue;
- }
-
- POOL_DEBUG(SAT_DEBUG_STATS, "resolving update/feature rules\n");
-
- for (i = solv->installed->start, r = solv->rules + solv->updaterules; i < solv->installed->end; i++, r++)
- {
- Rule *rr;
- s = pool->solvables + i;
- if (s->repo != solv->installed)
- continue;
-
- /* skip if already decided */
- if (solv->decisionmap[i] > 0)
- continue;
-
- /* noupdate is set if a job is erasing the installed solvable or installing a specific version */
- if (MAPTST(&solv->noupdate, i - solv->installed->start))
- continue;
-
- rr = r;
- if (rr->d < 0) /* disabled -> look at feature rule */
- rr -= solv->installed->end - solv->installed->start;
- if (!rr->p) /* identical to update rule? */
- rr = r;
- if (!rr->p || rr->d < 0)
- continue; /* no such rule (orpaned package) or disabled */
-
- queue_empty(&dq);
- FOR_RULELITERALS(p, dp, rr)
- {
- if (solv->decisionmap[p] > 0)
- break;
- if (solv->decisionmap[p] == 0)
- queue_push(&dq, p);
- }
- if (!p && dq.count) /* neither fulfilled nor empty */
+ /* install best version */
+ if (dq.count)
{
olevel = level;
level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
@@ -2730,7 +2801,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
if (level <= olevel)
break;
}
- /* if still undecided, keep it */
+ /* if still undecided keep package */
if (solv->decisionmap[i] == 0)
{
olevel = level;
@@ -2747,7 +2818,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
}
}
systemlevel = level + 1;
- if (i < solv->installed->end)
+ if (i < installed->end)
continue;
}
@@ -3093,17 +3164,16 @@ run_solver(Solver *solv, int disablerules, int doweak)
if (solv->distupgrade && solv->installed)
{
+ int installedone = 0;
+
/* let's see if we can install some unsupported package */
POOL_DEBUG(SAT_DEBUG_STATS, "deciding unsupported packages\n");
for (i = 0; i < solv->orphaned.count; i++)
{
p = solv->orphaned.elements[i];
- if (!solv->decisionmap[p])
- break;
- }
- if (i < solv->orphaned.count)
- {
- p = solv->orphaned.elements[i];
+ if (solv->decisionmap[p])
+ continue; /* already decided */
+ olevel = level;
if (solv->distupgrade_removeunsupported)
{
POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + p));
@@ -3113,9 +3183,13 @@ run_solver(Solver *solv, int disablerules, int doweak)
{
POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + p));
level = setpropagatelearn(solv, level, p, 0, 0);
+ installedone = 1;
}
- continue;
+ if (level < olevel)
+ break;
}
+ if (installedone || i < solv->orphaned.count)
+ continue;
}
if (solv->solution_callback)
@@ -3370,6 +3444,7 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined)
/* enable refined rules again */
for (i = 0; i < disabled.count; i++)
enableproblem(solv, disabled.elements[i]);
+ queue_free(&disabled);
/* disable problem rules again */
/* FIXME! */
@@ -3505,7 +3580,6 @@ problems_to_solutions(Solver *solv, Queue *job)
{
why = solution.elements[j];
/* must be either job descriptor or update rule */
- assert(why < 0 || (why >= solv->updaterules && why < solv->updaterules_end));
#if 0
solver_printproblem(solv, why);
#endif
@@ -3515,11 +3589,61 @@ problems_to_solutions(Solver *solv, Queue *job)
queue_push(&solutions, 0);
queue_push(&solutions, -why);
}
+ else if (why >= solv->infarchrules && why < solv->infarchrules_end)
+ {
+ Id p, name;
+ /* infarch rule, find replacement */
+ assert(solv->rules[why].p < 0);
+ name = pool->solvables[-solv->rules[why].p].name;
+ while (why >= solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
+ why--;
+ p = 0;
+ for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
+ if (solv->decisionmap[-solv->rules[why].p] > 0)
+ {
+ p = -solv->rules[why].p;
+ break;
+ }
+ if (!p)
+ p = -solv->rules[why].p; /* XXX: what to do here? */
+ queue_push(&solutions, SOLVER_SOLUTION_INFARCH);
+ queue_push(&solutions, p);
+ }
+ else if (why >= solv->duprules && why < solv->duprules_end)
+ {
+ Id p, name;
+ /* dist upgrade rule, find replacement */
+ assert(solv->rules[why].p < 0);
+ name = pool->solvables[-solv->rules[why].p].name;
+ while (why >= solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
+ why--;
+ p = 0;
+ for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
+ if (solv->decisionmap[-solv->rules[why].p] > 0)
+ {
+ p = -solv->rules[why].p;
+ break;
+ }
+ if (!p)
+ p = -solv->rules[why].p; /* XXX: what to do here? */
+ queue_push(&solutions, SOLVER_SOLUTION_DISTUPGRADE);
+ queue_push(&solutions, p);
+ }
else
{
/* update rule, find replacement package */
Id p, *dp, rp = 0;
Rule *rr;
+
+ assert(why >= solv->updaterules && why < solv->updaterules_end);
+ /* check if this is a false positive, i.e. the update rule is fulfilled */
+ rr = solv->rules + why;
+ FOR_RULELITERALS(p, dp, rr)
+ if (p > 0 && solv->decisionmap[p] > 0)
+ break;
+ if (p)
+ continue; /* false alarm */
+
p = solv->installed->start + (why - solv->updaterules);
rr = solv->rules + solv->featurerules + (why - solv->updaterules);
if (!rr->p)
@@ -3680,6 +3804,22 @@ solver_problemruleinfo(Solver *solv, Queue *job, Id rid, Id *depp, Id *sourcep,
Id p, d, w2, pp, req, *reqp, con, *conp, obs, *obsp, *dp;
assert(rid > 0);
+ if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
+ {
+ r = solv->rules + rid;
+ *depp = r->p < 0 ? pool->solvables[-r->p].name : 0;
+ *sourcep = 0;
+ *targetp = 0;
+ return SOLVER_PROBLEM_INFARCH_RULE;
+ }
+ if (rid >= solv->duprules && rid < solv->duprules_end)
+ {
+ r = solv->rules + rid;
+ *depp = r->p < 0 ? pool->solvables[-r->p].name : 0;
+ *sourcep = 0;
+ *targetp = 0;
+ return SOLVER_PROBLEM_DISTUPGRADE_RULE;
+ }
if (rid >= solv->jobrules && rid < solv->jobrules_end)
{
@@ -3943,7 +4083,7 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
assert(rid > 0);
if (rid >= solv->learntrules)
findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr);
- else if (rid >= solv->jobrules && rid < solv->jobrules_end)
+ else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end))
{
if (!*jobrp)
*jobrp = rid;
@@ -4253,6 +4393,204 @@ weaken_solvable_deps(Solver *solv, Id p)
/********************************************************************/
/* main() */
+
+static void
+addinfarchrules(Solver *solv, Map *addedmap)
+{
+ Pool *pool = solv->pool;
+ int first, i, j;
+ Id p, pp, a, aa, bestarch;
+ Solvable *s, *ps, *bests;
+ Queue badq, allowedarchs;
+
+ queue_init(&badq);
+ queue_init(&allowedarchs);
+ solv->infarchrules = solv->nrules;
+ for (i = 1; i < pool->nsolvables; i++)
+ {
+ if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
+ continue;
+ s = pool->solvables + i;
+ first = i;
+ bestarch = 0;
+ bests = 0;
+ queue_empty(&allowedarchs);
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ ps = pool->solvables + p;
+ if (ps->name != s->name || !MAPTST(addedmap, p))
+ continue;
+ if (p == i)
+ first = 0;
+ if (first)
+ break;
+ a = ps->arch;
+ a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
+ if (a != 1 && pool->installed && ps->repo == pool->installed && !solv->distupgrade)
+ queue_pushunique(&allowedarchs, ps->arch); /* also ok to keep this architecture */
+ if (a && a != 1 && (!bestarch || a < bestarch))
+ {
+ bestarch = a;
+ bests = ps;
+ }
+ }
+ if (first)
+ continue;
+ /* speed up common case where installed package already has best arch */
+ if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
+ allowedarchs.count--; /* installed arch is best */
+ queue_empty(&badq);
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ ps = pool->solvables + p;
+ if (ps->name != s->name || !MAPTST(addedmap, p))
+ continue;
+ a = ps->arch;
+ a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
+ if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0)
+ {
+ for (j = 0; j < allowedarchs.count; j++)
+ {
+ aa = allowedarchs.elements[j];
+ if (ps->arch == aa)
+ break;
+ aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0;
+ if (aa && ((a ^ aa) & 0xffff0000) == 0)
+ break; /* compatible */
+ }
+ if (j == allowedarchs.count)
+ queue_push(&badq, p);
+ }
+ }
+ if (!badq.count)
+ continue;
+ /* block all solvables in the badq! */
+ for (j = 0; j < badq.count; j++)
+ {
+ p = badq.elements[j];
+ addrule(solv, -p, 0);
+ }
+ }
+ queue_free(&badq);
+ queue_free(&allowedarchs);
+ solv->infarchrules_end = solv->nrules;
+}
+
+static void
+createdupmaps(Solver *solv, Queue *job)
+{
+ Pool *pool = solv->pool;
+ Repo *repo;
+ Id how, what, p, pi, pp, obs, *obsp;
+ Solvable *s, *ps;
+ int i;
+
+ map_init(&solv->dupmap, pool->nsolvables);
+ map_init(&solv->dupinvolvedmap, pool->nsolvables);
+ for (i = 0; i < job->count; i += 2)
+ {
+ how = job->elements[i];
+ what = job->elements[i + 1];
+ switch (how & SOLVER_JOBMASK)
+ {
+ case SOLVER_DISTUPGRADE:
+ if (what < 0 || what > pool->nrepos)
+ break;
+ repo = pool->repos[what];
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ MAPSET(&solv->dupmap, p);
+ FOR_PROVIDES(pi, pp, s->name)
+ {
+ ps = pool->solvables + pi;
+ if (ps->name != s->name)
+ continue;
+ MAPSET(&solv->dupinvolvedmap, pi);
+ }
+ if (s->obsoletes)
+ {
+ /* FIXME: check obsoletes/provides combination */
+ obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ {
+ FOR_PROVIDES(pi, pp, obs)
+ {
+ if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + pi, obs))
+ continue;
+ MAPSET(&solv->dupinvolvedmap, pi);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
+}
+
+static void
+freedupmaps(Solver *solv)
+{
+ map_free(&solv->dupmap);
+ map_free(&solv->dupinvolvedmap);
+}
+
+static void
+addduprules(Solver *solv, Map *addedmap)
+{
+ Pool *pool = solv->pool;
+ Id p, pp;
+ Solvable *s, *ps;
+ int first, i;
+
+ solv->duprules = solv->nrules;
+ for (i = 1; i < pool->nsolvables; i++)
+ {
+ if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
+ continue;
+ s = pool->solvables + i;
+ first = i;
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ ps = pool->solvables + p;
+ if (ps->name != s->name || !MAPTST(addedmap, p))
+ continue;
+ if (p == i)
+ first = 0;
+ if (first)
+ break;
+ if (!MAPTST(&solv->dupinvolvedmap, p))
+ continue;
+ if (solv->installed && ps->repo == solv->installed)
+ {
+ if (!solv->updatemap.size)
+ map_init(&solv->updatemap, pool->nsolvables);
+ MAPSET(&solv->updatemap, p);
+ if (!MAPTST(&solv->dupmap, p))
+ {
+ Id ip, ipp;
+ /* is installed identical to a good one? */
+ FOR_PROVIDES(ip, ipp, s->name)
+ {
+ Solvable *is = pool->solvables + ip;
+ if (!MAPTST(&solv->dupmap, ip))
+ continue;
+ if (is->evr == s->evr && solvable_identical(s, is))
+ break;
+ }
+ if (!ip)
+ addrule(solv, -p, 0); /* no match, sorry */
+ }
+ }
+ else if (!MAPTST(&solv->dupmap, p))
+ addrule(solv, -p, 0);
+ }
+ }
+ solv->duprules_end = solv->nrules;
+}
+
/*
*
* solve job queue
@@ -4274,6 +4612,7 @@ solver_solve(Solver *solv, Queue *job)
int goterase;
Rule *r;
int now, solve_start;
+ int hasdupjob = 0;
solve_start = sat_timems(0);
POOL_DEBUG(SAT_DEBUG_STATS, "solver started\n");
@@ -4372,6 +4711,12 @@ solver_solve(Solver *solv, Queue *job)
FOR_JOB_SELECT(p, pp, select, what)
addrpmrulesforupdaters(solv, pool->solvables + what, &addedmap, 0);
break;
+ case SOLVER_DISTUPGRADE:
+ if (!solv->distupgrade)
+ hasdupjob = 1;
+ break;
+ default:
+ break;
}
}
POOL_DEBUG(SAT_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
@@ -4416,6 +4761,11 @@ solver_solve(Solver *solv, Queue *job)
POOL_DEBUG(SAT_DEBUG_STATS, "decisions so far: %d\n", solv->decisionq.count);
POOL_DEBUG(SAT_DEBUG_STATS, "rpm rule creation took %d ms\n", sat_timems(now));
+ /* create dup maps if needed. We need the maps to create our
+ * update rules */
+ if (hasdupjob)
+ createdupmaps(solv, job);
+
/*
* create feature rules
*
@@ -4632,6 +4982,9 @@ solver_solve(Solver *solv, Queue *job)
queue_push(&solv->weakruleq, solv->nrules - 1);
}
break;
+ case SOLVER_DISTUPGRADE:
+ POOL_DEBUG(SAT_DEBUG_JOB, "job: distupgrade repo #%d\n", what);
+ break;
default:
POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n");
break;
@@ -4656,6 +5009,16 @@ solver_solve(Solver *solv, Queue *job)
assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
solv->jobrules_end = solv->nrules;
+ /* now create infarch and dup rules */
+ addinfarchrules(solv, &addedmap);
+ if (hasdupjob)
+ {
+ addduprules(solv, &addedmap);
+ freedupmaps(solv); /* no longer needed */
+ }
+ else
+ solv->duprules = solv->duprules_end = solv->nrules;
+
/* all rules created
* --------------------------------------------------------------
* prepare for solving
@@ -4666,6 +5029,8 @@ solver_solve(Solver *solv, Queue *job)
map_free(&installcandidatemap);
queue_free(&q);
+ POOL_DEBUG(SAT_DEBUG_STATS, "%d rpm rules, %d job rules, %d infarch rules, %d dup rules\n", solv->rpmrules_end - 1, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules);
+
/* create weak map */
map_init(&solv->weakrulemap, solv->nrules);
for (i = 0; i < solv->weakruleq.count; i++)
@@ -4707,7 +5072,7 @@ solver_solve(Solver *solv, Queue *job)
queue_init(&redoq);
goterase = 0;
/* disable all erase jobs (including weak "keep uninstalled" rules) */
- for (i = solv->jobrules, r = solv->rules + i; i < solv->learntrules; i++, r++)
+ for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
{
if (r->d < 0) /* disabled ? */
continue;
diff --git a/src/solver.h b/src/solver.h
index b8f0c38..1f4d96e 100644
--- a/src/solver.h
+++ b/src/solver.h
@@ -208,6 +208,13 @@ typedef struct solver {
Queue *job; /* tmp store for job we're working on */
+ Id infarchrules; /* inferior arch rules */
+ Id infarchrules_end;
+ Id duprules; /* dist upgrade rules */
+ Id duprules_end;
+ Map updatemap; /* bring those packages to the newest version */
+ Map dupmap; /* packages from dup repos */
+ Map dupinvolvedmap; /* packages involved in dup process */
} Solver;
/*
@@ -227,6 +234,7 @@ typedef struct solver {
#define SOLVER_WEAKENDEPS 0x0400
#define SOLVER_NOOBSOLETES 0x0500
#define SOLVER_LOCK 0x0600
+#define SOLVER_DISTUPGRADE 0x0700
#define SOLVER_JOBMASK 0xff00
@@ -260,9 +268,14 @@ typedef enum {
SOLVER_PROBLEM_PACKAGE_OBSOLETES,
SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE,
SOLVER_PROBLEM_SELF_CONFLICT,
- SOLVER_PROBLEM_RPM_RULE
+ SOLVER_PROBLEM_RPM_RULE,
+ SOLVER_PROBLEM_DISTUPGRADE_RULE,
+ SOLVER_PROBLEM_INFARCH_RULE
} SolverProbleminfo;
+#define SOLVER_SOLUTION_JOB (0)
+#define SOLVER_SOLUTION_DISTUPGRADE (-1)
+#define SOLVER_SOLUTION_INFARCH (-2)
extern Solver *solver_create(Pool *pool);
extern void solver_free(Solver *solv);
diff --git a/src/solverdebug.c b/src/solverdebug.c
index 65ad974..cdd783e 100644
--- a/src/solverdebug.c
+++ b/src/solverdebug.c
@@ -195,6 +195,10 @@ solver_printruleclass(Solver *solv, int type, Rule *r)
POOL_DEBUG(type, "WEAK ");
if (p >= solv->learntrules)
POOL_DEBUG(type, "LEARNT ");
+ else if (p >= solv->infarchrules && p < solv->infarchrules_end)
+ POOL_DEBUG(type, "INFARCH ");
+ else if (p >= solv->duprules && p < solv->duprules_end)
+ POOL_DEBUG(type, "DUP ");
else if (p >= solv->jobrules && p < solv->jobrules_end)
POOL_DEBUG(type, "JOB ");
else if (p >= solv->updaterules && p < solv->updaterules_end)
@@ -389,6 +393,12 @@ solver_printprobleminfo(Solver *solv, Queue *job, Id problem)
probr = solver_findproblemrule(solv, problem);
switch (solver_problemruleinfo(solv, job, probr, &dep, &source, &target))
{
+ case SOLVER_PROBLEM_DISTUPGRADE_RULE:
+ POOL_DEBUG(SAT_DEBUG_RESULT, "install %s from distupgrade repositories\n", dep2str(pool, dep));
+ return;
+ case SOLVER_PROBLEM_INFARCH_RULE:
+ POOL_DEBUG(SAT_DEBUG_RESULT, "do not install %s because of inferior architecture\n", dep2str(pool, dep));
+ return;
case SOLVER_PROBLEM_UPDATE_RULE:
s = pool_id2solvable(pool, source);
POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvable2str(pool, s));
@@ -460,7 +470,7 @@ solver_printsolutions(Solver *solv, Queue *job)
element = 0;
while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
{
- if (p == 0)
+ if (p == SOLVER_SOLUTION_JOB)
{
/* job, rp is index into job queue */
how = job->elements[rp - 1];
@@ -495,6 +505,22 @@ solver_printsolutions(Solver *solv, Queue *job)
break;
}
}
+ else if (p == SOLVER_SOLUTION_INFARCH)
+ {
+ s = pool->solvables + rp;
+ if (solv->installed && s->repo == solv->installed)
+ POOL_DEBUG(SAT_DEBUG_RESULT, "- keep %s despite the inferior architecture\n", solvable2str(pool, s));
+ else
+ POOL_DEBUG(SAT_DEBUG_RESULT, "- install %s despite the inferior architecture\n", solvable2str(pool, s));
+ }
+ else if (p == SOLVER_SOLUTION_DISTUPGRADE)
+ {
+ s = pool->solvables + rp;
+ if (solv->installed && s->repo == solv->installed)
+ POOL_DEBUG(SAT_DEBUG_RESULT, "- keep obsolete %s\n", solvable2str(pool, s));
+ else
+ POOL_DEBUG(SAT_DEBUG_RESULT, "- install %s from excluded repository\n", solvable2str(pool, s));
+ }
else
{
/* policy, replace p with rp */
diff --git a/tests/solver/deptestomatic.c b/tests/solver/deptestomatic.c
index cb7fcb6..2cf7b85 100644
--- a/tests/solver/deptestomatic.c
+++ b/tests/solver/deptestomatic.c
@@ -344,6 +344,25 @@ nscallback(Pool *pool, void *data, Id name, Id evr)
return 1;
return 0;
}
+ if (name == NAMESPACE_PRODUCTBUDDY)
+ {
+ Solvable *s = pool->solvables + evr;
+ Id p, pp, cap;
+ snprintf(dir, sizeof(dir), "product(%s)", id2str(pool, s->name) + 8);
+ cap = str2id(pool, dir, 0);
+ if (!cap)
+ return 0;
+ cap = rel2id(pool, cap, s->evr, REL_EQ, 0);
+ if (!cap)
+ return 0;
+ FOR_PROVIDES(p, pp, cap)
+ {
+ Solvable *ps = pool->solvables + p;
+ if (ps->repo == s->repo && ps->arch == s->arch)
+ break;
+ }
+ return p;
+ }
if (name != NAMESPACE_MODALIAS || ISRELDEP(evr))
return 0;
if (pd->nmodaliases == -1)
@@ -1127,7 +1146,11 @@ startElement( void *userData, const char *name, const char **atts )
}
else
{
+#if 1
queue_push( &(pd->trials), SOLVER_LOCK|SOLVER_SOLVABLE );
+#else
+ queue_push( &(pd->trials), SOLVER_INSTALL|SOLVER_SOLVABLE );
+#endif
queue_push( &(pd->trials), id );
}
}
diff --git a/tests/solver/yps.c b/tests/solver/yps.c
index ad38eae..a9c7db9 100644
--- a/tests/solver/yps.c
+++ b/tests/solver/yps.c
@@ -236,7 +236,7 @@ main(int argc, char **argv)
exit(0);
}
- while ((c = getopt(argc, argv, "uefrAvzwk:m:W:")) >= 0)
+ while ((c = getopt(argc, argv, "uefrAvzwk:m:W:D:")) >= 0)
{
switch(c)
{
@@ -273,6 +273,10 @@ main(int argc, char **argv)
case 'v':
debuglevel++;
break;
+ case 'D':
+ queue_push(&job, SOLVER_DISTUPGRADE);
+ queue_push(&job, atoi(optarg));
+ break;
default:
exit(1);
}
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index a5ab951..8945361 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -47,6 +47,9 @@ SET(repomdxml2solv_REPOS repomdxml2solv.c repo_repomdxml.c)
ADD_EXECUTABLE( repomdxml2solv ${repomdxml2solv_REPOS} )
TARGET_LINK_LIBRARIES( repomdxml2solv satsolver toolstuff ${EXPAT_LIBRARY})
+SET(installcheck_SOURCES installcheck.c repo_rpmmd.c repo_susetags.c)
+ADD_EXECUTABLE(installcheck ${installcheck_SOURCES})
+TARGET_LINK_LIBRARIES(installcheck satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
ADD_EXECUTABLE( dumpsolv dumpsolv.c )
TARGET_LINK_LIBRARIES( dumpsolv satsolver)
diff --git a/tools/installcheck.c b/tools/installcheck.c
new file mode 100644
index 0000000..e70a828
--- /dev/null
+++ b/tools/installcheck.c
@@ -0,0 +1,314 @@
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+
+#include "pool.h"
+#include "poolarch.h"
+#include "repo_solv.h"
+#include "repo_susetags.h"
+#include "repo_rpmmd.h"
+#include "solver.h"
+
+static ssize_t
+cookie_gzread(void *cookie, char *buf, size_t nbytes)
+{
+ return gzread((gzFile *)cookie, buf, nbytes);
+}
+
+static int
+cookie_gzclose(void *cookie)
+{
+ return gzclose((gzFile *)cookie);
+}
+
+FILE *
+myfopen(const char *fn)
+{
+ cookie_io_functions_t cio;
+ char *suf;
+ gzFile *gzf;
+
+ if (!fn)
+ return 0;
+ suf = strrchr(fn, '.');
+ if (!suf || strcmp(suf, ".gz") != 0)
+ return fopen(fn, "r");
+ gzf = gzopen(fn, "r");
+ if (!gzf)
+ return 0;
+ memset(&cio, 0, sizeof(cio));
+ cio.read = cookie_gzread;
+ cio.close = cookie_gzclose;
+ return fopencookie(gzf, "r", cio);
+}
+
+int
+main(int argc, char **argv)
+{
+ Pool *pool;
+ Solver *solv;
+ Queue job;
+ Queue rids;
+ Queue cand;
+ Queue archlocks;
+ char *arch;
+ int i, j;
+ Id p;
+ Id rpmid, rpmarch, rpmrel, archlock;
+ int status = 0;
+ int nocheck = 0;
+
+ archlock = 0;
+ arch = argv[1];
+ pool = pool_create();
+ pool_setarch(pool, arch);
+ for (i = 2; i < argc; i++)
+ {
+ FILE *fp;
+ int l;
+
+ if (!strcmp(argv[i], "--nocheck"))
+ {
+ if (!nocheck)
+ nocheck = pool->nsolvables;
+ continue;
+ }
+ l = strlen(argv[i]);
+ if (!strcmp(argv[i], "-"))
+ fp = stdin;
+ else if ((fp = myfopen(argv[i])) == 0)
+ {
+ perror(argv[i]);
+ exit(1);
+ }
+ Repo *repo = repo_create(pool, argv[i]);
+ if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
+ {
+ repo_add_susetags(repo, fp, 0, 0, 0);
+ }
+ else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
+ {
+ repo_add_susetags(repo, fp, 0, 0, 0);
+ }
+ else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
+ {
+ repo_add_rpmmd(repo, fp, 0, 0);
+ }
+ else if (repo_add_solv(repo, fp))
+ {
+ fprintf(stderr, "could not add repo %s\n", argv[i]);
+ exit(1);
+ }
+ if (fp != stdin)
+ fclose(fp);
+ }
+ pool_addfileprovides(pool);
+ pool_createwhatprovides(pool);
+ rpmid = str2id(pool, "rpm", 0);
+ rpmarch = str2id(pool, arch, 0);
+ rpmrel = 0;
+ if (rpmid && rpmarch)
+ {
+ for (p = 1; p < pool->nsolvables; p++)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->name == rpmid && s->arch == rpmarch)
+ break;
+ }
+ if (p < pool->nsolvables)
+ rpmrel = rel2id(pool, rpmid, rpmarch, REL_ARCH, 1);
+ }
+
+ queue_init(&job);
+ queue_init(&rids);
+ queue_init(&cand);
+ queue_init(&archlocks);
+ for (p = 1; p < pool->nsolvables; p++)
+ {
+ Solvable *s = pool->solvables + p;
+ if (!s->repo)
+ continue;
+ if (!pool_installable(pool, s))
+ continue;
+ if (rpmrel && s->arch != rpmarch)
+ {
+ Id rp, rpp;
+ FOR_PROVIDES(rp, rpp, s->name)
+ {
+ if (pool->solvables[rp].name != s->name)
+ continue;
+ if (pool->solvables[rp].arch == rpmarch)
+ break;
+ }
+ if (rp)
+ {
+ queue_push(&archlocks, p);
+ continue;
+ }
+ }
+ queue_push(&cand, p);
+ }
+
+ if (archlocks.count)
+ {
+ archlock = pool_queuetowhatprovides(pool, &archlocks);
+ }
+ /* prune cand by doing weak installs */
+ while (cand.count)
+ {
+ solv = solver_create(pool);
+ queue_empty(&job);
+ for (i = 0; i < cand.count; i++)
+ {
+ p = cand.elements[i];
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+ queue_push(&job, p);
+ }
+ if (rpmrel)
+ {
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
+ queue_push(&job, rpmrel);
+ }
+ if (archlock)
+ {
+ queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
+ queue_push(&job, archlock);
+ }
+ solv->dontinstallrecommended = 1;
+ solver_solve(solv, &job);
+ /* prune... */
+ for (i = j = 0; i < cand.count; i++)
+ {
+ p = cand.elements[i];
+ if (solv->decisionmap[p] <= 0)
+ {
+ cand.elements[j++] = p;
+ continue;
+ }
+#if 0
+ Solvable *s = pool->solvables + p;
+ if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
+ {
+ cand.elements[j++] = p;
+ continue;
+ }
+#endif
+ }
+ cand.count = j;
+ if (i == j)
+ break;
+ }
+
+ /* now check every candidate */
+ for (i = 0; i < cand.count; i++)
+ {
+ Solvable *s;
+
+ p = cand.elements[i];
+ if (nocheck && p >= nocheck)
+ continue;
+ s = pool->solvables + p;
+ solv = solver_create(pool);
+ queue_empty(&job);
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
+ queue_push(&job, p);
+ if (rpmrel)
+ {
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
+ queue_push(&job, rpmrel);
+ }
+ if (archlock)
+ {
+ queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
+ queue_push(&job, archlock);
+ }
+ solv->dontinstallrecommended = 1;
+ solver_solve(solv, &job);
+ if (solv->problems.count)
+ {
+ Id problem = 0;
+ Solvable *s2;
+
+ status = 1;
+ printf("can't install %s:\n", solvable2str(pool, s));
+ while ((problem = solver_next_problem(solv, problem)) != 0)
+ {
+ solver_findallproblemrules(solv, problem, &rids);
+ for (j = 0; j < rids.count; j++)
+ {
+ Id probr = rids.elements[j];
+ Id dep, source, target;
+ switch (solver_problemruleinfo(solv, &job, probr, &dep, &source, &target))
+ {
+ case SOLVER_PROBLEM_UPDATE_RULE:
+ break;
+ case SOLVER_PROBLEM_JOB_RULE:
+ break;
+ case SOLVER_PROBLEM_RPM_RULE:
+ printf(" some dependency problem\n");
+ break;
+ case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
+ printf(" nothing provides requested %s\n", dep2str(pool, dep));
+ break;
+ case SOLVER_PROBLEM_NOT_INSTALLABLE:
+ s = pool_id2solvable(pool, source);
+ printf(" package %s is not installable\n", solvable2str(pool, s));
+ break;
+ case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
+ s = pool_id2solvable(pool, source);
+ printf(" nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
+ if (ISRELDEP(dep))
+ {
+ Reldep *rd = GETRELDEP(pool, dep);
+ if (!ISRELDEP(rd->name))
+ {
+ Id rp, rpp;
+ FOR_PROVIDES(rp, rpp, rd->name)
+ printf(" (we have %s)\n", solvable2str(pool, pool->solvables + rp));
+ }
+ }
+ break;
+ case SOLVER_PROBLEM_SAME_NAME:
+ s = pool_id2solvable(pool, source);
+ s2 = pool_id2solvable(pool, target);
+ printf(" cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
+ break;
+ case SOLVER_PROBLEM_PACKAGE_CONFLICT:
+ s = pool_id2solvable(pool, source);
+ s2 = pool_id2solvable(pool, target);
+ printf(" package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+ break;
+ case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
+ s = pool_id2solvable(pool, source);
+ s2 = pool_id2solvable(pool, target);
+ printf(" package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+ break;
+ case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
+ s = pool_id2solvable(pool, source);
+ printf(" package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
+ break;
+ case SOLVER_PROBLEM_SELF_CONFLICT:
+ s = pool_id2solvable(pool, source);
+ printf(" package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep));
+ break;
+ }
+ }
+ }
+ }
+#if 0
+ else
+ {
+ if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
+ {
+ solver_printdecisions(solv);
+ }
+ }
+#endif
+ solver_free(solv);
+ }
+ exit(status);
+}
hooks/post-receive
--
New approach to dependency solving
--
To unsubscribe, e-mail: zypp-commit+unsubscribe@opensuse.org
For additional commands, e-mail: zypp-commit+help@opensuse.org