ref: refs/heads/master
commit dc9a92111f3b8652b6654975809447510391b3aa
Author: Michael Schroeder
Date: Wed May 13 16:31:28 2009 +0200
- start transaction ordering
---
src/CMakeLists.txt | 5 +-
src/solver.c | 417 ++++++-------------------
src/solver.h | 28 +--
src/solverdebug.c | 56 ++---
src/transaction.c | 690 ++++++++++++++++++++++++++++++++++++++++++
src/transaction.h | 55 ++++
tests/solver/deptestomatic.c | 33 ++-
tools/CMakeLists.txt | 4 +
tools/patchcheck.c | 487 +++++++++++++++++++++++++++++
tools/repo_rpmmd.c | 4 +-
10 files changed, 1385 insertions(+), 394 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0a56baa..a74bf8c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,7 +2,8 @@
SET(libsatsolver_SRCS
bitmap.c poolarch.c poolvendor.c poolid.c strpool.c dirpool.c
solver.c solverdebug.c repo_solv.c repo_helix.c evr.c pool.c
- queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c)
+ queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
+ transaction.c)
ADD_LIBRARY(satsolver STATIC ${libsatsolver_SRCS})
@@ -10,7 +11,7 @@ SET(libsatsolver_HEADERS
bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
poolid.h pooltypes.h queue.h solvable.h solver.h solverdebug.h
repo.h repodata.h repopage.h repo_solv.h repo_helix.h util.h
- strpool.h dirpool.h knownid.h)
+ strpool.h dirpool.h knownid.h transaction.h)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
diff --git a/src/solver.c b/src/solver.c
index 2329f19..5c8f997 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -140,8 +140,6 @@ dep_possible(Solver *solv, Id dep, Map *m)
* - unify rules, remove duplicates
*/
-static Pool *unifyrules_sortcmp_data;
-
/*-------------------------------------------------------------------
*
* compare rules for unification sort
@@ -149,9 +147,9 @@ static Pool *unifyrules_sortcmp_data;
*/
static int
-unifyrules_sortcmp(const void *ap, const void *bp)
+unifyrules_sortcmp(const void *ap, const void *bp, void *dp)
{
- Pool *pool = unifyrules_sortcmp_data;
+ Pool *pool = dp;
Rule *a = (Rule *)ap;
Rule *b = (Rule *)bp;
Id *ad, *bd;
@@ -206,8 +204,7 @@ unifyrules(Solver *solv)
POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n");
/* sort rules first */
- unifyrules_sortcmp_data = solv->pool;
- qsort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp);
+ sat_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool);
/* prune rules
* i = unpruned
@@ -216,7 +213,7 @@ unifyrules(Solver *solv)
jr = 0;
for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
{
- if (jr && !unifyrules_sortcmp(ir, jr))
+ if (jr && !unifyrules_sortcmp(ir, jr, pool))
continue; /* prune! */
jr = solv->rules + j++; /* keep! */
if (ir != jr)
@@ -1409,7 +1406,7 @@ addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
{
POOL_DEBUG(SAT_DEBUG_RULE_CREATION," %s requires %s\n", solvable2str(pool, s), dep2str(pool, req));
for (i = 0; dp[i]; i++)
- POOL_DEBUG(SAT_DEBUG_RULE_CREATION, " provided by %s\n", solvable2str(pool, pool->solvables + dp[i]));
+ POOL_DEBUG(SAT_DEBUG_RULE_CREATION, " provided by %s\n", solvid2str(pool, dp[i]));
}
/* add 'requires' dependency */
@@ -1974,9 +1971,9 @@ propagate(Solver *solv, int level)
IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
{
if (p > 0)
- POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), solvid2str(pool, p));
else
- POOL_DEBUG(SAT_DEBUG_PROPAGATE," -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvable2str(pool, pool->solvables - p));
+ POOL_DEBUG(SAT_DEBUG_PROPAGATE," -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), solvid2str(pool, -p));
}
*rp = *next_rp;
@@ -2022,11 +2019,10 @@ propagate(Solver *solv, int level)
IF_POOLDEBUG (SAT_DEBUG_PROPAGATE)
{
- Solvable *s = pool->solvables + (other_watch > 0 ? other_watch : -other_watch);
if (other_watch > 0)
- POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> decided to install %s\n", solvable2str(pool, s));
+ POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> decided to install %s\n", solvid2str(pool, other_watch));
else
- POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> decided to conflict %s\n", solvable2str(pool, s));
+ POOL_DEBUG(SAT_DEBUG_PROPAGATE, " -> decided to conflict %s\n", solvid2str(pool, -other_watch));
}
} /* foreach rule involving 'pkg' */
@@ -2572,7 +2568,7 @@ selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid
}
p = dq->elements[0];
- POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_POLICY, "installing %s\n", solvid2str(pool, p));
return setpropagatelearn(solv, level, p, disablerules, ruleid);
}
@@ -2675,6 +2671,7 @@ solver_free(Solver *solv)
sat_free(solv->obsoletes);
sat_free(solv->obsoletes_data);
sat_free(solv->multiversionupdaters);
+ sat_free(solv->transaction_installed);
sat_free(solv);
}
@@ -2899,7 +2896,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
if (solv->decisionmap[i] == 0)
{
olevel = level;
- POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvable2str(pool, pool->solvables + i));
+ POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i));
level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
if (level == 0)
{
@@ -3004,7 +3001,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
queue_free(&dqs);
return;
}
- if (level < systemlevel)
+ if (level < systemlevel || level == 1)
break;
n = 0;
} /* for(), decide */
@@ -3153,9 +3150,9 @@ run_solver(Solver *solv, int disablerules, int doweak)
/* simple case, just one package. no need to choose */
p = dq.elements[0];
if (dqs.count)
- POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvid2str(pool, p));
else
- POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p));
queue_push(&solv->recommendations, p);
level = setpropagatelearn(solv, level, p, 0, 0);
continue;
@@ -3173,7 +3170,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
p = dqs.elements[i];
if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
continue;
- POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_POLICY, "installing supplemented %s\n", solvid2str(pool, p));
queue_push(&solv->recommendations, p);
olevel = level;
level = setpropagatelearn(solv, level, p, 0, 0);
@@ -3224,7 +3221,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
queue_push(&solv->branches, -level);
}
p = dq.elements[0];
- POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p));
queue_push(&solv->recommendations, p);
olevel = level;
level = setpropagatelearn(solv, level, p, 0, 0);
@@ -3251,7 +3248,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
p = dq.elements[i];
break;
}
- POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_POLICY, "installing recommended %s\n", solvid2str(pool, p));
queue_push(&solv->recommendations, p);
level = setpropagatelearn(solv, level, p, 0, 0);
continue;
@@ -3273,12 +3270,12 @@ run_solver(Solver *solv, int disablerules, int doweak)
olevel = level;
if (solv->distupgrade_removeunsupported)
{
- POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_STATS, "removing unsupported %s\n", solvid2str(pool, p));
level = setpropagatelearn(solv, level, -p, 0, 0);
}
else
{
- POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_STATS, "keeping unsupported %s\n", solvid2str(pool, p));
level = setpropagatelearn(solv, level, p, 0, 0);
installedone = 1;
}
@@ -3302,7 +3299,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
if (solv->branches.elements[i - 1] < 0)
break;
p = solv->branches.elements[i];
- POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_STATS, "branching with %s\n", solvid2str(pool, p));
queue_empty(&dq);
for (j = i + 1; j < solv->branches.count; j++)
queue_push(&dq, solv->branches.elements[j]);
@@ -3351,7 +3348,7 @@ run_solver(Solver *solv, int disablerules, int doweak)
/* kill old solvable so that we do not loop */
p = solv->branches.elements[lasti];
solv->branches.elements[lasti] = 0;
- POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, solvable2str(pool, pool->solvables + p));
+ POOL_DEBUG(SAT_DEBUG_STATS, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, solvid2str(pool, p));
minimizationsteps++;
level = lastl;
@@ -3562,11 +3559,10 @@ refine_suggestion(Solver *solv, Queue *job, Id *problem, Id sug, Queue *refined,
* make essential job rules last
*/
-Queue *problems_sort_data;
-
static int
-problems_sortcmp(const void *ap, const void *bp)
+problems_sortcmp(const void *ap, const void *bp, void *dp)
{
+ Queue *job = dp;
Id a = *(Id *)ap, b = *(Id *)bp;
if (a < 0 && b > 0)
return 1;
@@ -3574,7 +3570,6 @@ problems_sortcmp(const void *ap, const void *bp)
return -1;
if (a < 0 && b < 0)
{
- Queue *job = problems_sort_data;
int af = job->elements[-a - 1] & SOLVER_ESSENTIAL;
int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL;
int x = af - bf;
@@ -3694,6 +3689,36 @@ convertsolution(Solver *solv, Id why, Queue *solutionq)
}
/*
+ * convert problem data into a form usable for refining.
+ * Returns the number of problems.
+ */
+int
+prepare_solutions(Solver *solv)
+{
+ int i, j = 1, idx = 1;
+
+ if (!solv->problems.count)
+ return 0;
+ queue_push(&solv->solutions, 0);
+ queue_push(&solv->solutions, -1); /* unrefined */
+ for (i = 1; i < solv->problems.count; i++)
+ {
+ Id p = solv->problems.elements[i];
+ queue_push(&solv->solutions, p);
+ if (p)
+ continue;
+ solv->problems.elements[j++] = idx;
+ if (i + 1 >= solv->problems.count)
+ break;
+ solv->problems.elements[j++] = solv->problems.elements[++i]; /* copy proofidx */
+ idx = solv->solutions.count;
+ queue_push(&solv->solutions, -1);
+ }
+ solv->problems.count = j;
+ return j / 2;
+}
+
+/*
* refine the simple solution rule list provided by
* the solver into multiple lists of job modifiers.
*/
@@ -3733,9 +3758,8 @@ create_solutions(Solver *solv, int probnr, int solidx)
break;
queue_push(&problem, v);
}
- problems_sort_data = &solv->job;
if (problem.count > 1)
- qsort(problem.elements, problem.count, sizeof(Id), problems_sortcmp);
+ sat_sort(problem.elements, problem.count, sizeof(Id), problems_sortcmp, &solv->job);
queue_push(&problem, 0); /* mark end for refine_suggestion */
problem.count--;
#if 0
@@ -3926,14 +3950,13 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
*sysrp = lsysr;
}
-
-/*-------------------------------------------------------------------
- *
+/*
* find problem rule
*
* search for a rule that describes the problem to the
- * user. A pretty hopeless task, actually. We currently
- * prefer simple requires.
+ * user. Actually a pretty hopeless task that may leave the user
+ * puzzled. To get all of the needed information use
+ * solver_findallproblemrules() instead.
*/
Id
@@ -3944,16 +3967,18 @@ solver_findproblemrule(Solver *solv, Id problem)
reqr = conr = sysr = jobr = 0;
findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr);
if (reqr)
- return reqr;
+ return reqr; /* some requires */
if (conr)
- return conr;
+ return conr; /* some conflict */
if (sysr)
- return sysr;
+ return sysr; /* an update rule */
if (jobr)
- return jobr;
+ return jobr; /* a user request */
assert(0);
}
+/*-------------------------------------------------------------------*/
+
static void
findallproblemrules_internal(Solver *solv, Id idx, Queue *rules)
{
@@ -3969,6 +3994,14 @@ findallproblemrules_internal(Solver *solv, Id idx, Queue *rules)
}
}
+/*
+ * find all problem rule
+ *
+ * return all rules that lead to the problem. This gives the user
+ * all of the information to understand the problem, but the result
+ * can be a large number of rules.
+ */
+
void
solver_findallproblemrules(Solver *solv, Id problem, Queue *rules)
{
@@ -3981,9 +4014,10 @@ solver_findallproblemrules(Solver *solv, Id problem, Queue *rules)
*
* create reverse obsoletes map for installed solvables
*
- * for each installed solvable find which packages with *different* names
+ * For each installed solvable find which packages with *different* names
* obsolete the solvable.
- * this index is used in policy_findupdatepackages if noupdateprovide is set.
+ * This index is used in policy_findupdatepackages if noupdateprovide is
+ * set.
*/
static void
@@ -3993,11 +4027,12 @@ create_obsolete_index(Solver *solv)
Solvable *s;
Repo *installed = solv->installed;
Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
- int i, n;
+ int i, n, cnt;
- if (!installed || !installed->nsolvables)
+ if (!installed || installed->start == installed->end)
return;
- solv->obsoletes = obsoletes = sat_calloc(installed->end - installed->start, sizeof(Id));
+ cnt = installed->end - installed->start;
+ solv->obsoletes = obsoletes = sat_calloc(cnt, sizeof(Id));
for (i = 1; i < pool->nsolvables; i++)
{
s = pool->solvables + i;
@@ -4021,7 +4056,7 @@ create_obsolete_index(Solver *solv)
}
}
n = 0;
- for (i = 0; i < installed->nsolvables; i++)
+ for (i = 0; i < cnt; i++)
if (obsoletes[i])
{
n += obsoletes[i] + 1;
@@ -4090,7 +4125,7 @@ removedisabledconflicts(Solver *solv, Queue *removed)
if (r->d < 0 && decisionmap[-p])
{
/* rule is now disabled, remove from decisionmap */
- POOL_DEBUG(SAT_DEBUG_SCHUBI, "removing conflict for package %s[%d]\n", solvable2str(pool, pool->solvables - p), -p);
+ POOL_DEBUG(SAT_DEBUG_SCHUBI, "removing conflict for package %s[%d]\n", solvid2str(pool, -p), -p);
queue_push(removed, -p);
queue_push(removed, decisionmap[-p]);
decisionmap[-p] = 0;
@@ -4153,7 +4188,7 @@ removedisabledconflicts(Solver *solv, Queue *removed)
}
if (new)
{
- POOL_DEBUG(SAT_DEBUG_SCHUBI, "re-conflicting package %s[%d]\n", solvable2str(pool, pool->solvables - new), -new);
+ POOL_DEBUG(SAT_DEBUG_SCHUBI, "re-conflicting package %s[%d]\n", solvid2str(pool, -new), -new);
decisionmap[-new] = -1;
new = 0;
n = 0; /* redo all rules */
@@ -4594,240 +4629,6 @@ findrecommendedsuggested(Solver *solv)
}
-Solver *obsq_sortcmp_data;
-
-static int
-obsq_sortcmp(const void *ap, const void *bp)
-{
- Id a, b, oa, ob;
- Solver *solv = obsq_sortcmp_data;
- Pool *pool = solv->pool;
- Solvable *s, *oas, *obs;
- int r;
-
- a = ((Id *)ap)[0];
- oa = ((Id *)ap)[1];
- b = ((Id *)bp)[0];
- ob = ((Id *)bp)[1];
- if (a != b)
- return a - b;
- if (oa == ob)
- return 0;
- s = pool->solvables + a;
- oas = pool->solvables + oa;
- obs = pool->solvables + ob;
- if (oas->name != obs->name)
- {
- if (oas->name == s->name)
- return -1;
- if (obs->name == s->name)
- return 1;
- return strcmp(id2str(pool, oas->name), id2str(pool, obs->name));
- }
- r = evrcmp(pool, oas->evr, obs->evr, EVRCMP_COMPARE);
- if (r)
- return -r; /* highest version first */
- return oa - ob;
-}
-
-void
-solver_transaction_info(Solver *solv, Id p, Queue *out)
-{
- Pool *pool = solv->pool;
- Solvable *s = pool->solvables + p;
- Queue *ti = &solv->transaction_info;
- int i;
-
- queue_empty(out);
- if (p <= 0 || !s->repo)
- return;
- if (s->repo == solv->installed)
- {
- /* find which packages obsolete us */
- for (i = 0; i < ti->count; i += 2)
- if (ti->elements[i + 1] == p)
- {
- queue_push(out, p);
- queue_push(out, ti->elements[i]);
- }
- if (out->count > 2)
- {
- /* sort obsoleters */
- obsq_sortcmp_data = solv;
- qsort(out->elements, out->count / 2, 2 * sizeof(Id), obsq_sortcmp);
- }
- for (i = 0; i < out->count; i += 2)
- out->elements[i] = out->elements[i / 2 + 1];
- out->count /= 2;
- }
- else
- {
- /* find the packages we obsolete */
- for (i = 0; i < ti->count; i += 2)
- {
- if (ti->elements[i] == p)
- queue_push(out, ti->elements[i + 1]);
- else if (out->count)
- break;
- }
- }
-}
-
-Id
-solver_transaction_pkg(Solver *solv, Id p)
-{
- Queue ti;
- Id tibuf[5];
-
- queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
- solver_transaction_info(solv, p, &ti);
- p = ti.count ? ti.elements[0] : 0;
- queue_free(&ti);
- return p;
-}
-
-static void
-create_transaction(Solver *solv)
-{
- Pool *pool = solv->pool;
- Repo *installed = solv->installed;
- Queue *ti = &solv->transaction_info;
- int i, j, r, noobs;
- Id p, p2, pp2;
- Solvable *s, *s2;
-
- queue_empty(&solv->transaction);
- queue_empty(ti);
-
- /* first create obsoletes index */
- if (installed)
- {
- for (i = 0; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p <= 0 || p == SYSTEMSOLVABLE)
- continue;
- s = pool->solvables + p;
- if (s->repo == installed)
- continue;
- noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p);
- FOR_PROVIDES(p2, pp2, s->name)
- {
- if (solv->decisionmap[p2] > 0)
- continue;
- s2 = pool->solvables + p2;
- if (s2->repo != installed)
- continue;
- if (noobs && (s->name != s2->name || s->evr != s2->evr || s->arch != s2->arch))
- continue;
- if (!solv->implicitobsoleteusesprovides && s->name != s2->name)
- continue;
- queue_push(ti, p);
- queue_push(ti, p2);
- }
- if (s->obsoletes && !noobs)
- {
- Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
- while ((obs = *obsp++) != 0)
- {
- FOR_PROVIDES(p2, pp2, obs)
- {
- s2 = pool->solvables + p2;
- if (s2->repo != installed)
- continue;
- if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
- continue;
- queue_push(ti, p);
- queue_push(ti, p2);
- }
- }
- }
- }
- obsq_sortcmp_data = solv;
- qsort(ti->elements, ti->count / 2, 2 * sizeof(Id), obsq_sortcmp);
- /* now unify */
- for (i = j = 0; i < ti->count; i += 2)
- {
- if (j && ti->elements[i] == ti->elements[j - 2] && ti->elements[i + 1] == ti->elements[j - 1])
- continue;
- ti->elements[j++] = ti->elements[i];
- ti->elements[j++] = ti->elements[i + 1];
- }
- ti->count = j;
- }
-
- if (installed)
- {
- FOR_REPO_SOLVABLES(installed, p, s)
- {
- if (solv->decisionmap[p] > 0)
- continue;
- p2 = solver_transaction_pkg(solv, p);
- if (!p2)
- queue_push(&solv->transaction, SOLVER_TRANSACTION_ERASE);
- else
- {
- s2 = pool->solvables + p2;
- if (s->name == s2->name)
- {
- if (s->evr == s2->evr && solvable_identical(s, s2))
- queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALLED);
- else
- {
- r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
- if (r < 0)
- queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADED);
- else if (r > 0)
- queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADED);
- else
- queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGED);
- }
- }
- else
- queue_push(&solv->transaction, SOLVER_TRANSACTION_OBSOLETED);
- }
- queue_push(&solv->transaction, p);
- }
- }
- for (i = 0; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p < 0 || p == SYSTEMSOLVABLE)
- continue;
- s = pool->solvables + p;
- if (solv->installed && s->repo == solv->installed)
- continue;
- noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p);
- p2 = solver_transaction_pkg(solv, p);
- if (noobs)
- queue_push(&solv->transaction, p2 ? SOLVER_TRANSACTION_MULTIREINSTALL : SOLVER_TRANSACTION_MULTIINSTALL);
- else if (!p2)
- queue_push(&solv->transaction, SOLVER_TRANSACTION_INSTALL);
- else
- {
- s2 = pool->solvables + p2;
- if (s->name == s2->name)
- {
- if (s->evr == s2->evr && solvable_identical(s, s2))
- queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALL);
- else
- {
- r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
- if (r > 0)
- queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADE);
- else if (r < 0)
- queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADE);
- else
- queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGE);
- }
- }
- else
- queue_push(&solv->transaction, SOLVER_TRANSACTION_RENAME);
- }
- queue_push(&solv->transaction, p);
- }
-}
-
/*
*
* solve job queue
@@ -5072,8 +4873,7 @@ solver_solve(Solver *solv, Queue *job)
assert(solv->distupgrade && !sr->p);
continue;
}
- unifyrules_sortcmp_data = pool;
- if (!unifyrules_sortcmp(r, sr))
+ if (!unifyrules_sortcmp(r, sr, pool))
{
/* identical rule, kill unneeded one */
if (solv->allowuninstall)
@@ -5259,10 +5059,10 @@ solver_solve(Solver *solv, Queue *job)
solv->duprules = solv->duprules_end = solv->nrules;
- /* all rules created
- * --------------------------------------------------------------
- * prepare for solving
- */
+ /* all rules created
+ * --------------------------------------------------------------
+ * prepare for solving
+ */
/* free unneeded memory */
map_free(&addedmap);
@@ -5315,33 +5115,14 @@ solver_solve(Solver *solv, Queue *job)
findrecommendedsuggested(solv);
/*
- * if unsolvable, prepare solution queue
+ * prepare solution queue if there were problems
*/
- if (solv->problems.count)
- {
- int j = 1, idx = 1;
- queue_push(&solv->solutions, 0);
- queue_push(&solv->solutions, -1); /* unrefined */
- for (i = 1; i < solv->problems.count; i++)
- {
- Id p = solv->problems.elements[i];
- queue_push(&solv->solutions, p);
- if (p)
- continue;
- solv->problems.elements[j++] = idx;
- if (i + 1 >= solv->problems.count)
- break;
- solv->problems.elements[j++] = solv->problems.elements[++i]; /* copy proofidx */
- idx = solv->solutions.count;
- queue_push(&solv->solutions, -1);
- }
- solv->problems.count = j;
- }
+ prepare_solutions(solv);
/*
* finally prepare transaction info
*/
- create_transaction(solv);
+ solver_create_transaction(solv);
POOL_DEBUG(SAT_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable);
POOL_DEBUG(SAT_DEBUG_STATS, "solver_solve took %d ms\n", sat_timems(solve_start));
@@ -5465,7 +5246,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
if (MAPTST(&im, p))
{
#if FIND_INVOLVED_DEBUG
- printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
+ printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
#endif
queue_push(&iq, p);
}
@@ -5488,7 +5269,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
if (MAPTST(&im, p))
{
#if FIND_INVOLVED_DEBUG
- printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
+ printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
#endif
queue_push(&iq, p);
}
@@ -5514,7 +5295,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
if (sup)
{
#if FIND_INVOLVED_DEBUG
- printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip));
+ printf("%s supplemented\n", solvid2str(pool, ip));
#endif
queue_push(&iq, ip);
}
@@ -5550,7 +5331,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
if (p == tp)
continue;
#if FIND_INVOLVED_DEBUG
- printf("%s requires %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
+ printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
#endif
MAPSET(&im, p);
queue_push(&iq, p);
@@ -5570,7 +5351,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
if (p == tp)
continue;
#if FIND_INVOLVED_DEBUG
- printf("%s recommends %s\n", solvable2str(pool, pool->solvables + ip), solvable2str(pool, pool->solvables + p));
+ printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
#endif
MAPSET(&im, p);
queue_push(&iq, p);
@@ -5598,7 +5379,7 @@ solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
if (sup)
{
#if FIND_INVOLVED_DEBUG
- printf("%s supplemented\n", solvable2str(pool, pool->solvables + ip));
+ printf("%s supplemented\n", solvid2str(pool, ip));
#endif
MAPSET(&im, ip);
queue_push(&iq, ip);
@@ -5707,7 +5488,7 @@ addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep)
}
static int
-solver_allruleinfos_cmp(const void *ap, const void *bp)
+solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
{
const Id *a = ap, *b = bp;
int r;
@@ -5758,7 +5539,7 @@ solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
/* now sort & unify em */
if (!rq->count)
return 0;
- qsort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp);
+ sat_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
/* throw out identical entries */
for (i = j = 0; i < rq->count; i += 4)
{
diff --git a/src/solver.h b/src/solver.h
index c271591..5330d3a 100644
--- a/src/solver.h
+++ b/src/solver.h
@@ -22,6 +22,7 @@ extern "C" {
#include "repo.h"
#include "queue.h"
#include "bitmap.h"
+#include "transaction.h"
/*
* Callback definitions in order to "overwrite" the policies by an external application.
*/
@@ -57,14 +58,15 @@ typedef struct rule {
Id n1, n2; /* next rules in linked list, corresponding to w1,w2 */
} Rule;
-struct solver;
+struct _Solver;
-typedef struct solver {
+typedef struct _Solver {
Pool *pool;
Queue job; /* copy of the job we're solving */
Queue transaction; /* solver result */
Queue transaction_info; /* transaction obsoletes info */
+ Id *transaction_installed; /* data for installed packages */
Repo *installed; /* copy of pool->installed */
@@ -130,7 +132,7 @@ typedef struct solver {
Queue learnt_pool;
Queue branches;
- int (*solution_callback)(struct solver *solv, void *data);
+ int (*solution_callback)(struct _Solver *solv, void *data);
void *solution_callback_data;
int propagate_index; /* index into decisionq for non-propagated decisions */
@@ -328,29 +330,9 @@ typedef enum {
#define SOLVER_SOLUTION_DISTUPGRADE (-1)
#define SOLVER_SOLUTION_INFARCH (-2)
-#define SOLVER_TRANSACTION_ERASE 0x10
-#define SOLVER_TRANSACTION_REINSTALLED 0x11
-#define SOLVER_TRANSACTION_DOWNGRADED 0x12
-#define SOLVER_TRANSACTION_CHANGED 0x13
-#define SOLVER_TRANSACTION_UPGRADED 0x14
-#define SOLVER_TRANSACTION_OBSOLETED 0x15
-
-#define SOLVER_TRANSACTION_INSTALL 0x20
-#define SOLVER_TRANSACTION_REINSTALL 0x21
-#define SOLVER_TRANSACTION_DOWNGRADE 0x22
-#define SOLVER_TRANSACTION_CHANGE 0x23
-#define SOLVER_TRANSACTION_UPGRADE 0x24
-#define SOLVER_TRANSACTION_RENAME 0x25
-
-#define SOLVER_TRANSACTION_MULTIINSTALL 0x30
-#define SOLVER_TRANSACTION_MULTIREINSTALL 0x31
-
-
extern Solver *solver_create(Pool *pool);
extern void solver_free(Solver *solv);
extern void solver_solve(Solver *solv, Queue *job);
-extern void solver_transaction_info(Solver *solv, Id p, Queue *info);
-extern Id solver_transaction_pkg(Solver *solv, Id p);
extern int solver_dep_installed(Solver *solv, Id dep);
extern int solver_splitprovides(Solver *solv, Id dep);
diff --git a/src/solverdebug.c b/src/solverdebug.c
index 1b74e1e..6bfc2a3 100644
--- a/src/solverdebug.c
+++ b/src/solverdebug.c
@@ -297,7 +297,7 @@ solver_printdecisions(Solver *solv)
POOL_DEBUG(SAT_DEBUG_RESULT, " change %s", solvable2str(pool, s));
break;
case SOLVER_TRANSACTION_UPGRADE:
- case SOLVER_TRANSACTION_RENAME:
+ case SOLVER_TRANSACTION_REPLACE:
POOL_DEBUG(SAT_DEBUG_RESULT, " upgrade %s", solvable2str(pool, s));
break;
case SOLVER_TRANSACTION_ERASE:
@@ -316,13 +316,13 @@ solver_printdecisions(Solver *solv)
case SOLVER_TRANSACTION_DOWNGRADE:
case SOLVER_TRANSACTION_CHANGE:
case SOLVER_TRANSACTION_UPGRADE:
- case SOLVER_TRANSACTION_RENAME:
- solver_transaction_info(solv, solv->transaction.elements[i + 1], &iq);
+ case SOLVER_TRANSACTION_REPLACE:
+ solver_transaction_all_pkgs(solv, solv->transaction.elements[i + 1], &iq);
if (iq.count)
{
POOL_DEBUG(SAT_DEBUG_RESULT, " (obsoletes");
for (j = 0; j < iq.count; j++)
- POOL_DEBUG(SAT_DEBUG_RESULT, " %s", solvable2str(pool, pool->solvables + iq.elements[j]));
+ POOL_DEBUG(SAT_DEBUG_RESULT, " %s", solvid2str(pool, iq.elements[j]));
POOL_DEBUG(SAT_DEBUG_RESULT, ")");
}
POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
@@ -393,22 +393,18 @@ solver_printprobleminfo(Solver *solv, Queue *job, Id problem)
Pool *pool = solv->pool;
Id probr;
Id dep, source, target;
- Solvable *s, *s2;
probr = solver_findproblemrule(solv, problem);
switch (solver_problemruleinfo(solv, job, probr, &dep, &source, &target))
{
case SOLVER_RULE_DISTUPGRADE:
- s = pool_id2solvable(pool, source);
- POOL_DEBUG(SAT_DEBUG_RESULT, "%s does not belong to a distupgrade repository\n", solvable2str(pool, s));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "%s does not belong to a distupgrade repository\n", solvid2str(pool, source));
return;
case SOLVER_RULE_INFARCH:
- s = pool_id2solvable(pool, source);
- POOL_DEBUG(SAT_DEBUG_RESULT, "%s has inferior architecture\n", solvable2str(pool, s));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "%s has inferior architecture\n", solvid2str(pool, source));
return;
case SOLVER_RULE_UPDATE:
- s = pool_id2solvable(pool, source);
- POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvable2str(pool, s));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "problem with installed package %s\n", solvid2str(pool, source));
return;
case SOLVER_RULE_JOB:
POOL_DEBUG(SAT_DEBUG_RESULT, "conflicting requests\n");
@@ -420,40 +416,28 @@ solver_printprobleminfo(Solver *solv, Queue *job, Id problem)
POOL_DEBUG(SAT_DEBUG_RESULT, "some dependency problem\n");
return;
case SOLVER_RULE_RPM_NOT_INSTALLABLE:
- s = pool_id2solvable(pool, source);
- POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvable2str(pool, s));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "package %s is not installable\n", solvid2str(pool, source));
return;
case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
- s = pool_id2solvable(pool, source);
- POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "nothing provides %s needed by %s\n", dep2str(pool, dep), solvid2str(pool, source));
return;
case SOLVER_RULE_RPM_SAME_NAME:
- s = pool_id2solvable(pool, source);
- s2 = pool_id2solvable(pool, target);
- POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "cannot install both %s and %s\n", solvid2str(pool, source), solvid2str(pool, target));
return;
case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
- s = pool_id2solvable(pool, source);
- s2 = pool_id2solvable(pool, target);
- POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
return;
case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
- s = pool_id2solvable(pool, source);
- s2 = pool_id2solvable(pool, target);
- POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
return;
case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES:
- s = pool_id2solvable(pool, source);
- s2 = pool_id2solvable(pool, target);
- POOL_DEBUG(SAT_DEBUG_RESULT, "package %s implicitely obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "package %s implicitely obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
return;
case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
- s = pool_id2solvable(pool, source);
- POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "package %s requires %s, but none of the providers can be installed\n", solvid2str(pool, source), dep2str(pool, dep));
return;
case SOLVER_RULE_RPM_SELF_CONFLICT:
- s = pool_id2solvable(pool, source);
- POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "package %s conflicts with %s provided by itself\n", solvid2str(pool, source), dep2str(pool, dep));
return;
case SOLVER_RULE_UNKNOWN:
case SOLVER_RULE_FEATURE:
@@ -497,7 +481,7 @@ solver_printsolutions(Solver *solv, Queue *job)
{
case SOLVER_INSTALL:
if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
- POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvable2str(pool, pool->solvables + what));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "- do not keep %s installed\n", solvid2str(pool, what));
else if (select == SOLVER_SOLVABLE_PROVIDES)
POOL_DEBUG(SAT_DEBUG_RESULT, "- do not install a solvable %s\n", solver_select2str(solv, select, what));
else
@@ -505,7 +489,7 @@ solver_printsolutions(Solver *solv, Queue *job)
break;
case SOLVER_ERASE:
if (select == SOLVER_SOLVABLE && !(solv->installed && pool->solvables[what].repo == solv->installed))
- POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvable2str(pool, pool->solvables + what));
+ POOL_DEBUG(SAT_DEBUG_RESULT, "- do not forbid installation of %s\n", solvid2str(pool, what));
else if (select == SOLVER_SOLVABLE_PROVIDES)
POOL_DEBUG(SAT_DEBUG_RESULT, "- do not deinstall all solvables %s\n", solver_select2str(solv, select, what));
else
@@ -610,7 +594,7 @@ solver_printtrivial(Solver *solv)
solver_trivial_installable(solv, &in, &out);
POOL_DEBUG(SAT_DEBUG_RESULT, "trivial installable status:\n");
for (i = 0; i < in.count; i++)
- POOL_DEBUG(SAT_DEBUG_RESULT, " %s: %d\n", solvable2str(pool, pool->solvables + in.elements[i]), out.elements[i]);
+ POOL_DEBUG(SAT_DEBUG_RESULT, " %s: %d\n", solvid2str(pool, in.elements[i]), out.elements[i]);
POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
queue_free(&in);
queue_free(&out);
@@ -623,7 +607,7 @@ solver_select2str(Solver *solv, Id select, Id what)
const char *s;
char *b;
if (select == SOLVER_SOLVABLE)
- return solvable2str(pool, pool->solvables + what);
+ return solvid2str(pool, what);
if (select == SOLVER_SOLVABLE_NAME)
return dep2str(pool, what);
if (select == SOLVER_SOLVABLE_PROVIDES)
@@ -640,7 +624,7 @@ solver_select2str(Solver *solv, Id select, Id what)
b = "";
while ((p = pool->whatprovidesdata[what++]) != 0)
{
- s = solvable2str(pool, pool->solvables + p);
+ s = solvid2str(pool, p);
b2 = pool_alloctmpspace(pool, strlen(b) + strlen(s) + 3);
sprintf(b2, "%s, %s", b, s);
b = b2;
diff --git a/src/transaction.c b/src/transaction.c
new file mode 100644
index 0000000..cf682f3
--- /dev/null
+++ b/src/transaction.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * transaction.c
+ *
+ * Transaction handling
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "transaction.h"
+#include "solver.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "evr.h"
+#include "util.h"
+
+static int
+obsq_sortcmp(const void *ap, const void *bp, void *dp)
+{
+ Id a, b, oa, ob;
+ Pool *pool = dp;
+ Solvable *s, *oas, *obs;
+ int r;
+
+ a = ((Id *)ap)[0];
+ oa = ((Id *)ap)[1];
+ b = ((Id *)bp)[0];
+ ob = ((Id *)bp)[1];
+ if (a != b)
+ return a - b;
+ if (oa == ob)
+ return 0;
+ s = pool->solvables + a;
+ oas = pool->solvables + oa;
+ obs = pool->solvables + ob;
+ if (oas->name != obs->name)
+ {
+ if (oas->name == s->name)
+ return -1;
+ if (obs->name == s->name)
+ return 1;
+ return strcmp(id2str(pool, oas->name), id2str(pool, obs->name));
+ }
+ r = evrcmp(pool, oas->evr, obs->evr, EVRCMP_COMPARE);
+ if (r)
+ return -r; /* highest version first */
+ return oa - ob;
+}
+
+void
+solver_transaction_all_pkgs(Solver *solv, Id p, Queue *pkgs)
+{
+ Pool *pool = solv->pool;
+ Solvable *s = pool->solvables + p;
+ Queue *ti = &solv->transaction_info;
+ Id q;
+ int i;
+
+ queue_empty(pkgs);
+ if (p <= 0 || !s->repo)
+ return;
+ if (s->repo == solv->installed)
+ {
+ q = solv->transaction_installed[p - solv->installed->start];
+ if (!q)
+ return;
+ if (q > 0)
+ {
+ queue_push(pkgs, q);
+ return;
+ }
+ /* find which packages obsolete us */
+ for (i = 0; i < ti->count; i += 2)
+ if (ti->elements[i + 1] == p)
+ {
+ queue_push(pkgs, p);
+ queue_push(pkgs, ti->elements[i]);
+ }
+ /* sort obsoleters */
+ if (pkgs->count > 2)
+ sat_sort(pkgs->elements, pkgs->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool);
+ for (i = 0; i < pkgs->count; i += 2)
+ pkgs->elements[i / 2] = pkgs->elements[i + 1];
+ pkgs->count /= 2;
+ }
+ else
+ {
+ /* find the packages we obsolete */
+ for (i = 0; i < ti->count; i += 2)
+ {
+ if (ti->elements[i] == p)
+ queue_push(pkgs, ti->elements[i + 1]);
+ else if (pkgs->count)
+ break;
+ }
+ }
+}
+
+Id
+solver_transaction_pkg(Solver *solv, Id p)
+{
+ Pool *pool = solv->pool;
+ Solvable *s = pool->solvables + p;
+ Queue ti;
+ Id tibuf[5];
+
+ if (p <= 0 || !s->repo)
+ return 0;
+ if (s->repo == solv->installed)
+ {
+ p = solv->transaction_installed[p - solv->installed->start];
+ return p < 0 ? -p : p;
+ }
+ queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
+ solver_transaction_all_pkgs(solv, p, &ti);
+ p = ti.count ? ti.elements[0] : 0;
+ queue_free(&ti);
+ return p;
+}
+
+/* type filtering, needed if either not all packages are shown
+ * or replaces are not shown, as otherwise parts of the
+ * transaction might not be shown to the user */
+
+Id
+solver_transaction_filter(Solver *solv, Id type, Id p, int flags)
+{
+ Pool *pool = solv->pool;
+ Solvable *s = pool->solvables + p;
+ Queue oq, rq;
+ Id q;
+ int i, j, ref = 0;
+
+ if (type == SOLVER_TRANSACTION_ERASE || type == SOLVER_TRANSACTION_INSTALL || type == SOLVER_TRANSACTION_MULTIINSTALL)
+ return type;
+
+ if (s->repo == pool->installed && (flags & SOLVER_TRANSACTION_SHOW_ACTIVE) == 0)
+ {
+ /* erase element */
+ if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0 && type == SOLVER_TRANSACTION_REPLACED)
+ type = SOLVER_TRANSACTION_ERASE;
+ return type;
+ }
+ if (s->repo != pool->installed && (flags & SOLVER_TRANSACTION_SHOW_ACTIVE) != 0)
+ {
+ if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0 && type == SOLVER_TRANSACTION_REPLACE)
+ type = SOLVER_TRANSACTION_INSTALL;
+ return type;
+ }
+
+ /* most of the time there's only one reference, so check it first */
+ q = solver_transaction_pkg(solv, p);
+ if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0)
+ {
+ Solvable *sq = pool->solvables + q;
+ if (sq->name != s->name)
+ {
+ if (s->repo == pool->installed)
+ return SOLVER_TRANSACTION_ERASE;
+ else if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
+ return SOLVER_TRANSACTION_MULTIINSTALL;
+ else
+ return SOLVER_TRANSACTION_INSTALL;
+ }
+ }
+ if (solver_transaction_pkg(solv, q) == p)
+ return type;
+
+ /* too bad, a miss. check em all */
+ queue_init(&oq);
+ queue_init(&rq);
+ solver_transaction_all_pkgs(solv, p, &oq);
+ for (i = 0; i < oq.count; i++)
+ {
+ q = oq.elements[i];
+ if ((flags & SOLVER_TRANSACTION_SHOW_REPLACES) == 0)
+ {
+ Solvable *sq = pool->solvables + q;
+ if (sq->name != s->name)
+ continue;
+ }
+ /* check if we are referenced? */
+ if ((flags & SOLVER_TRANSACTION_SHOW_ALL) != 0)
+ {
+ solver_transaction_all_pkgs(solv, q, &rq);
+ for (j = 0; j < rq.count; j++)
+ if (rq.elements[j] == p)
+ {
+ ref = 1;
+ break;
+ }
+ if (ref)
+ break;
+ }
+ else if (solver_transaction_pkg(solv, q) == p)
+ {
+ ref = 1;
+ break;
+ }
+ }
+ queue_free(&oq);
+ queue_free(&rq);
+
+ if (!ref)
+ {
+ if (s->repo == pool->installed)
+ type = SOLVER_TRANSACTION_ERASE;
+ else if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
+ type = SOLVER_TRANSACTION_MULTIINSTALL;
+ else
+ type = SOLVER_TRANSACTION_INSTALL;
+ }
+ return type;
+}
+
+static void
+create_transaction_info(Solver *solv)
+{
+ Pool *pool = solv->pool;
+ Queue *ti = &solv->transaction_info;
+ Repo *installed = solv->installed;
+ int i, j, noobs;
+ Id p, p2, pp2;
+ Solvable *s, *s2;
+
+ queue_empty(ti);
+ if (!installed)
+ return; /* no info needed */
+ for (i = 0; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p <= 0 || p == SYSTEMSOLVABLE)
+ continue;
+ s = pool->solvables + p;
+ if (s->repo == installed)
+ continue;
+ noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p);
+ FOR_PROVIDES(p2, pp2, s->name)
+ {
+ if (solv->decisionmap[p2] > 0)
+ continue;
+ s2 = pool->solvables + p2;
+ if (s2->repo != installed)
+ continue;
+ if (noobs && (s->name != s2->name || s->evr != s2->evr || s->arch != s2->arch))
+ continue;
+ if (!solv->implicitobsoleteusesprovides && s->name != s2->name)
+ continue;
+ queue_push(ti, p);
+ queue_push(ti, p2);
+ }
+ if (s->obsoletes && !noobs)
+ {
+ Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ {
+ FOR_PROVIDES(p2, pp2, obs)
+ {
+ s2 = pool->solvables + p2;
+ if (s2->repo != installed)
+ continue;
+ if (!solv->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
+ continue;
+ queue_push(ti, p);
+ queue_push(ti, p2);
+ }
+ }
+ }
+ }
+ sat_sort(ti->elements, ti->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool);
+ /* now unify */
+ for (i = j = 0; i < ti->count; i += 2)
+ {
+ if (j && ti->elements[i] == ti->elements[j - 2] && ti->elements[i + 1] == ti->elements[j - 1])
+ continue;
+ ti->elements[j++] = ti->elements[i];
+ ti->elements[j++] = ti->elements[i + 1];
+ }
+ ti->count = j;
+
+ /* create transaction_installed helper */
+ solv->transaction_installed = sat_calloc(installed->end - installed->start, sizeof(Id));
+ for (i = 0; i < ti->count; i += 2)
+ {
+ j = ti->elements[i + 1] - installed->start;
+ if (!solv->transaction_installed[j])
+ solv->transaction_installed[j] = ti->elements[i];
+ else
+ {
+ /* more than one package obsoletes us. compare */
+ Id q[4];
+ if (solv->transaction_installed[j] > 0)
+ solv->transaction_installed[j] = -solv->transaction_installed[j];
+ q[0] = q[2] = ti->elements[i + 1];
+ q[1] = ti->elements[i];
+ q[3] = -solv->transaction_installed[j];
+ if (obsq_sortcmp(q, q + 2, pool) < 0)
+ solv->transaction_installed[j] = -ti->elements[i];
+ }
+ }
+}
+
+
+void
+solver_create_transaction(Solver *solv)
+{
+ Pool *pool = solv->pool;
+ Repo *installed = solv->installed;
+ int i, r, noobs;
+ Id p, p2;
+ Solvable *s, *s2;
+
+ queue_empty(&solv->transaction);
+ create_transaction_info(solv);
+
+ if (installed)
+ {
+ FOR_REPO_SOLVABLES(installed, p, s)
+ {
+ if (solv->decisionmap[p] > 0)
+ continue;
+ p2 = solver_transaction_pkg(solv, p);
+ if (!p2)
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_ERASE);
+ else
+ {
+ s2 = pool->solvables + p2;
+ if (s->name == s2->name)
+ {
+ if (s->evr == s2->evr && solvable_identical(s, s2))
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALLED);
+ else
+ {
+ r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
+ if (r < 0)
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADED);
+ else if (r > 0)
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADED);
+ else
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGED);
+ }
+ }
+ else
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_REPLACED);
+ }
+ queue_push(&solv->transaction, p);
+ }
+ }
+ for (i = 0; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p < 0 || p == SYSTEMSOLVABLE)
+ continue;
+ s = pool->solvables + p;
+ if (solv->installed && s->repo == solv->installed)
+ continue;
+ noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p);
+ p2 = solver_transaction_pkg(solv, p);
+ if (noobs)
+ queue_push(&solv->transaction, p2 ? SOLVER_TRANSACTION_MULTIREINSTALL : SOLVER_TRANSACTION_MULTIINSTALL);
+ else if (!p2)
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_INSTALL);
+ else
+ {
+ s2 = pool->solvables + p2;
+ if (s->name == s2->name)
+ {
+ if (s->evr == s2->evr && solvable_identical(s, s2))
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_REINSTALL);
+ else
+ {
+ r = evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
+ if (r > 0)
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_UPGRADE);
+ else if (r < 0)
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_DOWNGRADE);
+ else
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_CHANGE);
+ }
+ }
+ else
+ queue_push(&solv->transaction, SOLVER_TRANSACTION_REPLACE);
+ }
+ queue_push(&solv->transaction, p);
+ }
+}
+
+#define TYPE_REQ (1<<0)
+#define TYPE_PREREQ (1<<1)
+#define TYPE_CON (1<<2)
+#define TYPE_ERASE (1<<3)
+
+#define EDGEDATA_BLOCK 127
+
+struct transel {
+ Id p;
+ Id edges;
+};
+
+struct orderdata {
+ Solver *solv;
+ struct transel *tes;
+ int ntes;
+ Id *edgedata;
+ int nedgedata;
+};
+
+static void
+addedge(struct orderdata *od, Id from, Id to, int type)
+{
+ Solver *solv = od->solv;
+ Pool *pool = solv->pool;
+ Solvable *s;
+ struct transel *te;
+ int i;
+
+ // printf("addedge %d %d type %d\n", from, to, type);
+ s = pool->solvables + from;
+ if (s->repo == solv->installed && solv->transaction_installed[from - solv->installed->start])
+ {
+ /* passive, map to active */
+ if (solv->transaction_installed[from - solv->installed->start] > 0)
+ from = solv->transaction_installed[from - solv->installed->start];
+ else
+ {
+ Queue ti;
+ Id tibuf[5];
+ queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
+ solver_transaction_all_pkgs(solv, from, &ti);
+ for (i = 0; i < ti.count; i++)
+ addedge(od, ti.elements[i], to, type);
+ queue_free(&ti);
+ }
+ return;
+ }
+ s = pool->solvables + to;
+ if (s->repo == solv->installed && solv->transaction_installed[to - solv->installed->start])
+ {
+ /* passive, map to active */
+ if (solv->transaction_installed[to - solv->installed->start] > 0)
+ to = solv->transaction_installed[to - solv->installed->start];
+ else
+ {
+ Queue ti;
+ Id tibuf[5];
+ queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
+ solver_transaction_all_pkgs(solv, to, &ti);
+ for (i = 0; i < ti.count; i++)
+ addedge(od, from, ti.elements[i], type);
+ queue_free(&ti);
+ return;
+ }
+ }
+
+ /* map target to te num */
+ for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+ if (te->p == to)
+ break;
+ if (i == od->ntes)
+ return;
+ to = i;
+
+ for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+ if (te->p == from)
+ break;
+ if (i == od->ntes)
+ return;
+
+ if (i == to)
+ return; /* no edges to ourselfes */
+
+ // printf("edge %d -> %d type %x\n", i, to, type);
+
+ for (i = te->edges; od->edgedata[i]; i += 2)
+ if (od->edgedata[i] == to)
+ break;
+ if (od->edgedata[i])
+ {
+ od->edgedata[i + 1] |= type;
+ return;
+ }
+ if (i + 1 == od->nedgedata)
+ {
+ // printf("tail add %d\n", i - te->edges);
+ if (!i)
+ te->edges = ++i;
+ od->edgedata = sat_extend(od->edgedata, od->nedgedata, 3, sizeof(Id), EDGEDATA_BLOCK);
+ }
+ else
+ {
+ // printf("extend %d\n", i - te->edges);
+ od->edgedata = sat_extend(od->edgedata, od->nedgedata, 3 + (i - te->edges), sizeof(Id), EDGEDATA_BLOCK);
+ if (i > te->edges)
+ memcpy(od->edgedata + od->nedgedata, od->edgedata + te->edges, sizeof(Id) * (i - te->edges));
+ i = od->nedgedata + (i - te->edges);
+ te->edges = od->nedgedata;
+ }
+ od->edgedata[i] = to;
+ od->edgedata[i + 1] = type;
+ od->edgedata[i + 2] = 0;
+ od->nedgedata = i + 3;
+}
+
+void
+solver_order_transaction(Solver *solv)
+{
+ Pool *pool = solv->pool;
+ Queue *tr = &solv->transaction;
+ Repo *installed = solv->installed;
+ Id type, p;
+ Solvable *s, *s2;
+ Id req, *reqp, con, *conp;
+ Id p2, pp2;
+ int i, j, pre, numte, numedge;
+ struct orderdata od;
+ struct transel *te;
+
+ /* create a transaction element for every active component */
+ numte = 0;
+ for (i = 0; i < tr->count; i += 2)
+ {
+ p = tr->elements[i + 1];
+ s = pool->solvables + p;
+ if (s->repo != installed || !solv->transaction_installed[p - solv->installed->start])
+ numte++;
+ }
+ if (!numte)
+ return; /* nothing to do... */
+
+
+ printf("numte = %d\n", numte);
+ numte++; /* leave first one zero */
+ od.solv = solv;
+ od.ntes = numte;
+ od.tes = sat_calloc(numte, sizeof(*od.tes));
+ od.edgedata = sat_extend(0, 0, 1, sizeof(Id), EDGEDATA_BLOCK);
+ od.edgedata[0] = 0;
+ od.nedgedata = 1;
+
+ for (i = 0, te = od.tes + 1; i < tr->count; i += 2)
+ {
+ p = tr->elements[i + 1];
+ s = pool->solvables + p;
+ if (s->repo == installed && solv->transaction_installed[p - solv->installed->start])
+ continue;
+ te->p = p;
+ te++;
+ }
+
+ /* create dependency graph */
+ for (i = 0; i < tr->count; i += 2)
+ {
+ type = tr->elements[i];
+ p = tr->elements[i + 1];
+ s = pool->solvables + p;
+ if (s->requires)
+ {
+ reqp = s->repo->idarraydata + s->requires;
+ pre = TYPE_REQ;
+ while ((req = *reqp++) != 0)
+ {
+ int eraseonly = 0;
+ if (req == SOLVABLE_PREREQMARKER)
+ {
+ pre = TYPE_PREREQ;
+ continue;
+ }
+#if 1
+ if (s->repo == installed && pre != TYPE_PREREQ)
+ continue;
+#endif
+ FOR_PROVIDES(p2, pp2, req)
+ {
+ if (p2 == p)
+ continue;
+ s2 = pool->solvables + p2;
+ if (!s2->repo)
+ continue;
+ if (s2->repo == installed && solv->decisionmap[p2] > 0)
+ continue;
+ if (s2->repo != installed && solv->decisionmap[p2] < 0)
+ continue; /* not interesting */
+ if (s->repo == installed)
+ {
+ /* we're uninstalling s */
+ if (s2->repo == installed)
+ {
+ if (eraseonly == 0)
+ eraseonly = 1;
+ }
+ if (s2->repo != installed)
+ {
+ /* update p2 before erasing p */
+#if 1
+ addedge(&od, p, p2, pre);
+#endif
+ eraseonly = -1;
+ }
+ }
+ else
+ {
+ /* install p2 before installing p */
+ if (s2->repo != installed)
+ addedge(&od, p, p2, pre);
+ }
+ }
+ if (eraseonly == 1)
+ {
+ printf("eraseonlyedge for %s req %s\n", solvable2str(pool, s), dep2str(pool, req));
+ /* need edges to uninstalled pkgs */
+#if 1
+ FOR_PROVIDES(p2, pp2, req)
+ {
+ if (p2 == p)
+ continue;
+ s2 = pool->solvables + p2;
+ if (!s2->repo || s2->repo != installed)
+ continue;
+ if (solv->decisionmap[p2] > 0)
+ continue;
+#if 0
+ addedge(&od, p2, p, pre);
+#else
+ addedge(&od, p2, p, TYPE_ERASE);
+#endif
+ }
+#endif
+ }
+ }
+ }
+ if (s->conflicts)
+ {
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+#if 1
+ FOR_PROVIDES(p2, pp2, con)
+ {
+ if (p2 == p)
+ continue;
+ s2 = pool->solvables + p2;
+ if (!s2->repo)
+ continue;
+ if (s->repo == installed)
+ {
+ if (s2->repo != installed && solv->decisionmap[p2] >= 0)
+ {
+ /* deinstall p before installing p2 */
+ addedge(&od, p2, p, TYPE_CON);
+ }
+ }
+ else
+ {
+ if (s2->repo == installed && solv->decisionmap[p2] < 0)
+ {
+ /* deinstall p2 before installing p */
+#if 1
+ addedge(&od, p, p2, TYPE_CON);
+#endif
+ }
+ }
+
+ }
+#endif
+ }
+ }
+ }
+ numedge = 0;
+ for (i = 1, te = od.tes + i; i < numte; i++, te++)
+ {
+ printf("TE #%d, %d(%s)\n", i, te->p, solvid2str(pool, te->p));
+ for (j = te->edges; od.edgedata[j]; j += 2)
+ {
+ struct transel *te2 = od.tes + od.edgedata[j];
+ printf(" depends %x on TE %d, %d(%s)\n", od.edgedata[j + 1], od.edgedata[j], te2->p, solvid2str(pool, te2->p));
+ numedge++;
+ }
+ }
+ printf("TEs: %d, Edges: %d, Space: %d\n", numte - 1, numedge, od.nedgedata / 2);
+}
diff --git a/src/transaction.h b/src/transaction.h
new file mode 100644
index 0000000..25a7967
--- /dev/null
+++ b/src/transaction.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * transaction.h
+ *
+ */
+
+#ifndef SATSOLVER_TRANSACTION_H
+#define SATSOLVER_TRANSACTION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "pooltypes.h"
+#include "queue.h"
+
+struct _Solver;
+
+#define SOLVER_TRANSACTION_ERASE 0x10
+#define SOLVER_TRANSACTION_REINSTALLED 0x11
+#define SOLVER_TRANSACTION_DOWNGRADED 0x12
+#define SOLVER_TRANSACTION_CHANGED 0x13
+#define SOLVER_TRANSACTION_UPGRADED 0x14
+#define SOLVER_TRANSACTION_REPLACED 0x15
+
+#define SOLVER_TRANSACTION_INSTALL 0x20
+#define SOLVER_TRANSACTION_REINSTALL 0x21
+#define SOLVER_TRANSACTION_DOWNGRADE 0x22
+#define SOLVER_TRANSACTION_CHANGE 0x23
+#define SOLVER_TRANSACTION_UPGRADE 0x24
+#define SOLVER_TRANSACTION_REPLACE 0x25
+
+#define SOLVER_TRANSACTION_MULTIINSTALL 0x30
+#define SOLVER_TRANSACTION_MULTIREINSTALL 0x31
+
+#define SOLVER_TRANSACTION_SHOW_ACTIVE (1 << 0)
+#define SOLVER_TRANSACTION_SHOW_ALL (1 << 1)
+#define SOLVER_TRANSACTION_SHOW_REPLACES (1 << 2)
+
+extern void solver_create_transaction(struct _Solver *solv);
+extern void solver_transaction_all_pkgs(struct _Solver *solv, Id p, Queue *pkgs);
+extern Id solver_transaction_pkg(struct _Solver *solv, Id p);
+extern Id solver_transaction_filter(struct _Solver *solv, Id type, Id p, int mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tests/solver/deptestomatic.c b/tests/solver/deptestomatic.c
index 945bf50..5da6b4c 100644
--- a/tests/solver/deptestomatic.c
+++ b/tests/solver/deptestomatic.c
@@ -47,14 +47,12 @@ static void rc_printdecisions(Solver *solv, Queue *job);
#define MAXNAMELEN 100
-static Pool *decision_data;
-
/*-----------------------------------------------------------------*/
static int
-transaction_sortcmp(const void *ap, const void *bp)
+transaction_sortcmp(const void *ap, const void *bp, void *dp)
{
- Pool *pool = decision_data;
+ Pool *pool = dp;
int r;
Id a = ((Id *)ap)[1];
Id b = ((Id *)bp)[1];
@@ -663,19 +661,19 @@ add_repo( Parsedata *pd, const char *name, const char *file )
err( "add_repo, no filename!" );
return NULL;
}
- char solvname[256];
+ char solvname[256 + 5];
int l = strlen( file );
if (l > 255 )
{
err( "add_repo, filename too long!" );
return NULL;
}
-
+
const char *ptr = file + l - 1;
while (*ptr)
{
if (ptr == file)
- break;
+ break;
if (*ptr == '.')
{
if (!strncmp( ptr, ".xml", 4 ))
@@ -686,6 +684,7 @@ add_repo( Parsedata *pd, const char *name, const char *file )
}
--ptr;
}
+
strncpy( solvname, file, l );
strcpy( solvname + l, ".solv" );
@@ -1441,7 +1440,7 @@ printf("hardware %s\n", dir);
static void
-rc_printdownloadsize(struct solver *solv)
+rc_printdownloadsize(Solver *solv)
{
int i;
Solvable *s;
@@ -1534,6 +1533,13 @@ endElement( void *userData, const char *name )
rc_printdownloadsize(solv);
}
rc_printdecisions(solv, &pd->trials);
+#if 0
+ if (1)
+ {
+ extern void solver_order_transaction(Solver *solv);
+ solver_order_transaction(solv);
+ }
+#endif
}
// clean up
@@ -1623,18 +1629,20 @@ rc_printdecisions(Solver *solv, Queue *job)
printf(">!> Solution #1:\n");
int installs = 0, uninstalls = 0, upgrades = 0;
+ Id type, p;
- decision_data = solv->pool;
- qsort(solv->transaction.elements, solv->transaction.count / 2, 2 * sizeof(Id), transaction_sortcmp);
+ sat_sort(solv->transaction.elements, solv->transaction.count / 2, 2 * sizeof(Id), transaction_sortcmp, pool);
for (i = 0; i < solv->transaction.count; i += 2)
{
+ type = solv->transaction.elements[i];
+ p = solv->transaction.elements[i + 1];
s = pool->solvables + solv->transaction.elements[i + 1];
- switch(solv->transaction.elements[i])
+ type = solver_transaction_filter(solv, type, p, 0);
+ switch(type)
{
case SOLVER_TRANSACTION_INSTALL:
case SOLVER_TRANSACTION_MULTIINSTALL:
- case SOLVER_TRANSACTION_RENAME:
printf(">!> install %s-%s%s", id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
if (!redcarpet)
printf(".%s", id2str(pool, s->arch));
@@ -1644,7 +1652,6 @@ rc_printdecisions(Solver *solv, Queue *job)
installs++;
break;
case SOLVER_TRANSACTION_ERASE:
- case SOLVER_TRANSACTION_OBSOLETED:
if (redcarpet)
printf(">!> remove %s-%s%s\n", id2str(pool, s->name), id2rc(solv, s->evr), id2str(pool, s->evr));
else
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 7fca8f3..5f20cf0 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -47,6 +47,10 @@ 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})
+SET(patchcheck_SOURCES patchcheck.c repo_rpmmd.c repo_susetags.c repo_updateinfoxml.c)
+ADD_EXECUTABLE(patchcheck ${patchcheck_SOURCES})
+TARGET_LINK_LIBRARIES(patchcheck satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
+
ADD_EXECUTABLE( dumpsolv dumpsolv.c )
TARGET_LINK_LIBRARIES( dumpsolv satsolver)
diff --git a/tools/patchcheck.c b/tools/patchcheck.c
new file mode 100644
index 0000000..e24d88d
--- /dev/null
+++ b/tools/patchcheck.c
@@ -0,0 +1,487 @@
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+
+#include "pool.h"
+#include "evr.h"
+#include "poolarch.h"
+#include "repo_solv.h"
+#include "repo_susetags.h"
+#include "repo_updateinfoxml.h"
+#include "repo_rpmmd.h"
+#include "solver.h"
+#include "solverdebug.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);
+}
+
+void
+showproblems(Solver *solv, Solvable *s, Queue *cand, Queue *badguys)
+{
+ Pool *pool = solv->pool;
+ Queue rids, rinfo;
+ Id problem = 0;
+ int jj;
+ int rerun = 0;
+
+ queue_init(&rids);
+ queue_init(&rinfo);
+ printf("can't install %s:\n", solvable2str(pool, s));
+ while ((problem = solver_next_problem(solv, problem)) != 0)
+ {
+ solver_findallproblemrules(solv, problem, &rids);
+ for (jj = 0; jj < rids.count; jj++)
+ {
+ Id probr = rids.elements[jj];
+ int k, l;
+
+ queue_empty(&rinfo);
+ solver_allruleinfos(solv, probr, &rinfo);
+ for (k = 0; k < rinfo.count; k += 4)
+ {
+ Id dep, source, target;
+ source = rinfo.elements[k + 1];
+ target = rinfo.elements[k + 2];
+ dep = rinfo.elements[k + 3];
+ switch (rinfo.elements[k])
+ {
+ case SOLVER_PROBLEM_DISTUPGRADE_RULE:
+ break;
+ case SOLVER_PROBLEM_INFARCH_RULE:
+ printf(" %s has inferior architecture\n", solvid2str(pool, source));
+ break;
+ case SOLVER_PROBLEM_UPDATE_RULE:
+ printf(" update rule for %s\n", solvid2str(pool, source));
+ if (badguys)
+ queue_pushunique(badguys, source);
+ if (!cand)
+ break;
+ /* only drop update problem packages from cand so that we see all problems of this patch */
+ for (l = 0; l < cand->count; l++)
+ if (cand->elements[l] == source || cand->elements[l] == -source)
+ break;
+ if (l == cand->count)
+ break;
+ if (!rerun)
+ {
+ for (l = 0; l < cand->count; l++)
+ if (cand->elements[l] < 0)
+ cand->elements[l] = -cand->elements[l];
+ rerun = 1;
+ }
+ for (l = 0; l < cand->count; l++)
+ if (cand->elements[l] == source)
+ {
+ cand->elements[l] = -source;
+ }
+ 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:
+ printf(" package %s is not installable\n", solvid2str(pool, source));
+ break;
+ case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
+ printf(" nothing provides %s needed by %s\n", dep2str(pool, dep), solvid2str(pool, source));
+ 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", solvid2str(pool, rp));
+ }
+ }
+ break;
+ case SOLVER_PROBLEM_SAME_NAME:
+ printf(" cannot install both %s and %s\n", solvid2str(pool, source), solvid2str(pool, target));
+ break;
+ case SOLVER_PROBLEM_PACKAGE_CONFLICT:
+ printf(" package %s conflicts with %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
+ break;
+ case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
+ printf(" package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
+ break;
+ case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
+ printf(" package %s requires %s, but none of the providers can be installed\n", solvid2str(pool, source), dep2str(pool, dep));
+ break;
+ case SOLVER_PROBLEM_SELF_CONFLICT:
+ printf(" package %s conflicts with %s provided by itself\n", solvid2str(pool, source), dep2str(pool, dep));
+ break;
+ }
+ }
+ }
+ }
+ queue_free(&rids);
+ queue_free(&rinfo);
+}
+
+void
+toinst(Solver *solv, Repo *repo, Repo *instrepo)
+{
+ Pool *pool = solv->pool;
+ int k;
+ Id p;
+
+ for (k = 0; k < solv->decisionq.count; k++)
+ {
+ p = solv->decisionq.elements[k];
+ if (p < 0 || p == SYSTEMSOLVABLE)
+ continue;
+ /* oh my! */
+ pool->solvables[p].repo = instrepo;
+ }
+}
+
+void
+frominst(Solver *solv, Repo *repo, Repo *instrepo)
+{
+ Pool *pool = solv->pool;
+ int k;
+
+ for (k = 1; k < pool->nsolvables; k++)
+ if (pool->solvables[k].repo == instrepo)
+ pool->solvables[k].repo = repo;
+}
+
+int
+main(int argc, char **argv)
+{
+ Pool *pool;
+ char *arch, *mypatch;
+ const char *pname;
+ int l;
+ FILE *fp;
+ int i, j;
+ Queue job;
+ Queue cand;
+ Queue badguys;
+ Id pid, p, pp;
+ Id con, *conp;
+ Solver *solv;
+ Repo *repo, *instrepo;
+ int status = 0;
+ int tests = 0;
+ int updatestart = 0;
+
+ arch = argv[1];
+ pool = pool_create();
+ pool_setarch(pool, arch);
+ mypatch = argv[2];
+
+ repo = repo_create(pool, 0);
+ instrepo = repo_create(pool, 0);
+ for (i = 3; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "--updaterepos"))
+ {
+ updatestart = 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);
+ }
+ 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 (l >= 17 && !strcmp(argv[i] + l - 17, "updateinfo.xml.gz"))
+ {
+ repo_add_updateinfoxml(repo, fp, 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);
+ }
+
+ /* bad hack ahead: clone repo */
+ instrepo->idarraydata = repo->idarraydata;
+ instrepo->start = repo->start;
+ instrepo->end = repo->end;
+ instrepo->nsolvables = repo->nsolvables; /* sic! */
+ pool_set_installed(pool, instrepo);
+
+ pool_addfileprovides(pool);
+ pool_createwhatprovides(pool);
+
+ queue_init(&job);
+ queue_init(&cand);
+ queue_init(&badguys);
+
+#if 0
+ pool_setdebuglevel(pool, 2);
+#endif
+
+ for (pid = 1; pid < pool->nsolvables; pid++)
+ {
+ Solvable *s = pool->solvables + pid;
+ if (!s->repo)
+ continue;
+ if (!pool_installable(pool, s))
+ continue;
+ pname = id2str(pool, s->name);
+ if (strncmp(pname, "patch:", 6) != 0)
+ continue;
+ if (*mypatch)
+ {
+ if (strncmp(mypatch, pname + 6, strlen(pname + 6)) != 0)
+ continue;
+ if (strcmp(mypatch, pname + 6) != 0)
+ {
+ l = strlen(pname + 6);
+ if (mypatch[l] != '-')
+ continue;
+ if (strcmp(mypatch + l + 1, id2str(pool, s->evr)) != 0)
+ continue;
+ }
+ }
+ else
+ {
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ Solvable *s2 = pool->solvables + p;
+ if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) < 0)
+ break;
+ }
+ if (p)
+ continue; /* found a newer one */
+ }
+ tests++;
+ if (!s->conflicts)
+ continue;
+
+#if 0
+ printf("testing patch %s-%s\n", pname + 6, id2str(pool, s->evr));
+#endif
+
+ /* Test 1: are all old patches included */
+ FOR_PROVIDES(p, pp, s->name)
+ {
+ Solvable *s2 = pool->solvables + p;
+ Id con2, *conp2;
+ int shown = 0;
+
+ if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0)
+ continue;
+ if (!s2->conflicts)
+ continue;
+ conp2 = s2->repo->idarraydata + s2->conflicts;
+ while ((con2 = *conp2++) != 0)
+ {
+ Reldep *rd2;
+ if (!ISRELDEP(con2))
+ continue;
+ rd2 = GETRELDEP(pool, con2);
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+ Reldep *rd;
+ if (!ISRELDEP(con))
+ continue;
+ rd = GETRELDEP(pool, con);
+ if (rd->name == rd2->name)
+ break;
+ }
+ if (!con)
+ {
+ if (!shown++)
+ printf("%s:\n", solvable2str(pool, s));
+ printf(" %s contained %s\n", solvable2str(pool, s2), dep2str(pool, rd2->name));
+ }
+ }
+ }
+
+ /* Test 2: are the packages installable */
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+ FOR_PROVIDES(p, pp, con)
+ {
+ queue_empty(&job);
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+ queue_push(&job, p);
+
+ /* also set up some minimal system */
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+ queue_push(&job, str2id(pool, "rpm", 1));
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+ queue_push(&job, str2id(pool, "aaa_base", 1));
+
+ solv = solver_create(pool);
+ solv->dontinstallrecommended = 1;
+ solv = solver_create(pool);
+ solver_solve(solv, &job);
+ toinst(solv, repo, instrepo);
+ solver_free(solv);
+ queue_empty(&job);
+ for (i = 1; i < updatestart; i++)
+ {
+ if (pool->solvables[i].repo != repo || i == pid)
+ continue;
+ queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
+ queue_push(&job, i);
+ }
+ queue_push(&job, SOLVER_INSTALL_SOLVABLE);
+ queue_push(&job, pid);
+ solv = solver_create(pool);
+ solv->dontinstallrecommended = 1;
+ solver_solve(solv, &job);
+ if (solv->problems.count)
+ {
+ status = 1;
+ showproblems(solv, s, 0, 0);
+ }
+ frominst(solv, repo, instrepo);
+ solver_free(solv);
+ }
+ }
+
+ if (0)
+ continue;
+
+ /* Test 3: can we upgrade all packages? */
+ queue_empty(&cand);
+ queue_empty(&badguys);
+ for (p = 1; p < pool->nsolvables; p++)
+ {
+ Solvable *s = pool->solvables + p;
+ if (!s->repo)
+ continue;
+ if (strchr(id2str(pool, s->name), ':'))
+ continue; /* only packages, please */
+ if (!pool_installable(pool, s))
+ continue;
+ queue_push(&cand, p);
+ }
+ while (cand.count)
+ {
+ solv = solver_create(pool);
+ solv->dontinstallrecommended = 1;
+ solv = solver_create(pool);
+ queue_empty(&job);
+ for (i = 0; i < badguys.count; i++)
+ {
+ queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK);
+ queue_push(&job, badguys.elements[i]);
+ }
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+ queue_push(&job, con);
+ }
+ for (i = 0; i < cand.count; i++)
+ {
+ p = cand.elements[i];
+ queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+ queue_push(&job, p);
+ }
+ solver_solve(solv, &job);
+#if 0
+ solver_printdecisions(solv);
+#endif
+ /* put packages into installed repo and prune them from cand */
+ toinst(solv, repo, instrepo);
+ for (i = 0; i < cand.count; i++)
+ {
+ p = cand.elements[i];
+ if (p > 0 && solv->decisionmap[p] > 0)
+ cand.elements[i] = -p; /* drop candidate */
+ }
+ solver_free(solv);
+
+ /* now the interesting part: test patch */
+ queue_empty(&job);
+#if 0
+ for (i = 1; i < updatestart; i++)
+ {
+ if (pool->solvables[i].repo != repo || i == pid)
+ continue;
+ queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
+ queue_push(&job, i);
+ }
+#endif
+ queue_push(&job, SOLVER_INSTALL_SOLVABLE);
+ queue_push(&job, pid);
+ solv = solver_create(pool);
+ solv->dontinstallrecommended = 1;
+ solver_solve(solv, &job);
+
+ if (solv->problems.count)
+ {
+ status = 1;
+ showproblems(solv, s, &cand, &badguys);
+ }
+ frominst(solv, repo, instrepo);
+ solver_free(solv);
+ /* now drop all negative elements from cand */
+ for (i = j = 0; i < cand.count; i++)
+ {
+ if (cand.elements[i] < 0)
+ continue;
+ cand.elements[j++] = cand.elements[i];
+ }
+ if (i == j)
+ break; /* no progress */
+ cand.count = j;
+ }
+ }
+ exit(status);
+}
diff --git a/tools/repo_rpmmd.c b/tools/repo_rpmmd.c
index 867c026..eed0ab1 100644
--- a/tools/repo_rpmmd.c
+++ b/tools/repo_rpmmd.c
@@ -269,7 +269,7 @@ langtag(struct parsedata *pd, Id tag, const char *language)
}
static int
-id3_cmp (const void *v1, const void *v2)
+id3_cmp (const void *v1, const void *v2, void *dp)
{
Id *i1 = (Id*)v1;
Id *i2 = (Id*)v2;
@@ -284,7 +284,7 @@ commit_diskusage (struct parsedata *pd, unsigned handle)
/* Now sort in dirid order. This ensures that parents come before
their children. */
if (pd->ndirs > 1)
- qsort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp);
+ sat_sort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp, 0);
/* Substract leaf numbers from all parents to make the numbers
non-cumulative. This must be done post-order (i.e. all leafs
adjusted before parents). We ensure this by starting at the end of
--
To unsubscribe, e-mail: zypp-commit+unsubscribe@opensuse.org
For additional commands, e-mail: zypp-commit+help@opensuse.org