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})
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")
* - unify rules, remove duplicates
*/
-static Pool *unifyrules_sortcmp_data;
-
/*-------------------------------------------------------------------
*
* compare rules for unification sort
*/
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;
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
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)
{
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 */
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;
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' */
}
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);
}
sat_free(solv->obsoletes);
sat_free(solv->obsoletes_data);
sat_free(solv->multiversionupdaters);
+ sat_free(solv->transaction_installed);
sat_free(solv);
}
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)
{
queue_free(&dqs);
return;
}
- if (level < systemlevel)
+ if (level < systemlevel || level == 1)
break;
n = 0;
} /* for(), decide */
/* 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;
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);
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);
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;
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;
}
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]);
/* 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;
* 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;
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;
}
/*
+ * 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.
*/
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
*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
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)
{
}
}
+/*
+ * 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)
{
*
* 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
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;
}
}
n = 0;
- for (i = 0; i < installed->nsolvables; i++)
+ for (i = 0; i < cnt; i++)
if (obsoletes[i])
{
n += obsoletes[i] + 1;
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;
}
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 */
}
-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
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)
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);
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));
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);
}
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);
}
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);
}
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);
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);
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);
}
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;
/* 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)
{
#include "repo.h"
#include "queue.h"
#include "bitmap.h"
+#include "transaction.h"
/*
* Callback definitions in order to "overwrite" the policies by an external application.
*/
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 */
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 */
#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);
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:
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");
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");
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:
{
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
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
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);
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)
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;
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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
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)
--- /dev/null
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <zlib.h>
+
+#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);
+}
}
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;
/* 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