summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTizenOpenSource <tizenopensrc@samsung.com>2023-12-08 12:23:05 +0900
committerTizenOpenSource <tizenopensrc@samsung.com>2023-12-08 12:23:05 +0900
commit1aac48dff40ef592968a18058bad270da65ed847 (patch)
tree3e9a2fb59b3a9559e2a8f2aa1ad194929708d1df /src
parent2d757ccc60324e7bfcc07f6f46d7f38e30642fcb (diff)
downloadlibsolv-1aac48dff40ef592968a18058bad270da65ed847.tar.gz
libsolv-1aac48dff40ef592968a18058bad270da65ed847.tar.bz2
libsolv-1aac48dff40ef592968a18058bad270da65ed847.zip
Imported Upstream version 0.7.27upstream/0.7.27upstream
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/conda.h11
-rw-r--r--src/cplxdeps.c1
-rw-r--r--src/dataiterator.h12
-rw-r--r--src/decision.c1228
-rw-r--r--src/knownid.h1
-rw-r--r--src/libsolv.ver17
-rw-r--r--src/linkedpkg.c40
-rw-r--r--src/linkedpkg.h7
-rw-r--r--src/policy.c65
-rw-r--r--src/pool.c2
-rw-r--r--src/pool.h33
-rw-r--r--src/poolarch.c6
-rw-r--r--src/pooltypes.h17
-rw-r--r--src/problems.c157
-rw-r--r--src/problems.h9
-rw-r--r--src/repo.h4
-rw-r--r--src/repo_write.c29
-rw-r--r--src/repodata.h11
-rw-r--r--src/rules.c249
-rw-r--r--src/rules.h11
-rw-r--r--src/solvable.c135
-rw-r--r--src/solver.c452
-rw-r--r--src/solver.h35
-rw-r--r--src/solverdebug.c40
-rw-r--r--src/transaction.h7
26 files changed, 2062 insertions, 519 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bbf30ba..ca04b39 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -20,7 +20,7 @@ SET (libsolv_SRCS
transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c
chksum.c md5.c sha1.c sha2.c solvversion.c selection.c
fileprovides.c diskusage.c suse.c solver_util.c cleandeps.c
- userinstalled.c filelistfilter.c)
+ userinstalled.c filelistfilter.c decision.c)
SET (libsolv_HEADERS
bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
diff --git a/src/conda.h b/src/conda.h
index 3bcfa2d..07703be 100644
--- a/src/conda.h
+++ b/src/conda.h
@@ -13,10 +13,21 @@
#ifndef LIBSOLV_CONDA_H
#define LIBSOLV_CONDA_H
+#include "pooltypes.h"
+#include "solvable.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
int pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode);
int solvable_conda_matchversion(Solvable *s, const char *version);
Id pool_addrelproviders_conda(Pool *pool, Id name, Id evr, Queue *plist);
Id pool_conda_matchspec(Pool *pool, const char *name);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* LIBSOLV_CONDA_H */
diff --git a/src/cplxdeps.c b/src/cplxdeps.c
index 6c40752..26e754d 100644
--- a/src/cplxdeps.c
+++ b/src/cplxdeps.c
@@ -405,6 +405,7 @@ pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map *m, int neg)
Reldep *rd2 = GETRELDEP(pool, rd->evr);
if (rd2->flags == REL_ELSE)
{
+ pool_add_pos_literals_complex_dep(pool, rd2->name, q, m, !neg);
pool_add_pos_literals_complex_dep(pool, rd2->evr, q, m, !neg);
dep = rd2->name;
}
diff --git a/src/dataiterator.h b/src/dataiterator.h
index 0649258..357ae59 100644
--- a/src/dataiterator.h
+++ b/src/dataiterator.h
@@ -20,8 +20,6 @@
extern "C" {
#endif
-struct s_Repo;
-
typedef struct s_KeyValue {
Id id;
const char *str;
@@ -106,8 +104,8 @@ typedef struct s_Dataiterator
int flags;
Pool *pool;
- struct s_Repo *repo;
- struct s_Repodata *data;
+ Repo *repo;
+ Repodata *data;
/* data pointers */
unsigned char *dp;
@@ -165,9 +163,9 @@ typedef struct s_Dataiterator
* keyname: if non-null, limit search to this keyname
* match: if non-null, limit search to this match
*/
-int dataiterator_init(Dataiterator *di, Pool *pool, struct s_Repo *repo, Id p, Id keyname, const char *match, int flags);
+int dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags);
void dataiterator_init_clone(Dataiterator *di, Dataiterator *from);
-void dataiterator_set_search(Dataiterator *di, struct s_Repo *repo, Id p);
+void dataiterator_set_search(Dataiterator *di, Repo *repo, Id p);
void dataiterator_set_keyname(Dataiterator *di, Id keyname);
int dataiterator_set_match(Dataiterator *di, const char *match, int flags);
@@ -181,7 +179,7 @@ void dataiterator_skip_attribute(Dataiterator *di);
void dataiterator_skip_solvable(Dataiterator *di);
void dataiterator_skip_repo(Dataiterator *di);
void dataiterator_jump_to_solvid(Dataiterator *di, Id solvid);
-void dataiterator_jump_to_repo(Dataiterator *di, struct s_Repo *repo);
+void dataiterator_jump_to_repo(Dataiterator *di, Repo *repo);
void dataiterator_entersub(Dataiterator *di);
void dataiterator_clonepos(Dataiterator *di, Dataiterator *from);
void dataiterator_seek(Dataiterator *di, int whence);
diff --git a/src/decision.c b/src/decision.c
new file mode 100644
index 0000000..c0cf4ad
--- /dev/null
+++ b/src/decision.c
@@ -0,0 +1,1228 @@
+/*
+ * Copyright (c) 2022, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * decision.c
+ *
+ * solver decision and alternative introspection code
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "util.h"
+#include "evr.h"
+
+int
+solver_get_decisionlevel(Solver *solv, Id p)
+{
+ return solv->decisionmap[p];
+}
+
+void
+solver_get_decisionqueue(Solver *solv, Queue *decisionq)
+{
+ queue_free(decisionq);
+ queue_init_clone(decisionq, &solv->decisionq);
+}
+
+int
+solver_get_lastdecisionblocklevel(Solver *solv)
+{
+ Id p;
+ if (solv->decisionq.count == 0)
+ return 0;
+ p = solv->decisionq.elements[solv->decisionq.count - 1];
+ if (p < 0)
+ p = -p;
+ return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
+}
+
+void
+solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
+{
+ Id p;
+ int i;
+
+ queue_empty(decisionq);
+ for (i = 0; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p < 0)
+ p = -p;
+ if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
+ break;
+ }
+ if (i == solv->decisionq.count)
+ return;
+ for (i = 0; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p < 0)
+ p = -p;
+ if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
+ queue_push(decisionq, p);
+ else
+ break;
+ }
+}
+
+/* return the reason and some extra info (i.e. a rule id) why
+ * a package was installed/conflicted */
+int
+solver_describe_decision(Solver *solv, Id p, Id *infop)
+{
+ int i;
+ Id pp, why;
+
+ if (infop)
+ *infop = 0;
+ if (!solv->decisionmap[p])
+ return SOLVER_REASON_UNRELATED;
+ pp = solv->decisionmap[p] < 0 ? -p : p;
+ for (i = 0; i < solv->decisionq.count; i++)
+ if (solv->decisionq.elements[i] == pp)
+ break;
+ if (i == solv->decisionq.count) /* just in case... */
+ return SOLVER_REASON_UNRELATED;
+ why = solv->decisionq_why.elements[i];
+ if (infop)
+ *infop = why >= 0 ? why : -why;
+ if (why > 0)
+ return SOLVER_REASON_UNIT_RULE;
+ i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
+ return solv->decisionq_reason.elements[i];
+}
+
+/* create pseudo ruleinfo elements why a package was installed if
+ * the reason was SOLVER_REASON_WEAKDEP */
+int
+solver_allweakdepinfos(Solver *solv, Id p, Queue *whyq)
+{
+ Pool *pool = solv->pool;
+ int i;
+ int level = solv->decisionmap[p];
+ int decisionno;
+ Solvable *s;
+
+ queue_empty(whyq);
+ if (level < 0)
+ return 0; /* huh? */
+ for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
+ if (solv->decisionq.elements[decisionno] == p)
+ break;
+ if (decisionno == solv->decisionq.count)
+ return 0; /* huh? */
+ i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
+ if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP)
+ return 0; /* huh? */
+
+ /* 1) list all packages that recommend us */
+ for (i = 1; i < pool->nsolvables; i++)
+ {
+ Id *recp, rec, pp2, p2;
+ if (solv->decisionmap[i] <= 0 || solv->decisionmap[i] >= level)
+ continue;
+ s = pool->solvables + i;
+ if (!s->recommends)
+ continue;
+ if (!solv->addalreadyrecommended && s->repo == solv->installed)
+ continue;
+ recp = s->repo->idarraydata + s->recommends;
+ while ((rec = *recp++) != 0)
+ {
+ int found = 0;
+ FOR_PROVIDES(p2, pp2, rec)
+ {
+ if (p2 == p)
+ found = 1;
+ else
+ {
+ /* if p2 is already installed, this recommends is ignored */
+ if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
+ break;
+ }
+ }
+ if (!p2 && found)
+ {
+ queue_push2(whyq, SOLVER_RULE_PKG_RECOMMENDS, i);
+ queue_push2(whyq, 0, rec);
+ }
+ }
+ }
+ /* 2) list all supplements */
+ s = pool->solvables + p;
+ if (s->supplements && level > 0)
+ {
+ Id *supp, sup, pp2, p2;
+ /* this is a hack. to use solver_dep_fulfilled we temporarily clear
+ * everything above our level in the decisionmap */
+ for (i = decisionno; i < solv->decisionq.count; i++ )
+ {
+ p2 = solv->decisionq.elements[i];
+ if (p2 > 0)
+ solv->decisionmap[p2] = -solv->decisionmap[p2];
+ }
+ supp = s->repo->idarraydata + s->supplements;
+ while ((sup = *supp++) != 0)
+ if (solver_dep_fulfilled(solv, sup))
+ {
+ int found = 0;
+ /* let's see if this is an easy supp */
+ FOR_PROVIDES(p2, pp2, sup)
+ {
+ if (!solv->addalreadyrecommended && solv->installed)
+ {
+ if (pool->solvables[p2].repo == solv->installed)
+ continue;
+ }
+ if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
+ {
+ queue_push2(whyq, SOLVER_RULE_PKG_SUPPLEMENTS, p);
+ queue_push2(whyq, p2, sup);
+ found = 1;
+ }
+ }
+ if (!found)
+ {
+ /* hard case, just note dependency with no package */
+ queue_push2(whyq, SOLVER_RULE_PKG_SUPPLEMENTS, p);
+ queue_push2(whyq, 0, sup);
+ }
+ }
+ for (i = decisionno; i < solv->decisionq.count; i++)
+ {
+ p2 = solv->decisionq.elements[i];
+ if (p2 > 0)
+ solv->decisionmap[p2] = -solv->decisionmap[p2];
+ }
+ }
+ return whyq->count / 4;
+}
+
+SolverRuleinfo
+solver_weakdepinfo(Solver *solv, Id p, Id *fromp, Id *top, Id *depp)
+{
+ Queue iq;
+ queue_init(&iq);
+ solver_allweakdepinfos(solv, p, &iq);
+ if (fromp)
+ *fromp = iq.count ? iq.elements[1] : 0;
+ if (top)
+ *top = iq.count ? iq.elements[2] : 0;
+ if (depp)
+ *depp = iq.count ? iq.elements[3] : 0;
+ return iq.count ? iq.elements[0] : SOLVER_RULE_UNKNOWN;
+}
+
+/* deprecated, use solver_allweakdepinfos instead */
+void
+solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
+{
+ int i, j;
+ solver_allweakdepinfos(solv, p, whyq);
+ for (i = j = 0; i < whyq->count; i += 4)
+ {
+ if (whyq->elements[i] == SOLVER_RULE_PKG_RECOMMENDS)
+ {
+ whyq->elements[j++] = SOLVER_REASON_RECOMMENDED;
+ whyq->elements[j++] = whyq->elements[i + 1];
+ whyq->elements[j++] = whyq->elements[i + 3];
+ }
+ else if (whyq->elements[i] == SOLVER_RULE_PKG_SUPPLEMENTS)
+ {
+ whyq->elements[j++] = SOLVER_REASON_SUPPLEMENTED;
+ whyq->elements[j++] = whyq->elements[i + 2];
+ whyq->elements[j++] = whyq->elements[i + 3];
+ }
+ }
+ queue_truncate(whyq, j);
+}
+
+static int
+decisionsort_cmp(const void *va, const void *vb, void *vd)
+{
+ Solver *solv = vd;
+ Pool *pool = solv->pool;
+ const Id *a = va, *b = vb; /* (decision, reason, rid, bits, type, from, to, dep) */
+ Solvable *as, *bs;
+ if (a[4] != b[4]) /* type */
+ return a[4] - b[4];
+ if (a[7] != b[7]) /* dep id */
+ return a[7] - b[7];
+ as = pool->solvables + a[5];
+ bs = pool->solvables + b[5];
+ if (as->name != bs->name)
+ return strcmp(pool_id2str(pool, as->name), pool_id2str(pool, bs->name));
+ if (as->evr != bs->evr)
+ {
+ int r = pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE);
+ if (r)
+ return r;
+ }
+ as = pool->solvables + a[6];
+ bs = pool->solvables + b[6];
+ if (as->name != bs->name)
+ return strcmp(pool_id2str(pool, as->name), pool_id2str(pool, bs->name));
+ if (as->evr != bs->evr)
+ {
+ int r = pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+static void
+decisionmerge(Solver *solv, Queue *q)
+{
+ Pool *pool = solv->pool;
+ int i, j;
+
+ for (i = 0; i < q->count; i += 8)
+ {
+ Id p = q->elements[i] >= 0 ? q->elements[i] : -q->elements[i];
+ int reason = q->elements[i + 1];
+ int bits = q->elements[i + 3];
+ Id name = pool->solvables[p].name;
+ for (j = i + 8; j < q->count; j += 8)
+ {
+ int merged;
+ p = q->elements[j] >= 0 ? q->elements[j] : -q->elements[j];
+ if (reason != q->elements[j + 1] || name != pool->solvables[p].name)
+ break;
+ merged = solver_merge_decisioninfo_bits(solv, bits, q->elements[i + 4], q->elements[i + 5], q->elements[i + 6], q->elements[i + 7], q->elements[j + 3], q->elements[j + 4], q->elements[j + 5], q->elements[j + 6], q->elements[j + 7]);
+ if (!merged)
+ break;
+ bits = merged;
+ }
+ j -= 8;
+ for (; i < j; i += 8)
+ q->elements[i + 3] = bits;
+ }
+}
+
+/* move a decison from position "from" to a smaller position "to" */
+static inline void
+move_decision(Queue *q, int to, int from)
+{
+ queue_insertn(q, to, 8, 0);
+ memmove(q->elements + to, q->elements + from + 8, 8 * sizeof(Id));
+ queue_deleten(q, from + 8, 8);
+}
+
+/* sort a block of SOLVER_REASON_UNIT_RULE decisions */
+static void
+sort_unit_decisions(Solver *solv, Queue *q, int start, int end, Map *m)
+{
+ Pool *pool = solv->pool;
+ int i, j, k, doing = 1;
+ if (start + 8 == end)
+ {
+ Id truelit = q->elements[start];
+ MAPSET(m, truelit >= 0 ? truelit : -truelit);
+ return;
+ }
+ /* alternate between conflicts and installs, starting with conflicts */
+ for (i = start; i < end; doing ^= 1)
+ {
+ for (j = k = i; j < end; j += 8)
+ {
+ Rule *or;
+ Id p, pp;
+ Id truelit = q->elements[j];
+ if ((doing == 0 && truelit < 0) || (doing != 0 && truelit >= 0))
+ continue;
+ or = solv->rules + q->elements[j + 2];
+ FOR_RULELITERALS(p, pp, or)
+ if (p != truelit && !MAPTST(m, p >= 0 ? p : -p))
+ break;
+ if (p)
+ continue; /* not unit yet */
+ if (j > k)
+ move_decision(q, k, j);
+ k += 8;
+ }
+ if (k == i)
+ continue;
+ if (i + 8 < k)
+ solv_sort(q->elements + i, (k - i) / 8, 8 * sizeof(Id), decisionsort_cmp, solv);
+ for (; i < k; i += 8)
+ {
+ Id truelit = q->elements[i];
+ MAPSET(m, truelit >= 0 ? truelit : -truelit);
+ }
+ }
+}
+
+static void
+solver_get_proof(Solver *solv, Id id, int flags, Queue *q)
+{
+ Pool *pool = solv->pool;
+ Map seen, seent; /* seent: was the literal true or false */
+ Id rid, truelit;
+ int first = 1;
+ int why, i, cnt;
+
+ queue_empty(q);
+ if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_PROBLEM)
+ why = solv->problems.elements[2 * id - 2];
+ else if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_LEARNTRULE && id >= solv->learntrules && id < solv->nrules)
+ why = solv->learnt_why.elements[id - solv->learntrules];
+ else
+ return;
+ if (!solv->learnt_pool.elements[why])
+ return;
+
+ map_init(&seen, pool->nsolvables);
+ map_init(&seent, pool->nsolvables);
+ while ((rid = solv->learnt_pool.elements[why++]) != 0)
+ {
+ Rule *r = solv->rules + rid;
+ Id p, pp;
+ truelit = 0;
+ FOR_RULELITERALS(p, pp, r)
+ {
+ Id vv = p > 0 ? p : -p;
+ if (MAPTST(&seen, vv))
+ {
+ if ((p > 0 ? 1 : 0) == (MAPTST(&seent, vv) ? 1 : 0))
+ {
+ if (truelit)
+ abort();
+ truelit = p; /* the one true literal! */
+ }
+ }
+ else
+ {
+ /* a new literal. it must be false as the rule is unit */
+ MAPSET(&seen, vv);
+ if (p < 0)
+ MAPSET(&seent, vv);
+ }
+ }
+ if (truelit)
+ queue_push(q, truelit);
+ else if (!first)
+ abort();
+ queue_push(q, rid);
+ first = 0;
+ }
+
+ /* add ruleinfo data to all rules (and also reverse the queue) */
+ cnt = q->count;
+ for (i = q->count - 1; i >= 0; i -= 2)
+ {
+ SolverRuleinfo type;
+ Id from = 0, to = 0, dep = 0;
+ rid = q->elements[i];
+ type = solver_ruleinfo(solv, rid, &from, &to, &dep);
+ if (type == SOLVER_RULE_CHOICE || type == SOLVER_RULE_RECOMMENDS)
+ {
+ /* use pkg ruleinfo for choice/recommends rules */
+ Id rid2 = solver_rule2pkgrule(solv, rid);
+ if (rid2)
+ type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
+ }
+ queue_insertn(q, q->count, 8, 0);
+ q->elements[q->count - 8] = i > 0 ? q->elements[i - 1] : 0;
+ q->elements[q->count - 8 + 1] = i > 0 ? SOLVER_REASON_UNIT_RULE : SOLVER_REASON_UNSOLVABLE;
+ q->elements[q->count - 8 + 2] = rid;
+ q->elements[q->count - 8 + 4] = type;
+ q->elements[q->count - 8 + 5] = from;
+ q->elements[q->count - 8 + 6] = to;
+ q->elements[q->count - 8 + 7] = dep;
+ }
+ queue_deleten(q, 0, cnt);
+
+ /* switch last two decisions if the unsolvable rule is of type SOLVER_RULE_RPM_SAME_NAME */
+ if (q->count >= 16 && q->elements[q->count - 8 + 3] == SOLVER_RULE_RPM_SAME_NAME && q->elements[q->count - 16] > 0)
+ {
+ Rule *r = solv->rules + q->elements[q->count - 8 + 1];
+ /* make sure that the rule is a binary conflict and it matches the installed element */
+ if (r->p < 0 && (r->d == 0 || r->d == -1) && r->w2 < 0
+ && (q->elements[q->count - 16] == -r->p || q->elements[q->count - 16] -r->w2))
+ {
+ /* looks good! swap decisions and fixup truelit entries */
+ move_decision(q, q->count - 16, q->count - 8);
+ q->elements[q->count - 16] = -q->elements[q->count - 8];
+ q->elements[q->count - 8] = 0;
+ }
+ }
+
+ /* put learnt rule premises in front */
+ MAPZERO(&seen);
+ MAPSET(&seen, 1);
+ i = 0;
+ if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_LEARNTRULE)
+ {
+ /* insert learnt prereqs at front */
+ Rule *r = solv->rules + id;
+ Id p, pp;
+ i = 0;
+ FOR_RULELITERALS(p, pp, r)
+ {
+ queue_insertn(q, i, 8, 0);
+ q->elements[i] = -p;
+ q->elements[i + 1] = SOLVER_REASON_PREMISE;
+ q->elements[i + 5] = p >= 0 ? p : -p;
+ MAPSET(&seen, p >= 0 ? p : -p);
+ i += 8;
+ }
+ }
+
+ if (flags & SOLVER_DECISIONLIST_SORTED)
+ {
+ /* sort premise block */
+ if (i > 8)
+ solv_sort(q->elements, i / 8, 8 * sizeof(Id), decisionsort_cmp, solv);
+ sort_unit_decisions(solv, q, i, q->count - 8, &seen);
+ }
+
+ map_free(&seen);
+ map_free(&seent);
+
+ if (!(flags & SOLVER_DECISIONLIST_WITHINFO))
+ {
+ int j;
+ for (i = j = 0; i < q->count; i += 8)
+ {
+ q->elements[j++] = q->elements[i];
+ q->elements[j++] = q->elements[i + 1];
+ q->elements[j++] = q->elements[i + 2];
+ }
+ queue_truncate(q, j);
+ }
+ else
+ {
+ /* set decisioninfo bits */
+ for (i = 0; i < q->count; i += 8)
+ q->elements[i + 3] = solver_calc_decisioninfo_bits(solv, q->elements[i], q->elements[i + 4], q->elements[i + 5], q->elements[i + 6], q->elements[i + 7]);
+ if (flags & SOLVER_DECISIONLIST_MERGEDINFO)
+ decisionmerge(solv, q);
+ }
+}
+
+void
+solver_get_learnt(Solver *solv, Id id, int flags, Queue *q)
+{
+ int why = -1;
+ Queue todo;
+
+ queue_empty(q);
+ queue_init(&todo);
+ if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_PROBLEM)
+ why = solv->problems.elements[2 * id - 2];
+ else if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_LEARNTRULE && id >= solv->learntrules && id < solv->nrules)
+ why = solv->learnt_why.elements[id - solv->learntrules];
+ else if ((flags & SOLVER_DECISIONLIST_TYPEMASK) == SOLVER_DECISIONLIST_SOLVABLE)
+ {
+ int i, j, cnt;
+ solver_get_decisionlist(solv, id, 0, &todo);
+ cnt = todo.count;
+ for (i = 0; i < cnt; i += 3)
+ {
+ int rid = todo.elements[i + 2];
+ if (rid < solv->learntrules || rid >= solv->nrules)
+ continue;
+ /* insert sorted and unified */
+ for (j = 0; j < q->count; j++)
+ {
+ if (q->elements[j] < rid)
+ continue;
+ if (q->elements[j] == rid)
+ rid = 0;
+ break;
+ }
+ if (!rid)
+ continue; /* already in list */
+ queue_insert(q, j, rid);
+ queue_push(&todo, solv->learnt_why.elements[rid - solv->learntrules]);
+ }
+ queue_deleten(&todo, 0, cnt);
+ }
+ else
+ {
+ queue_free(&todo);
+ return;
+ }
+ if (why >= 0)
+ queue_push(&todo, why);
+ while (todo.count)
+ {
+ int i, rid;
+ why = queue_pop(&todo);
+ while ((rid = solv->learnt_pool.elements[why++]) != 0)
+ {
+ if (rid < solv->learntrules || rid >= solv->nrules)
+ continue;
+ /* insert sorted and unified */
+ for (i = 0; i < q->count; i++)
+ {
+ if (q->elements[i] < rid)
+ continue;
+ if (q->elements[i] == rid)
+ rid = 0;
+ break;
+ }
+ if (!rid)
+ continue; /* already in list */
+ queue_insert(q, i, rid);
+ queue_push(&todo, solv->learnt_why.elements[rid - solv->learntrules]);
+ }
+ }
+ queue_free(&todo);
+}
+
+static void
+getdecisionlist(Solver *solv, Map *dm, int flags, Queue *decisionlistq)
+{
+ Pool *pool = solv->pool;
+ int i, ii, reason, info;
+ Queue iq;
+
+ queue_empty(decisionlistq);
+ if ((flags & SOLVER_DECISIONLIST_TYPEMASK) != SOLVER_DECISIONLIST_SOLVABLE)
+ return;
+ queue_init(&iq);
+ for (ii = solv->decisionq.count - 1; ii > 0; ii--)
+ {
+ Id v = solv->decisionq.elements[ii];
+ Id vv = (v > 0 ? v : -v);
+ if (!MAPTST(dm, vv))
+ continue;
+ info = solv->decisionq_why.elements[ii];
+ if (info > 0)
+ reason = SOLVER_REASON_UNIT_RULE;
+ else if (info <= 0)
+ {
+ info = -info;
+ reason = solv->decisionmap[vv];
+ reason = solv->decisionq_reason.elements[reason >= 0 ? reason : -reason];
+ }
+ if (flags & (SOLVER_DECISIONLIST_SORTED | SOLVER_DECISIONLIST_WITHINFO))
+ {
+ queue_insertn(decisionlistq, 0, 5, 0);
+ if (reason == SOLVER_REASON_WEAKDEP)
+ {
+ solver_allweakdepinfos(solv, v, &iq);
+ if (iq.count)
+ {
+ decisionlistq->elements[1] = iq.elements[0];
+ decisionlistq->elements[2] = iq.elements[1];
+ decisionlistq->elements[3] = iq.elements[2];
+ decisionlistq->elements[4] = iq.elements[3];
+ }
+ }
+ else if (info > 0)
+ {
+ Id from, to, dep;
+ int type = solver_ruleinfo(solv, info, &from, &to, &dep);
+ if (type == SOLVER_RULE_CHOICE || type == SOLVER_RULE_RECOMMENDS)
+ {
+ /* use pkg ruleinfo for choice/recommends rules */
+ Id rid2 = solver_rule2pkgrule(solv, info);
+ if (rid2)
+ type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
+ }
+ decisionlistq->elements[1] = type;
+ decisionlistq->elements[2] = from;
+ decisionlistq->elements[3] = to;
+ decisionlistq->elements[4] = dep;
+ }
+ }
+ queue_unshift(decisionlistq, info);
+ queue_unshift(decisionlistq, reason);
+ queue_unshift(decisionlistq, v);
+ switch (reason)
+ {
+ case SOLVER_REASON_WEAKDEP:
+ if (v <= 0)
+ break;
+ solver_allweakdepinfos(solv, v, &iq);
+ for (i = 0; i < iq.count; i += 4)
+ {
+ if (iq.elements[i + 1])
+ MAPSET(dm, iq.elements[i + 1]);
+ if (iq.elements[i + 2])
+ MAPSET(dm, iq.elements[i + 2]);
+ else if (iq.elements[i] == SOLVER_RULE_PKG_SUPPLEMENTS)
+ {
+ Id p2, pp2, id = iq.elements[i + 3];
+ FOR_PROVIDES(p2, pp2, id)
+ if (solv->decisionmap[p2] > 0)
+ MAPSET(dm, p2);
+ }
+ }
+ break;
+ case SOLVER_REASON_RESOLVE_JOB:
+ case SOLVER_REASON_UNIT_RULE:
+ case SOLVER_REASON_RESOLVE:
+ solver_ruleliterals(solv, info, &iq);
+ for (i = 0; i < iq.count; i++)
+ {
+ Id p2 = iq.elements[i];
+ if (p2 < 0)
+ MAPSET(dm, -p2);
+ else if (solv->decisionmap[p2] > 0)
+ MAPSET(dm, p2);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ queue_free(&iq);
+ if ((flags & SOLVER_DECISIONLIST_SORTED) != 0)
+ {
+ /* reuse dm as "seen" map */
+ MAPZERO(dm);
+ MAPSET(dm, 1);
+ for (i = 0; i < decisionlistq->count; i += 8)
+ {
+ if (decisionlistq->elements[i + 1] != SOLVER_REASON_UNIT_RULE)
+ {
+ Id p = decisionlistq->elements[i] < 0 ? -decisionlistq->elements[i] : decisionlistq->elements[i];
+ MAPSET(dm, p);
+ }
+ else
+ {
+ int j;
+ for (j = i + 8; j < decisionlistq->count; j += 8)
+ if (decisionlistq->elements[j + 1] != SOLVER_REASON_UNIT_RULE)
+ break;
+ sort_unit_decisions(solv, decisionlistq, i, j, dm);
+ }
+ }
+ }
+ if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
+ {
+ /* set decisioninfo bits */
+ for (i = 0; i < decisionlistq->count; i += 8)
+ decisionlistq->elements[i + 3] = solver_calc_decisioninfo_bits(solv, decisionlistq->elements[i], decisionlistq->elements[i + 4], decisionlistq->elements[i + 5], decisionlistq->elements[i + 6], decisionlistq->elements[i + 7]);
+ if (flags & SOLVER_DECISIONLIST_MERGEDINFO)
+ decisionmerge(solv, decisionlistq);
+ }
+ else if ((flags & SOLVER_DECISIONLIST_SORTED) != 0)
+ {
+ /* strip the info elements we added for sorting */
+ int j;
+ for (i = j = 0; i < decisionlistq->count; i += 8)
+ {
+ decisionlistq->elements[j++] = decisionlistq->elements[i];
+ decisionlistq->elements[j++] = decisionlistq->elements[i + 1];
+ decisionlistq->elements[j++] = decisionlistq->elements[i + 2];
+ }
+ queue_truncate(decisionlistq, j);
+ }
+}
+
+void
+solver_get_decisionlist(Solver *solv, Id id, int flags, Queue *decisionlistq)
+{
+ Pool *pool = solv->pool;
+ Map dm;
+ if ((flags & SOLVER_DECISIONLIST_TYPEMASK) != SOLVER_DECISIONLIST_SOLVABLE)
+ return solver_get_proof(solv, id, flags, decisionlistq);
+ map_init(&dm, pool->nsolvables);
+ MAPSET(&dm, id);
+ getdecisionlist(solv, &dm, flags, decisionlistq);
+ map_free(&dm);
+ if (!decisionlistq->count)
+ {
+ queue_push(decisionlistq, -id);
+ queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
+ if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
+ {
+ queue_push(decisionlistq, solver_calc_decisioninfo_bits(solv, -id, 0, 0, 0, 0));
+ queue_push2(decisionlistq, 0, 0);
+ queue_push2(decisionlistq, 0, 0);
+ }
+ }
+}
+
+void
+solver_get_decisionlist_multiple(Solver *solv, Queue *idq, int flags, Queue *decisionlistq)
+{
+ Pool *pool = solv->pool;
+ int i;
+ Map dm;
+ queue_empty(decisionlistq);
+ if ((flags & SOLVER_DECISIONLIST_TYPEMASK) != SOLVER_DECISIONLIST_SOLVABLE)
+ return;
+ map_init(&dm, pool->nsolvables);
+ for (i = 0; i < idq->count; i++)
+ {
+ Id p = idq->elements[i];
+ if (solv->decisionmap[p] != 0)
+ MAPSET(&dm, p);
+ }
+ getdecisionlist(solv, &dm, flags, decisionlistq);
+ map_free(&dm);
+ for (i = 0; i < idq->count; i++)
+ {
+ Id p = idq->elements[i];
+ if (solv->decisionmap[p] != 0)
+ continue;
+ queue_push(decisionlistq, -p);
+ queue_push2(decisionlistq, SOLVER_REASON_UNRELATED, 0);
+ if ((flags & SOLVER_DECISIONLIST_WITHINFO) != 0)
+ {
+ queue_push(decisionlistq, solver_calc_decisioninfo_bits(solv, -p, 0, 0, 0, 0));
+ queue_push2(decisionlistq, 0, 0);
+ queue_push2(decisionlistq, 0, 0);
+ }
+ }
+}
+
+
+const char *
+solver_reason2str(Solver *solv, int reason)
+{
+ switch(reason)
+ {
+ case SOLVER_REASON_WEAKDEP:
+ return "a weak dependency";
+ case SOLVER_REASON_RESOLVE_JOB:
+ return "a job rule";
+ case SOLVER_REASON_RESOLVE:
+ return "a rule";
+ case SOLVER_REASON_UNIT_RULE:
+ return "an unit rule";
+ case SOLVER_REASON_KEEP_INSTALLED:
+ return "update/keep installed";
+ case SOLVER_REASON_UPDATE_INSTALLED:
+ return "update installed";
+ case SOLVER_REASON_CLEANDEPS_ERASE:
+ return "cleandeps erase";
+ case SOLVER_REASON_RESOLVE_ORPHAN:
+ return "orphaned package";
+ case SOLVER_REASON_UNSOLVABLE:
+ return "unsolvable";
+ case SOLVER_REASON_PREMISE:
+ return "learnt rule premise";
+ case SOLVER_REASON_UNRELATED:
+ return "it is unrelated";
+ default:
+ break;
+ }
+ return "an unknown reason";
+}
+
+static const char *
+decisionruleinfo2str(Solver *solv, Id decision, int type, Id from, Id to, Id dep)
+{
+ int bits = solver_calc_decisioninfo_bits(solv, decision, type, from, to, dep);
+ return solver_decisioninfo2str(solv, bits, type, from, to, dep);
+}
+
+const char *
+solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info)
+{
+ if (reason == SOLVER_REASON_WEAKDEP && decision > 0)
+ {
+ Id from, to, dep;
+ int type = solver_weakdepinfo(solv, decision, &from, &to, &dep);
+ if (type)
+ return decisionruleinfo2str(solv, decision, type, from, to, dep);
+ }
+ if ((reason == SOLVER_REASON_RESOLVE_JOB || reason == SOLVER_REASON_UNIT_RULE || reason == SOLVER_REASON_RESOLVE || reason == SOLVER_REASON_UNSOLVABLE) && info > 0)
+ {
+ Id from, to, dep;
+ int type = solver_ruleinfo(solv, info, &from, &to, &dep);
+ if (type == SOLVER_RULE_CHOICE || type == SOLVER_RULE_RECOMMENDS)
+ {
+ Id rid2 = solver_rule2pkgrule(solv, info);
+ if (rid2)
+ {
+ type = solver_ruleinfo(solv, rid2, &from, &to, &dep);
+ if (type)
+ return decisionruleinfo2str(solv, decision, type, from, to, dep);
+ }
+ }
+ if (type)
+ return decisionruleinfo2str(solv, decision, type, from, to, dep);
+ }
+ return solver_reason2str(solv, reason);
+}
+
+/* decision merge state bits */
+#define DMS_INITED (1 << 0)
+#define DMS_IDENTICAL_FROM (1 << 1)
+#define DMS_IDENTICAL_TO (1 << 2)
+#define DMS_MERGED (1 << 3)
+#define DMS_NEGATIVE (1 << 4)
+#define DMS_NOMERGE (1 << 5)
+
+/* add some bits about the decision and the ruleinfo so we can join decisions */
+int
+solver_calc_decisioninfo_bits(Solver *solv, Id decision, int type, Id from, Id to, Id dep)
+{
+ Id decisionpkg = decision >= 0 ? decision : -decision;
+ int bits = DMS_INITED | (decision < 0 ? DMS_NEGATIVE : 0);
+ if (!decision)
+ return bits | DMS_NOMERGE;
+ switch (type)
+ {
+ case SOLVER_RULE_DISTUPGRADE:
+ case SOLVER_RULE_INFARCH:
+ case SOLVER_RULE_UPDATE:
+ case SOLVER_RULE_FEATURE:
+ case SOLVER_RULE_BLACK:
+ case SOLVER_RULE_STRICT_REPO_PRIORITY:
+ case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
+ case SOLVER_RULE_PKG_REQUIRES:
+ case SOLVER_RULE_PKG_RECOMMENDS:
+ case SOLVER_RULE_PKG_SUPPLEMENTS:
+ if (decisionpkg == from)
+ bits |= DMS_IDENTICAL_FROM;
+ break;
+ case SOLVER_RULE_PKG_SAME_NAME:
+ case SOLVER_RULE_PKG_CONFLICTS:
+ case SOLVER_RULE_PKG_OBSOLETES:
+ case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
+ case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
+ case SOLVER_RULE_PKG_CONSTRAINS:
+ if (decisionpkg == from)
+ bits |= DMS_IDENTICAL_FROM;
+ else if (decisionpkg == to)
+ bits |= DMS_IDENTICAL_TO;
+ break;
+ default:
+ break;
+ }
+ return bits;
+}
+
+/* try to merge the ruleinfos of two decisions */
+int
+solver_merge_decisioninfo_bits(Solver *solv, int bits1, int type1, Id from1, Id to1, Id dep1, int bits2, int type2, Id from2, Id to2, Id dep2)
+{
+ int merged = 0;
+ if (type1 != type2 || dep1 != dep2)
+ return 0;
+ if (!bits1 || !bits2 || ((bits1 | bits2) & DMS_NOMERGE) != 0 || ((bits1 ^ bits2) & DMS_NEGATIVE) != 0)
+ return 0;
+ merged = (((bits1 ^ (DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO)) | (bits2 ^ (DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO))) ^ (DMS_IDENTICAL_FROM | DMS_IDENTICAL_TO)) | DMS_MERGED;
+ if (((bits1 & DMS_MERGED) != 0 && bits1 != merged) || ((bits2 & DMS_MERGED) != 0 && bits2 != merged))
+ return 0;
+ if (((merged & DMS_IDENTICAL_FROM) == 0 && from1 != from2) || ((merged & DMS_IDENTICAL_TO) == 0 && to1 != to2))
+ return 0;
+ return merged;
+}
+
+void
+solver_decisionlist_solvables(Solver *solv, Queue *decisionlistq, int pos, Queue *q)
+{
+ queue_empty(q);
+ for (; pos < decisionlistq->count; pos += 8)
+ {
+ Id p = decisionlistq->elements[pos];
+ queue_push(q, p > 0 ? p : -p);
+ if ((decisionlistq->elements[pos + 3] & DMS_MERGED) == 0)
+ break;
+ }
+}
+
+int
+solver_decisionlist_merged(Solver *solv, Queue *decisionlistq, int pos)
+{
+ int cnt = 0;
+ for (; pos < decisionlistq->count; pos += 8, cnt++)
+ if ((decisionlistq->elements[pos + 3] & DMS_MERGED) == 0)
+ break;
+ return cnt;
+}
+
+/* special version of solver_ruleinfo2str which supports merged decisions */
+const char *
+solver_decisioninfo2str(Solver *solv, int bits, int type, Id from, Id to, Id dep)
+{
+ Pool *pool = solv->pool;
+ const char *s;
+ int multiple = bits & DMS_MERGED;
+
+ /* use it/they variants if DMS_IDENTICAL_FROM is set */
+ if ((bits & DMS_IDENTICAL_FROM) != 0)
+ {
+ switch (type)
+ {
+ case SOLVER_RULE_DISTUPGRADE:
+ return multiple ? "they do not belong to a distupgrade repository" : "it does not belong to a distupgrade repository";
+ case SOLVER_RULE_INFARCH:
+ return multiple ? "they have inferior architecture": "it has inferior architecture";
+ case SOLVER_RULE_UPDATE:
+ return multiple ? "they need to stay installed or be updated" : "it needs to stay installed or be updated";
+ case SOLVER_RULE_FEATURE:
+ return multiple ? "they need to stay installed or be updated/downgraded" : "it needs to stay installed or be updated/downgraded";
+ case SOLVER_RULE_BLACK:
+ return multiple ? "they can only be installed by a direct request" : "it can only be installed by a direct request";
+ case SOLVER_RULE_STRICT_REPO_PRIORITY:
+ return multiple ? "they are excluded by strict repo priority" : "it is excluded by strict repo priority";
+
+ case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
+ return pool_tmpjoin(pool, "nothing provides ", pool_dep2str(pool, dep), 0);
+ case SOLVER_RULE_PKG_REQUIRES:
+ return pool_tmpjoin(pool, multiple ? "they require " : "it requires ", pool_dep2str(pool, dep), 0);
+ case SOLVER_RULE_PKG_RECOMMENDS:
+ return pool_tmpjoin(pool, multiple ? "they recommend " : "it recommends ", pool_dep2str(pool, dep), 0);
+ case SOLVER_RULE_PKG_SUPPLEMENTS:
+ s = pool_tmpjoin(pool, multiple ? "they supplement " : "it supplements ", pool_dep2str(pool, dep), 0);
+ if (to)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
+ return s;
+ case SOLVER_RULE_PKG_SAME_NAME:
+ return pool_tmpappend(pool, multiple ? "they have the same name as " : "it has the same name as ", pool_solvid2str(pool, to), 0);
+ case SOLVER_RULE_PKG_CONFLICTS:
+ s = pool_tmpappend(pool, multiple ? "they conflict with " : "it conflicts with ", pool_dep2str(pool, dep), 0);
+ if (to)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
+ return s;
+ case SOLVER_RULE_PKG_OBSOLETES:
+ s = pool_tmpappend(pool, multiple ? "they obsolete " : "it obsoletes ", pool_dep2str(pool, dep), 0);
+ if (to)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
+ return s;
+ case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
+ s = pool_tmpjoin(pool, multiple ? "they are installed and obsolete " : "it is installed and obsoletes ", pool_dep2str(pool, dep), 0);
+ if (to)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
+ return s;
+ case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
+ s = pool_tmpjoin(pool, multiple ? "they implicitly obsolete " : "it implicitly obsoletes ", pool_dep2str(pool, dep), 0);
+ if (to)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, to));
+ return s;
+ case SOLVER_RULE_PKG_CONSTRAINS:
+ s = pool_tmpappend(pool, multiple ? "they have constraint " : "it has constraint ", pool_dep2str(pool, dep), 0);
+ if (to)
+ s = pool_tmpappend(pool, s, " conflicting with ", pool_solvid2str(pool, to));
+ return s;
+ default:
+ break;
+ }
+ }
+
+ /* in some cases we can drop the "to" part if DMS_IDENTICAL_TO is set */
+ if ((bits & DMS_IDENTICAL_TO) != 0)
+ {
+ switch (type)
+ {
+ case SOLVER_RULE_PKG_SAME_NAME:
+ return pool_tmpappend(pool, multiple ? "they have the same name as " : "it has the same name as ", pool_solvid2str(pool, from), 0);
+ case SOLVER_RULE_PKG_CONFLICTS:
+ case SOLVER_RULE_PKG_OBSOLETES:
+ case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
+ case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
+ case SOLVER_RULE_PKG_CONSTRAINS:
+ bits &= ~DMS_IDENTICAL_TO;
+ to = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* fallback to solver_ruleinfo2str if we can */
+ if (multiple && (bits & (DMS_IDENTICAL_FROM|DMS_IDENTICAL_TO)) != 0)
+ return "unsupported decision merge?";
+ return solver_ruleinfo2str(solv, type, from, to, dep);
+}
+
+int
+solver_alternatives_count(Solver *solv)
+{
+ Id *elements = solv->branches.elements;
+ int res, count;
+ for (res = 0, count = solv->branches.count; count; res++)
+ count -= elements[count - 2];
+ return res;
+}
+
+int
+solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
+{
+ int cnt = solver_alternatives_count(solv);
+ int count = solv->branches.count;
+ Id *elements = solv->branches.elements;
+ if (choices)
+ queue_empty(choices);
+ if (alternative <= 0 || alternative > cnt)
+ return 0;
+ elements += count;
+ for (; cnt > alternative; cnt--)
+ elements -= elements[-2];
+ if (levelp)
+ *levelp = elements[-1];
+ if (fromp)
+ *fromp = elements[-4];
+ if (idp)
+ *idp = elements[-3];
+ if (chosenp)
+ {
+ int i;
+ *chosenp = 0;
+ for (i = elements[-2]; i > 4; i--)
+ {
+ Id p = -elements[-i];
+ if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
+ {
+ *chosenp = p;
+ break;
+ }
+ }
+ }
+ if (choices)
+ queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
+ return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
+}
+
+static int
+find_alternative_rule_from_learnt_rec(Solver *solv, int rid, Map *m, int cnt)
+{
+ Pool *pool = solv->pool;
+ int why = solv->learnt_why.elements[rid - solv->learntrules];
+ while ((rid = solv->learnt_pool.elements[why++]) != 0)
+ {
+ Rule *r = solv->rules + rid;
+ Id p, pp;
+ int c;
+ if (rid >= solv->learntrules)
+ {
+ if ((rid = find_alternative_rule_from_learnt_rec(solv, rid, m, cnt)))
+ return rid;
+ continue;
+ }
+ c = 0;
+ FOR_RULELITERALS(p, pp, r)
+ if (p > 0 && MAPTST(m, p))
+ c++;
+ if (c == cnt) /* all bits hit */
+ return rid;
+ }
+ return 0;
+}
+
+static int
+find_alternative_rule_from_learnt(Solver *solv, int rid)
+{
+ Pool *pool = solv->pool;
+ Map m;
+ int i, count, cnt;
+ Id *elements = solv->branches.elements;
+
+ /* find alternative by rule id */
+ for (count = solv->branches.count; count; count -= elements[count - 2])
+ if (elements[count - 4] == 0 && elements[count - 3] == rid)
+ break;
+ if (!count)
+ return 0;
+ map_init(&m, pool->nsolvables);
+ cnt = 0;
+ for (i = count - elements[count - 2]; i < count - 4; i++)
+ if (elements[i] > 0)
+ {
+ MAPSET(&m, elements[i]);
+ cnt++;
+ }
+ rid = find_alternative_rule_from_learnt_rec(solv, rid, &m, cnt);
+ map_free(&m);
+ return rid;
+}
+
+int
+solver_alternativeinfo(Solver *solv, int type, Id id, Id from, Id *fromp, Id *top, Id *depp)
+{
+ if (fromp)
+ *fromp = 0;
+ if (top)
+ *top = 0;
+ if (depp)
+ *depp = 0;
+ if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
+ {
+ if (fromp)
+ *fromp = from;
+ if (depp)
+ *depp = id;
+ return SOLVER_RULE_PKG_RECOMMENDS;
+ }
+ else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
+ {
+ int rclass = solver_ruleclass(solv, id);
+ if (rclass == SOLVER_RULE_LEARNT)
+ {
+ id = find_alternative_rule_from_learnt(solv, id);
+ if (!id)
+ return SOLVER_RULE_LEARNT;
+ rclass = solver_ruleclass(solv, id);
+ }
+ if (rclass == SOLVER_RULE_CHOICE || rclass == SOLVER_RULE_RECOMMENDS)
+ id = solver_rule2pkgrule(solv, id);
+ else if (rclass == SOLVER_RULE_BEST)
+ {
+ Id info = solv->bestrules_info[id - solv->bestrules];
+ if (info > 0)
+ {
+ /* best update */
+ if (fromp)
+ *fromp = info;
+ return SOLVER_RULE_UPDATE;
+ }
+ id = -info; /* best job, delegate to job rule */
+ }
+ return solver_ruleinfo(solv, id, fromp, top, depp);
+ }
+ return 0;
+}
+
+const char *
+solver_alternative2str(Solver *solv, int type, Id id, Id from)
+{
+ const char *s;
+ Pool *pool = solv->pool;
+ Id to, dep;
+ type = solver_alternativeinfo(solv, type, id, from, &from, &to, &dep);
+ switch (type)
+ {
+ case SOLVER_RULE_PKG_RECOMMENDS:
+ s = pool_dep2str(pool, dep);
+ if (from)
+ s = pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
+ return s;
+ case SOLVER_RULE_PKG_REQUIRES:
+ s = pool_dep2str(pool, dep);
+ if (from)
+ s = pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, from));
+ return s;
+ case SOLVER_RULE_PKG_CONFLICTS:
+ s = pool_dep2str(pool, dep);
+ if (from)
+ s = pool_tmpappend(pool, s, ", conflicted by ", pool_solvid2str(pool, from));
+ return s;
+ case SOLVER_RULE_YUMOBS:
+ return pool_tmpjoin(pool, pool_id2str(pool, pool->solvables[to].name), ", obsoleting ", pool_dep2str(pool, dep));;
+ case SOLVER_RULE_JOB:
+ if ((to & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES || (to & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_NAME)
+ return pool_dep2str(pool, dep);
+ return solver_select2str(pool, to & SOLVER_SELECTMASK, dep);
+ case SOLVER_RULE_UPDATE:
+ case SOLVER_RULE_FEATURE:
+ return pool_solvid2str(pool, from);
+ default:
+ break;
+ }
+ return solver_ruleinfo2str(solv, type, from, to, dep);
+}
+
diff --git a/src/knownid.h b/src/knownid.h
index 2bb27b2..19f67ae 100644
--- a/src/knownid.h
+++ b/src/knownid.h
@@ -272,6 +272,7 @@ KNOWNID(SOLVABLE_LANGONLY, "solvable:langonly"),
KNOWNID(UPDATE_COLLECTIONLIST, "update:collectionlist"), /* list of UPDATE_COLLECTION (actually packages) and UPDATE_MODULE */
KNOWNID(SOLVABLE_MULTIARCH, "solvable:multiarch"), /* debian multi-arch field */
+KNOWNID(SOLVABLE_SIGNATUREDATA, "solvable:signaturedata"), /* conda */
KNOWNID(ID_NUM_INTERNAL, 0)
diff --git a/src/libsolv.ver b/src/libsolv.ver
index c77f8d3..b9f9f96 100644
--- a/src/libsolv.ver
+++ b/src/libsolv.ver
@@ -113,6 +113,7 @@ SOLV_1.0 {
pool_shrink_rels;
pool_shrink_strings;
pool_solvable2str;
+ pool_solvidset2str;
pool_str2id;
pool_strn2id;
pool_tmpappend;
@@ -341,9 +342,13 @@ SOLV_1.0 {
solvable_trivial_installable_queue;
solvable_trivial_installable_repo;
solvable_unset;
+ solver_all_solutionelements;
solver_allruleinfos;
+ solver_allweakdepinfos;
solver_alternative2str;
+ solver_alternativeinfo;
solver_alternatives_count;
+ solver_calc_decisioninfo_bits;
solver_calc_duchanges;
solver_calc_installsizechange;
solver_calculate_multiversionmap;
@@ -351,6 +356,10 @@ SOLV_1.0 {
solver_create;
solver_create_state_maps;
solver_create_transaction;
+ solver_decisioninfo2str;
+ solver_decisionlist_merged;
+ solver_decisionlist_solvables;
+ solver_decisionreason2str;
solver_describe_decision;
solver_describe_weakdep_decision;
solver_findallproblemrules;
@@ -360,13 +369,17 @@ SOLV_1.0 {
solver_get_alternative;
solver_get_decisionblock;
solver_get_decisionlevel;
+ solver_get_decisionlist;
+ solver_get_decisionlist_multiple;
solver_get_decisionqueue;
solver_get_flag;
solver_get_lastdecisionblocklevel;
+ solver_get_learnt;
solver_get_orphaned;
solver_get_recommendations;
solver_get_unneeded;
solver_get_userinstalled;
+ solver_merge_decisioninfo_bits;
solver_next_problem;
solver_next_solution;
solver_next_solutionelement;
@@ -387,6 +400,7 @@ SOLV_1.0 {
solver_problem2str;
solver_problem_count;
solver_problemruleinfo2str;
+ solver_reason2str;
solver_rule2job;
solver_rule2jobidx;
solver_rule2pkgrule;
@@ -394,12 +408,14 @@ SOLV_1.0 {
solver_rule2solvable;
solver_ruleclass;
solver_ruleinfo;
+ solver_ruleinfo2str;
solver_ruleliterals;
solver_rulecmp;
solver_select2str;
solver_set_flag;
solver_solution_count;
solver_solutionelement2str;
+ solver_solutionelementtype2str;
solver_solutionelement_count;
solver_solutionelement_internalid;
solver_solutionelement_extrajobflags;
@@ -408,6 +424,7 @@ SOLV_1.0 {
solver_take_solutionelement;
solver_trivial_installable;
solver_unifyrules;
+ solver_weakdepinfo;
stringpool_clone;
stringpool_free;
stringpool_freehash;
diff --git a/src/linkedpkg.c b/src/linkedpkg.c
index 5912f98..26fb706 100644
--- a/src/linkedpkg.c
+++ b/src/linkedpkg.c
@@ -44,7 +44,7 @@
#ifdef ENABLE_LINKED_PKGS
-void
+static void
find_application_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
{
Id req = 0;
@@ -121,7 +121,7 @@ find_application_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp
*prvidp = prv;
}
-void
+static void
find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
{
Id p, pp, namerelid;
@@ -232,7 +232,7 @@ find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Qu
*prvidp = solvable_selfprovidedep(s);
}
-void
+static void
find_pattern_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
{
Id p, pp, *pr, apevr = 0, aprel = 0;
@@ -274,37 +274,31 @@ find_pattern_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Qu
*prvidp = aprel;
}
-/* the following two functions are used in solvable_lookup_str_base to do
+/* the following function is used in solvable_lookup_str_base to do
* translated lookups on the product/pattern packages
*/
Id
-find_autopattern_name(Pool *pool, Solvable *s)
+find_autopackage_name(Pool *pool, Solvable *s)
{
+ const char *autoprv = 0;
+ const char *n = pool_id2str(pool, s->name);
Id prv, *prvp;
- if (!s->provides)
- return 0;
- for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
- if (ISRELDEP(prv))
- {
- Reldep *rd = GETRELDEP(pool, prv);
- if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autopattern()"))
- return strncmp(pool_id2str(pool, rd->evr), "pattern:", 8) != 0 ? rd->evr : 0;
- }
- return 0;
-}
-Id
-find_autoproduct_name(Pool *pool, Solvable *s)
-{
- Id prv, *prvp;
- if (!s->provides)
+ if (*n == 'p')
+ {
+ if (!strncmp("pattern:", n, 8))
+ autoprv = "autopattern()";
+ if (!strncmp("product:", n, 8))
+ autoprv = "autoproduct()";
+ }
+ if (!autoprv)
return 0;
for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
if (ISRELDEP(prv))
{
Reldep *rd = GETRELDEP(pool, prv);
- if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autoproduct()"))
- return strncmp(pool_id2str(pool, rd->evr), "product:", 8) != 0 ? rd->evr : 0;
+ if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), autoprv))
+ return rd->evr;
}
return 0;
}
diff --git a/src/linkedpkg.h b/src/linkedpkg.h
index 51b82a5..4cf5561 100644
--- a/src/linkedpkg.h
+++ b/src/linkedpkg.h
@@ -25,12 +25,7 @@ has_package_link(Pool *pool, Solvable *s)
return 0;
}
-extern void find_application_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
-extern void find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
-extern void find_pattern_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
-
-extern Id find_autopattern_name(Pool *pool, Solvable *s);
-extern Id find_autoproduct_name(Pool *pool, Solvable *s);
+extern Id find_autopackage_name(Pool *pool, Solvable *s);
/* generic */
extern void find_package_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
diff --git a/src/policy.c b/src/policy.c
index c02d237..02548ea 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -232,13 +232,13 @@ check_complex_dep(Solver *solv, Id dep, Map *m, Queue **cqp)
{
Pool *pool = solv->pool;
Queue q;
- queue_init(&q);
Id p;
int i, qcnt;
#if 0
printf("check_complex_dep %s\n", pool_dep2str(pool, dep));
#endif
+ queue_init(&q);
i = pool_normalize_complex_dep(pool, dep, &q, CPLXDEPS_EXPAND);
if (i == 0 || i == 1)
{
@@ -1511,7 +1511,7 @@ policy_create_obsolete_index(Solver *solv)
{
FOR_PROVIDES(p, pp, obs)
{
- Solvable *ps = pool->solvables + p;;
+ Solvable *ps = pool->solvables + p;
if (ps->repo != installed)
continue;
if (ps->name == s->name)
@@ -1545,7 +1545,7 @@ policy_create_obsolete_index(Solver *solv)
{
FOR_PROVIDES(p, pp, obs)
{
- Solvable *ps = pool->solvables + p;;
+ Solvable *ps = pool->solvables + p;
if (ps->repo != installed)
continue;
if (ps->name == s->name)
@@ -1562,6 +1562,29 @@ policy_create_obsolete_index(Solver *solv)
}
+/* return true if solvable s obsoletes solvable with id pi */
+static inline int
+is_obsoleting(Pool *pool, Solvable *s, Id pi)
+{
+ Id p, pp, obs, *obsp;
+ Solvable *si = pool->solvables + pi;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, si, s))
+ return 0;
+ obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0) /* for all obsoletes */
+ {
+ FOR_PROVIDES(p, pp, obs) /* and all matching providers of the obsoletes */
+ {
+ if (p != pi)
+ continue;
+ if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
+ continue;
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*
* find update candidates
*
@@ -1576,8 +1599,7 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
{
/* installed packages get a special upgrade allowed rule */
Pool *pool = solv->pool;
- Id p, pp, n, p2, pp2;
- Id obs, *obsp;
+ Id p, pp, n;
Solvable *ps;
int haveprovobs = 0;
int allowdowngrade = allow_all ? 1 : solv->allowdowngrade;
@@ -1618,31 +1640,14 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
continue;
else if ((!solv->noupdateprovide || solv->needupdateprovide) && ps->obsoletes) /* provides/obsoletes combination ? */
{
- /* check if package ps obsoletes installed package s */
+ /* check if package ps that provides s->name obsoletes installed package s */
/* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless
* use it to limit our update candidates */
- if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, ps))
+ if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
continue;
- obsp = ps->repo->idarraydata + ps->obsoletes;
- while ((obs = *obsp++) != 0) /* for all obsoletes */
- {
- FOR_PROVIDES(p2, pp2, obs) /* and all matching providers of the obsoletes */
- {
- Solvable *ps2 = pool->solvables + p2;
- if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps2, obs))
- continue;
- if (p2 == n) /* match ! */
- break;
- }
- if (p2) /* match! */
- break;
- }
- if (!obs) /* continue if no match */
+ if (!is_obsoleting(pool, ps, n))
continue;
- /* here we have 'p' with a matching provides/obsoletes combination
- * thus flagging p as a valid update candidate for s
- */
- haveprovobs = 1;
+ haveprovobs = 1; /* have matching provides/obsoletes combination */
}
else
continue;
@@ -1664,14 +1669,14 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
for (opp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *opp++) != 0;)
{
ps = pool->solvables + p;
- if (!allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
- continue;
- if (!allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
- continue;
/* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless
* use it to limit our update candidates */
if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
continue;
+ if (!allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
+ continue;
+ if (!allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
+ continue;
queue_push(qs, p);
}
}
diff --git a/src/pool.c b/src/pool.c
index 54226e9..45e85ea 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -1461,7 +1461,7 @@ pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
{
Id pp;
FOR_PROVIDES(p, pp, dep)
- if (pool_match_dep(pool, p, dep))
+ if (pool_match_nevr(pool, pool->solvables + p, dep))
queue_push(q, p);
return;
}
diff --git a/src/pool.h b/src/pool.h
index 935a326..08cf1d0 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -36,13 +36,11 @@ extern "C" {
/*----------------------------------------------- */
-struct s_Repo;
-struct s_Repodata;
struct s_Repokey;
struct s_KeyValue;
typedef struct s_Datapos {
- struct s_Repo *repo;
+ Repo *repo;
Id solvid;
Id repodataid;
Id schema;
@@ -66,16 +64,16 @@ struct s_Pool_tmpspace {
struct s_Pool {
void *appdata; /* application private pointer */
- struct s_Stringpool ss;
+ Stringpool ss;
Reldep *rels; /* table of rels: Id -> Reldep */
int nrels; /* number of unique rels */
- struct s_Repo **repos;
+ Repo **repos;
int nrepos; /* repos allocated */
int urepos; /* repos in use */
- struct s_Repo *installed; /* packages considered installed */
+ Repo *installed; /* packages considered installed */
Solvable *solvables;
int nsolvables; /* solvables allocated */
@@ -109,16 +107,16 @@ struct s_Pool {
Map *considered;
/* callback for REL_NAMESPACE dependencies handled by the application */
- Id (*nscallback)(struct s_Pool *, void *data, Id name, Id evr);
+ Id (*nscallback)(Pool *, void *data, Id name, Id evr);
void *nscallbackdata;
/* debug mask and callback */
int debugmask;
- void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str);
+ void (*debugcallback)(Pool *, void *data, int type, const char *str);
void *debugcallbackdata;
/* load callback */
- int (*loadcallback)(struct s_Pool *, struct s_Repodata *, void *);
+ int (*loadcallback)(Pool *, Repodata *, void *);
void *loadcallbackdata;
/* search position */
@@ -155,7 +153,7 @@ struct s_Pool {
char *rootdir;
- int (*custom_vendorcheck)(struct s_Pool *, Solvable *, Solvable *);
+ int (*custom_vendorcheck)(Pool *, Solvable *, Solvable *);
int addfileprovidesfiltered; /* 1: only use filtered file list for addfileprovides */
int addedfileprovides; /* true: application called addfileprovides */
@@ -251,14 +249,14 @@ extern int pool_set_flag(Pool *pool, int flag, int value);
extern int pool_get_flag(Pool *pool, int flag);
extern void pool_debug(Pool *pool, int type, const char *format, ...) __attribute__((format(printf, 3, 4)));
-extern void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str), void *debugcallbackdata);
+extern void pool_setdebugcallback(Pool *pool, void (*debugcallback)(Pool *pool, void *data, int type, const char *str), void *debugcallbackdata);
extern void pool_setdebugmask(Pool *pool, int mask);
-extern void pool_setloadcallback(Pool *pool, int (*cb)(struct s_Pool *, struct s_Repodata *, void *), void *loadcbdata);
-extern void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct s_Pool *, void *, Id, Id), void *nscbdata);
+extern void pool_setloadcallback(Pool *pool, int (*cb)(Pool *, Repodata *, void *), void *loadcbdata);
+extern void pool_setnamespacecallback(Pool *pool, Id (*cb)(Pool *, void *, Id, Id), void *nscbdata);
extern void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
-extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(struct s_Pool *, Solvable *, Solvable *));
-extern int (*pool_get_custom_vendorcheck(Pool *pool))(struct s_Pool *, Solvable *, Solvable *);
+extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, Solvable *));
+extern int (*pool_get_custom_vendorcheck(Pool *pool))(Pool *, Solvable *, Solvable *);
extern char *pool_alloctmpspace(Pool *pool, int len);
extern void pool_freetmpspace(Pool *pool, const char *space);
@@ -266,7 +264,7 @@ extern char *pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const
extern char *pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3);
extern const char *pool_bin2hex(Pool *pool, const unsigned char *buf, int len);
-extern void pool_set_installed(Pool *pool, struct s_Repo *repo);
+extern void pool_set_installed(Pool *pool, Repo *repo);
extern int pool_error(Pool *pool, int ret, const char *format, ...) __attribute__((format(printf, 3, 4)));
extern char *pool_errstr(Pool *pool);
@@ -297,6 +295,7 @@ static inline const char *pool_solvid2str(Pool *pool, Id p)
{
return pool_solvable2str(pool, pool->solvables + p);
}
+extern const char *pool_solvidset2str(Pool *pool, Queue *q);
void pool_set_languages(Pool *pool, const char **languages, int nlanguages);
Id pool_id2langid(Pool *pool, Id id, const char *lang, int create);
@@ -362,7 +361,7 @@ void pool_set_whatprovides(Pool *pool, Id id, Id providers);
* key - search only this key
* match - key must match this string
*/
-void pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct s_Repodata *data, struct s_Repokey *key, struct s_KeyValue *kv), void *cbdata);
+void pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, struct s_Repokey *key, struct s_KeyValue *kv), void *cbdata);
void pool_clear_pos(Pool *pool);
diff --git a/src/poolarch.c b/src/poolarch.c
index 6727760..e5fb5bf 100644
--- a/src/poolarch.c
+++ b/src/poolarch.c
@@ -22,8 +22,14 @@
static const char *archpolicies[] = {
#if defined(FEDORA) || defined(MAGEIA)
+ "x86_64_v4", "x86_64_v4:x86_64_v3:x86_64_v2:x86_64:athlon:i686:i586:i486:i386",
+ "x86_64_v3", "x86_64_v3:x86_64_v2:x86_64:athlon:i686:i586:i486:i386",
+ "x86_64_v2", "x86_64_v2:x86_64:athlon:i686:i586:i486:i386",
"x86_64", "x86_64:athlon:i686:i586:i486:i386",
#else
+ "x86_64_v4", "x86_64_v4:x86_64_v3:x86_64_v2:x86_64:i686:i586:i486:i386",
+ "x86_64_v3", "x86_64_v3:x86_64_v2:x86_64:i686:i586:i486:i386",
+ "x86_64_v2", "x86_64_v2:x86_64:i686:i586:i486:i386",
"x86_64", "x86_64:i686:i586:i486:i386",
#endif
"i686", "i686:i586:i486:i386",
diff --git a/src/pooltypes.h b/src/pooltypes.h
index c69f375..bccdfc1 100644
--- a/src/pooltypes.h
+++ b/src/pooltypes.h
@@ -13,6 +13,10 @@
#ifndef LIBSOLV_POOLTYPES_H
#define LIBSOLV_POOLTYPES_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* format version number for .solv files */
#define SOLV_VERSION_0 0
#define SOLV_VERSION_1 1
@@ -36,10 +40,23 @@ typedef struct s_Stringpool Stringpool;
struct s_Pool;
typedef struct s_Pool Pool;
+struct s_Repo;
+typedef struct s_Repo Repo;
+
+struct s_Repodata;
+typedef struct s_Repodata Repodata;
+
+struct s_Solvable;
+typedef struct s_Solvable Solvable;
+
/* identifier for string values */
typedef int Id; /* must be signed!, since negative Id is used in solver rules to denote negation */
/* offset value, e.g. used to 'point' into the stringspace */
typedef unsigned int Offset;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* LIBSOLV_POOLTYPES_H */
diff --git a/src/problems.c b/src/problems.c
index 0bd48d4..b0a421c 100644
--- a/src/problems.c
+++ b/src/problems.c
@@ -22,6 +22,7 @@
#include "pool.h"
#include "util.h"
#include "evr.h"
+#include "policy.h"
#include "solverdebug.h"
/**********************************************************************************/
@@ -220,6 +221,16 @@ solver_disableproblemset(Solver *solv, int start)
solver_disableproblem(solv, solv->problems.elements[i]);
}
+#ifdef SUSE
+static inline int
+suse_isptf(Pool *pool, Solvable *s)
+{
+ if (!strncmp("ptf-", pool_id2str(pool, s->name), 4))
+ return 1;
+ return 0;
+}
+#endif
+
/*-------------------------------------------------------------------
* try to fix a problem by auto-uninstalling packages
*/
@@ -250,6 +261,10 @@ solver_autouninstall(Solver *solv, int start)
Id p = solv->installed->start + (v - solv->updaterules);
if (m && !MAPTST(m, v - solv->updaterules))
continue;
+#ifdef SUSE
+ if (suse_isptf(pool, pool->solvables + p))
+ continue; /* do not autouninstall ptf packages */
+#endif
if (pool->considered && !MAPTST(pool->considered, p))
continue; /* do not uninstalled disabled packages */
if (solv->bestrules_info && solv->bestrules_end > solv->bestrules)
@@ -972,6 +987,7 @@ solver_solutionelement_internalid(Solver *solv, Id problem, Id solution)
return solv->solutions.elements[solidx + 2 * solv->solutions.elements[solidx] + 3];
}
+/* currently just SOLVER_CLEANDEPS */
Id
solver_solutionelement_extrajobflags(Solver *solv, Id problem, Id solution)
{
@@ -1026,6 +1042,56 @@ solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, I
return element + 1;
}
+static inline void
+queue_push3(Queue *q, Id id1, Id id2, Id id3)
+{
+ queue_push(q, id1);
+ queue_push2(q, id2, id3);
+}
+
+static void
+add_expanded_replace(Solver *solv, Id p, Id rp, Queue *q)
+{
+ int illegal = policy_is_illegal(solv, solv->pool->solvables + p, solv->pool->solvables + rp, 0);
+ if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0)
+ queue_push3(q, SOLVER_SOLUTION_REPLACE_DOWNGRADE, p, rp);
+ if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0)
+ queue_push3(q, SOLVER_SOLUTION_REPLACE_ARCHCHANGE, p, rp);
+ if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0)
+ queue_push3(q, SOLVER_SOLUTION_REPLACE_VENDORCHANGE, p, rp);
+ if ((illegal & POLICY_ILLEGAL_NAMECHANGE) != 0)
+ queue_push3(q, SOLVER_SOLUTION_REPLACE_NAMECHANGE, p, rp);
+ if (!illegal || (illegal & ~(POLICY_ILLEGAL_DOWNGRADE | POLICY_ILLEGAL_ARCHCHANGE | POLICY_ILLEGAL_VENDORCHANGE | POLICY_ILLEGAL_NAMECHANGE)))
+ queue_push3(q, SOLVER_SOLUTION_REPLACE, p, rp);
+}
+
+/* solutionelements are (type, p, rp) triplets */
+void
+solver_all_solutionelements(Solver *solv, Id problem, Id solution, int expandreplaces, Queue *q)
+{
+ int i, cnt;
+ Id solidx = solv->problems.elements[problem * 2 - 1];
+ solidx = solv->solutions.elements[solidx + solution];
+ queue_empty(q);
+ if (!solidx)
+ return;
+ cnt = solv->solutions.elements[solidx++];
+ for (i = 0; i < cnt; i++)
+ {
+ Id p = solv->solutions.elements[solidx++];
+ Id rp = solv->solutions.elements[solidx++];
+ if (p > 0)
+ {
+ if (rp && expandreplaces)
+ add_expanded_replace(solv, p, rp, q);
+ else
+ queue_push3(q, rp ? SOLVER_SOLUTION_REPLACE : SOLVER_SOLUTION_ERASE, p, rp);
+ }
+ else
+ queue_push3(q, p, rp, 0);
+ }
+}
+
void
solver_take_solutionelement(Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job)
{
@@ -1043,6 +1109,11 @@ solver_take_solutionelement(Solver *solv, Id p, Id rp, Id extrajobflags, Queue *
job->elements[rp] = 0;
return;
}
+ if (p == SOLVER_SOLUTION_ERASE)
+ {
+ p = rp;
+ rp = 0;
+ }
if (rp <= 0 && p <= 0)
return; /* just in case */
if (rp > 0)
@@ -1388,62 +1459,66 @@ solver_problem2str(Solver *solv, Id problem)
}
const char *
-solver_solutionelement2str(Solver *solv, Id p, Id rp)
+solver_solutionelementtype2str(Solver *solv, int type, Id p, Id rp)
{
Pool *pool = solv->pool;
- if (p == SOLVER_SOLUTION_JOB || p == SOLVER_SOLUTION_POOLJOB)
- {
- Id how, what;
- if (p == SOLVER_SOLUTION_JOB)
- rp += solv->pooljobcnt;
- how = solv->job.elements[rp - 1];
- what = solv->job.elements[rp];
- return pool_tmpjoin(pool, "do not ask to ", pool_job2str(pool, how, what, 0), 0);
- }
- else if (p == SOLVER_SOLUTION_INFARCH)
+ Solvable *s;
+ const char *str;
+
+ switch (type)
{
- Solvable *s = pool->solvables + rp;
+ case SOLVER_SOLUTION_JOB:
+ case SOLVER_SOLUTION_POOLJOB:
+ if (type == SOLVER_SOLUTION_JOB)
+ p += solv->pooljobcnt;
+ return pool_tmpjoin(pool, "do not ask to ", pool_job2str(pool, solv->job.elements[p - 1], solv->job.elements[p], 0), 0);
+ case SOLVER_SOLUTION_INFARCH:
+ s = pool->solvables + p;
if (solv->installed && s->repo == solv->installed)
return pool_tmpjoin(pool, "keep ", pool_solvable2str(pool, s), " despite the inferior architecture");
else
return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the inferior architecture");
- }
- else if (p == SOLVER_SOLUTION_DISTUPGRADE)
- {
- Solvable *s = pool->solvables + rp;
+ case SOLVER_SOLUTION_DISTUPGRADE:
+ s = pool->solvables + p;
if (solv->installed && s->repo == solv->installed)
return pool_tmpjoin(pool, "keep obsolete ", pool_solvable2str(pool, s), 0);
else
return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " from excluded repository");
- }
- else if (p == SOLVER_SOLUTION_BEST)
- {
- Solvable *s = pool->solvables + rp;
+ case SOLVER_SOLUTION_BEST:
+ s = pool->solvables + p;
if (solv->installed && s->repo == solv->installed)
return pool_tmpjoin(pool, "keep old ", pool_solvable2str(pool, s), 0);
else
return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the old version");
+ case SOLVER_SOLUTION_BLACK:
+ return pool_tmpjoin(pool, "install ", pool_solvid2str(pool, p), 0);
+ case SOLVER_SOLUTION_STRICTREPOPRIORITY:
+ return pool_tmpjoin(pool, "install ", pool_solvid2str(pool, p), " despite the repo priority");
+
+ /* replace types: p -> rp */
+ case SOLVER_SOLUTION_ERASE:
+ return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
+ case SOLVER_SOLUTION_REPLACE:
+ str = pool_tmpjoin(pool, "allow replacement of ", pool_solvid2str(pool, p), 0);
+ return pool_tmpappend(pool, str, " with ", pool_solvid2str(pool, rp));
+ case SOLVER_SOLUTION_REPLACE_DOWNGRADE:
+ return pool_tmpjoin(pool, "allow ", policy_illegal2str(solv, POLICY_ILLEGAL_DOWNGRADE, pool->solvables + p, pool->solvables + rp), 0);
+ case SOLVER_SOLUTION_REPLACE_ARCHCHANGE:
+ return pool_tmpjoin(pool, "allow ", policy_illegal2str(solv, POLICY_ILLEGAL_ARCHCHANGE, pool->solvables + p, pool->solvables + rp), 0);
+ case SOLVER_SOLUTION_REPLACE_VENDORCHANGE:
+ return pool_tmpjoin(pool, "allow ", policy_illegal2str(solv, POLICY_ILLEGAL_VENDORCHANGE, pool->solvables + p, pool->solvables + rp), 0);
+ case SOLVER_SOLUTION_REPLACE_NAMECHANGE:
+ return pool_tmpjoin(pool, "allow ", policy_illegal2str(solv, POLICY_ILLEGAL_NAMECHANGE, pool->solvables + p, pool->solvables + rp), 0);
+ default:
+ break;
}
- else if (p == SOLVER_SOLUTION_BLACK)
- {
- Solvable *s = pool->solvables + rp;
- return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), 0);
- }
- else if (p > 0 && rp == 0)
- return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
- else if (p == SOLVER_SOLUTION_STRICTREPOPRIORITY)
- {
- Solvable *s = pool->solvables + rp;
- return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the repo priority");
- }
- else if (p > 0 && rp > 0)
- {
- const char *sp = pool_solvid2str(pool, p);
- const char *srp = pool_solvid2str(pool, rp);
- const char *str = pool_tmpjoin(pool, "allow replacement of ", sp, 0);
- return pool_tmpappend(pool, str, " with ", srp);
- }
- else
- return "bad solution element";
+ return "bad solution element";
}
+const char *
+solver_solutionelement2str(Solver *solv, Id p, Id rp)
+{
+ if (p > 0)
+ return solver_solutionelementtype2str(solv, rp ? SOLVER_SOLUTION_REPLACE : SOLVER_SOLUTION_ERASE, p, rp);
+ return solver_solutionelementtype2str(solv, p, rp, 0);
+}
diff --git a/src/problems.h b/src/problems.h
index f9b1efc..9e4ad1f 100644
--- a/src/problems.h
+++ b/src/problems.h
@@ -29,6 +29,13 @@ struct s_Solver;
#define SOLVER_SOLUTION_POOLJOB (-4)
#define SOLVER_SOLUTION_BLACK (-5)
#define SOLVER_SOLUTION_STRICTREPOPRIORITY (-6)
+/* replace solution types */
+#define SOLVER_SOLUTION_ERASE (-100)
+#define SOLVER_SOLUTION_REPLACE (-101)
+#define SOLVER_SOLUTION_REPLACE_DOWNGRADE (-102)
+#define SOLVER_SOLUTION_REPLACE_ARCHCHANGE (-103)
+#define SOLVER_SOLUTION_REPLACE_VENDORCHANGE (-104)
+#define SOLVER_SOLUTION_REPLACE_NAMECHANGE (-105)
void solver_recordproblem(struct s_Solver *solv, Id rid);
void solver_fixproblem(struct s_Solver *solv, Id rid);
@@ -45,6 +52,7 @@ unsigned int solver_solutionelement_count(struct s_Solver *solv, Id problem, Id
Id solver_solutionelement_internalid(struct s_Solver *solv, Id problem, Id solution);
Id solver_solutionelement_extrajobflags(struct s_Solver *solv, Id problem, Id solution);
Id solver_next_solutionelement(struct s_Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp);
+void solver_all_solutionelements(struct s_Solver *solv, Id problem, Id solution, int expandreplaces, Queue *q);
void solver_take_solutionelement(struct s_Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job);
void solver_take_solution(struct s_Solver *solv, Id problem, Id solution, Queue *job);
@@ -55,6 +63,7 @@ void solver_findallproblemrules(struct s_Solver *solv, Id problem, Queue *rules)
extern const char *solver_problemruleinfo2str(struct s_Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep);
extern const char *solver_problem2str(struct s_Solver *solv, Id problem);
extern const char *solver_solutionelement2str(struct s_Solver *solv, Id p, Id rp);
+extern const char *solver_solutionelementtype2str(struct s_Solver *solv, int type, Id p, Id rp);
#ifdef __cplusplus
}
diff --git a/src/repo.h b/src/repo.h
index b503431..1f270d7 100644
--- a/src/repo.h
+++ b/src/repo.h
@@ -24,7 +24,7 @@
extern "C" {
#endif
-typedef struct s_Repo {
+struct s_Repo {
const char *name; /* name pointer */
Id repoid; /* our id */
void *appdata; /* application private pointer */
@@ -56,7 +56,7 @@ typedef struct s_Repo {
int lastmarker;
Offset lastmarkerpos;
#endif /* LIBSOLV_INTERNAL */
-} Repo;
+};
extern Repo *repo_create(Pool *pool, const char *name);
extern void repo_free(Repo *repo, int reuseids);
diff --git a/src/repo_write.c b/src/repo_write.c
index a73eebf..c965a76 100644
--- a/src/repo_write.c
+++ b/src/repo_write.c
@@ -266,6 +266,8 @@ struct extdata {
int len;
};
+#define DIRIDCACHE_SIZE 1024
+
struct cbdata {
Pool *pool;
Repo *repo;
@@ -300,6 +302,8 @@ struct cbdata {
Id lastdirid; /* last dir id seen in this repodata */
Id lastdirid_own; /* last dir id put in own pool */
+
+ Id diridcache[3 * DIRIDCACHE_SIZE];
};
#define NEEDID_BLOCK 1023
@@ -564,22 +568,40 @@ putinownpool(struct cbdata *cbdata, Repodata *data, Id id)
static Id
putinowndirpool_slow(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
{
- Id compid, parent;
+ Id compid, parent, id;
+ Id *cacheent;
parent = dirpool_parent(dp, dir);
if (parent)
- parent = putinowndirpool_slow(cbdata, data, dp, parent);
+ {
+ /* put parent in own pool first */
+ cacheent = cbdata->diridcache + (parent & (DIRIDCACHE_SIZE - 1));
+ if (cacheent[0] == parent && cacheent[DIRIDCACHE_SIZE] == data->repodataid)
+ parent = cacheent[2 * DIRIDCACHE_SIZE];
+ else
+ parent = putinowndirpool_slow(cbdata, data, dp, parent);
+ }
compid = dirpool_compid(dp, dir);
if (cbdata->ownspool && compid > 1 && (!cbdata->clonepool || data->localpool))
compid = putinownpool(cbdata, data, compid);
- return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
+ id = dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
+ /* cache result */
+ cacheent = cbdata->diridcache + (dir & (DIRIDCACHE_SIZE - 1));
+ cacheent[0] = dir;
+ cacheent[DIRIDCACHE_SIZE] = data->repodataid;
+ cacheent[2 * DIRIDCACHE_SIZE] = id;
+ return id;
}
static inline Id
putinowndirpool(struct cbdata *cbdata, Repodata *data, Id dir)
{
+ Id *cacheent;
if (dir && dir == cbdata->lastdirid)
return cbdata->lastdirid_own;
+ cacheent = cbdata->diridcache + (dir & (DIRIDCACHE_SIZE - 1));
+ if (dir && cacheent[0] == dir && cacheent[DIRIDCACHE_SIZE] == data->repodataid)
+ return cacheent[2 * DIRIDCACHE_SIZE];
cbdata->lastdirid = dir;
cbdata->lastdirid_own = putinowndirpool_slow(cbdata, data, &data->dirpool, dir);
return cbdata->lastdirid_own;
@@ -1019,6 +1041,7 @@ static Id verticals[] = {
SOLVABLE_LEADSIGID,
SOLVABLE_CHANGELOG_AUTHOR,
SOLVABLE_CHANGELOG_TEXT,
+ SOLVABLE_SIGNATUREDATA,
0
};
diff --git a/src/repodata.h b/src/repodata.h
index 2504f2a..fda463e 100644
--- a/src/repodata.h
+++ b/src/repodata.h
@@ -34,7 +34,6 @@ extern "C" {
#define SIZEOF_SHA384 48
#define SIZEOF_SHA512 64
-struct s_Repo;
struct s_KeyValue;
typedef struct s_Repokey {
@@ -67,13 +66,13 @@ struct dircache;
#define REPODATA_FILELIST_FILTERED 1
#define REPODATA_FILELIST_EXTENSION 2
-typedef struct s_Repodata {
+struct s_Repodata {
Id repodataid; /* our id */
- struct s_Repo *repo; /* back pointer to repo */
+ Repo *repo; /* back pointer to repo */
int state; /* available, stub or error */
- void (*loadcallback)(struct s_Repodata *);
+ void (*loadcallback)(Repodata *);
int start; /* start of solvables this repodata is valid for */
int end; /* last solvable + 1 of this repodata */
@@ -140,7 +139,7 @@ typedef struct s_Repodata {
struct dircache *dircache;
#endif
-} Repodata;
+};
#define SOLVID_META -1
#define SOLVID_POS -2
@@ -149,7 +148,7 @@ typedef struct s_Repodata {
/*-----
* management functions
*/
-void repodata_initdata(Repodata *data, struct s_Repo *repo, int localpool);
+void repodata_initdata(Repodata *data, Repo *repo, int localpool);
void repodata_freedata(Repodata *data);
void repodata_free(Repodata *data);
diff --git a/src/rules.c b/src/rules.c
index 2c56959..7d57cfd 100644
--- a/src/rules.c
+++ b/src/rules.c
@@ -183,7 +183,7 @@ solver_unifyrules(Solver *solv)
binr++;
else
{
- dp = solv->pool->whatprovidesdata + r->d;
+ dp = pool->whatprovidesdata + r->d;
while (*dp++)
lits++;
}
@@ -659,8 +659,12 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w
int oldcount = solv->ruleinfoq->count;
addpkgrule(solv, qele[0], 0, d, type, dep);
/* fixup from element of ruleinfo */
- if (solv->ruleinfoq->count > oldcount)
- solv->ruleinfoq->elements[oldcount + 1] = p;
+ if (solv->ruleinfoq->count > oldcount && solv->ruleinfoq->elements[oldcount + 1] != p)
+ {
+ if (solv->ruleinfoq->elements[oldcount + 2])
+ solv->ruleinfoq->elements[oldcount + 2] = solv->ruleinfoq->elements[oldcount + 1];
+ solv->ruleinfoq->elements[oldcount + 1] = p;
+ }
}
else
addpkgrule(solv, qele[0], 0, d, type, dep);
@@ -1668,6 +1672,16 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
if (first)
continue; /* not the first in the group */
+ if (!bestscore && allowedarchs.count > 1 && pool->implicitobsoleteusescolors)
+ {
+ for (j = 0; j < allowedarchs.count; j++)
+ {
+ a = pool_arch2score(pool, allowedarchs.elements[j]);
+ if (a && a != 1 && (!bestscore || a < bestscore))
+ bestscore = a;
+ }
+ }
+
if (!bestscore)
continue; /* did not find a score for this group */
@@ -1931,8 +1945,8 @@ solver_addtodupmaps(Solver *solv, Id p, Id how, int targeted)
void
solver_createdupmaps(Solver *solv)
{
- Queue *job = &solv->job;
Pool *pool = solv->pool;
+ Queue *job = &solv->job;
Repo *installed = solv->installed;
Id select, how, what, p, pp;
Solvable *s;
@@ -2199,12 +2213,12 @@ reenableblackrule(Solver *solv, Id p)
void
solver_addblackrules(Solver *solv)
{
- int i;
- Id how, select, what, p, pp;
- Queue *job = &solv->job;
Pool *pool = solv->pool;
Repo *installed = solv->installed;
+ Id how, select, what, p, pp;
+ Queue *job = &solv->job;
Map updatemap;
+ int i;
map_init(&updatemap, 0);
solv->blackrules = solv->nrules;
@@ -2353,6 +2367,31 @@ reenablerepopriorule(Solver *solv, Id name)
#define DISABLE_BLACK 4
#define DISABLE_REPOPRIO 5
+/* check if installed package p is in lock-step with another installed package */
+static int
+installed_is_in_lockstep(Solver *solv, Id p)
+{
+ Pool *pool = solv->pool;
+ Repo *installed = solv->installed;
+ int rid;
+ Id pp, l;
+ Rule *r;
+
+ if (!installed)
+ return 0;
+ for (rid = solv->infarchrules, r = solv->rules + rid; rid < solv->infarchrules_end; rid++, r++)
+ {
+ if (r->p >= 0)
+ continue;
+ if (pool->solvables[-r->p].repo != installed)
+ continue;
+ FOR_RULELITERALS(l, pp, r)
+ if (l == p)
+ return 1;
+ }
+ return 0;
+}
+
static void
jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
{
@@ -2485,6 +2524,20 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
return;
/* now the hard part: disable some update rules */
+ /* if the job asks for a single solvable to stay, disable the update rule */
+ if (select == SOLVER_SOLVABLE && pool->solvables[what].repo == installed && solv->bestrules_info)
+ if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
+ {
+ int ni = solv->bestrules_end - solv->bestrules;
+ for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
+ if (solv->bestrules_info[i] == what)
+ {
+ queue_push2(q, DISABLE_UPDATE, what); /* will also disable the best rule */
+ break;
+ }
+ return;
+ }
+
/* first check if we have installed or multiversion packages in the job */
FOR_JOB_SELECT(p, pp, select, what)
{
@@ -2560,6 +2613,20 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
case SOLVER_ERASE:
if (!installed)
break;
+ set = how & SOLVER_SETMASK;
+ if (!(set & (SOLVER_NOAUTOSET | SOLVER_SETARCH)) && pool->implicitobsoleteusescolors && solv->infarchrules != solv->infarchrules_end)
+ {
+ if (select == SOLVER_SOLVABLE)
+ set |= SOLVER_SETARCH;
+ else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
+ {
+ Reldep *rd = GETRELDEP(pool, what);
+ if (rd->flags <= 7 && ISRELDEP(rd->name))
+ rd = GETRELDEP(pool, rd->name);
+ if (rd->flags == REL_ARCH)
+ set |= SOLVER_SETARCH;
+ }
+ }
if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
{
FOR_REPO_SOLVABLES(installed, p, s)
@@ -2569,6 +2636,9 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
if (pool->solvables[p].repo == installed)
{
queue_push2(q, DISABLE_UPDATE, p);
+ if ((set & SOLVER_SETARCH) != 0 && pool->implicitobsoleteusescolors && solv->infarchrules != solv->infarchrules_end)
+ if (installed_is_in_lockstep(solv, p))
+ queue_push2(q, DISABLE_INFARCH, pool->solvables[p].name); /* allow to break the lock-step */
#ifdef ENABLE_LINKED_PKGS
if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1)
queue_push2(q, DISABLE_UPDATE, solv->instbuddy[p - installed->start]);
@@ -3008,7 +3078,7 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
qp = rq.elements[i + 1];
qo = rq.elements[i + 2];
qd = rq.elements[i + 3];
- if (type == SOLVER_RULE_PKG || type > qt)
+ if (type == SOLVER_RULE_PKG || qt == SOLVER_RULE_PKG_SAME_NAME || type > qt)
{
type = qt;
if (fromp)
@@ -3017,6 +3087,8 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
*top = qo;
if (depp)
*depp = qd;
+ if (qt == SOLVER_RULE_PKG_SAME_NAME)
+ break; /* prefer SOLVER_RULE_PKG_SAME_NAME */
}
}
queue_free(&rq);
@@ -3076,8 +3148,12 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
}
if (rid >= solv->bestrules && rid < solv->bestrules_end)
{
+ /* > 0: the package we are updating */
if (fromp && solv->bestrules_info[rid - solv->bestrules] > 0)
*fromp = solv->bestrules_info[rid - solv->bestrules];
+ /* < 0: the job rule */
+ if (top && solv->bestrules_info[rid - solv->bestrules] < 0)
+ *top = -solv->bestrules_info[rid - solv->bestrules];
return SOLVER_RULE_BEST;
}
if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
@@ -3109,9 +3185,17 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
return SOLVER_RULE_STRICT_REPO_PRIORITY;
}
if (rid >= solv->choicerules && rid < solv->choicerules_end)
- return SOLVER_RULE_CHOICE;
+ {
+ if (solv->choicerules_info && fromp)
+ *fromp = solv->choicerules_info[rid - solv->choicerules];
+ return SOLVER_RULE_CHOICE;
+ }
if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
- return SOLVER_RULE_RECOMMENDS;
+ {
+ if (solv->recommendsrules_info && fromp)
+ *fromp = solv->recommendsrules_info[rid - solv->recommendsrules];
+ return SOLVER_RULE_RECOMMENDS;
+ }
if (rid >= solv->learntrules)
return SOLVER_RULE_LEARNT;
return SOLVER_RULE_UNKNOWN;
@@ -3196,10 +3280,10 @@ solver_rule2job(Solver *solv, Id rid, Id *whatp)
Id
solver_rule2solvable(Solver *solv, Id rid)
{
- if (rid >= solv->updaterules && rid < solv->updaterules_end)
- return rid - solv->updaterules;
- if (rid >= solv->featurerules && rid < solv->featurerules_end)
- return rid - solv->featurerules;
+ if (rid >= solv->updaterules && rid < solv->updaterules_end && solv->installed)
+ return solv->installed->start + (rid - solv->updaterules);
+ if (rid >= solv->featurerules && rid < solv->featurerules_end && solv->installed)
+ return solv->installed->start + (rid - solv->featurerules);
return 0;
}
@@ -3365,6 +3449,7 @@ solver_addchoicerules(Solver *solv)
int lastaddedcnt;
unsigned int now;
int isinstalled;
+ int dodowngradecheck = solv->allowdowngrade;
solv->choicerules = solv->nrules;
if (!pool->installed)
@@ -3373,6 +3458,8 @@ solver_addchoicerules(Solver *solv)
return;
}
now = solv_timems(0);
+ if ((solv->dupinvolvedmap_all || solv->dupinvolvedmap.size) && solv->dup_allowdowngrade)
+ dodowngradecheck = 1;
queue_init(&q);
queue_init(&qi);
queue_init(&qcheck);
@@ -3448,8 +3535,16 @@ solver_addchoicerules(Solver *solv)
/* do extra checking for packages related to installed packages */
for (i = j = 0; i < qi.count; i += 2)
{
+ int isdowngrade = 0;
p2 = qi.elements[i];
- if (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p2 - solv->installed->start)))
+ if (dodowngradecheck)
+ {
+ p = qi.elements[i + 1];
+ if (pool->solvables[p2].name == pool->solvables[p].name)
+ if (pool_evrcmp(pool, pool->solvables[p2].evr, pool->solvables[p].evr, EVRCMP_COMPARE) > 0)
+ isdowngrade = 1;
+ }
+ if (isdowngrade || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p2 - solv->installed->start)))
{
if (solver_choicerulecheck(solv, p2, r, &m, &qcheck))
continue;
@@ -3593,6 +3688,7 @@ solver_disablechoicerules(Solver *solv, Rule *r)
if (p)
solver_disablerule(solv, r);
}
+ map_free(&m);
}
static void
@@ -3957,7 +4053,7 @@ find_obsolete_group(Solver *solv, Id obs, Queue *q)
}
/* find names so that we can build groups */
queue_init_clone(&qn, q);
- prune_to_best_version(solv->pool, &qn);
+ prune_to_best_version(pool, &qn);
#if 0
{
for (i = 0; i < qn.count; i++)
@@ -4078,7 +4174,7 @@ for (j = 0; j < qq.count; j++)
if (!qq.count)
continue;
- /* at least two goups, build rules */
+ /* at least two groups, build rules */
group = 0;
for (j = 0; j < qq.count; j++)
{
@@ -4260,3 +4356,122 @@ solver_check_brokenorphanrules(Solver *solv, Queue *dq)
}
}
+const char *
+solver_ruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep)
+{
+ Pool *pool = solv->pool;
+ char *s;
+ Solvable *ss;
+ switch (type)
+ {
+ case SOLVER_RULE_DISTUPGRADE:
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " does not belong to a distupgrade repository", 0);
+ case SOLVER_RULE_INFARCH:
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " has inferior architecture", 0);
+ case SOLVER_RULE_UPDATE:
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " needs to stay installed or be updated", 0);
+ case SOLVER_RULE_FEATURE:
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " needs to stay installed or be updated/downgraded", 0);
+ case SOLVER_RULE_JOB:
+ return pool_tmpjoin(pool, "job ", pool_job2str(pool, target, dep, 0), 0);
+ case SOLVER_RULE_JOB_UNSUPPORTED:
+ return pool_tmpjoin(pool, "unsupported job ", pool_job2str(pool, target, dep, 0), 0);
+ case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
+ return pool_tmpjoin(pool, "nothing provides requested ", pool_dep2str(pool, dep), 0);
+ case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
+ return pool_tmpjoin(pool, "requested package ", pool_dep2str(pool, dep), " does not exist");
+ case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
+ return pool_tmpjoin(pool, "requested ", pool_dep2str(pool, dep), " is provided by the system");
+ case SOLVER_RULE_BEST:
+ if (source > 0)
+ return pool_tmpjoin(pool, "install best update candidate for ", pool_solvid2str(pool, source), 0);
+ if (target > 0)
+ {
+ target = solver_rule2job(solv, target, &dep);
+ return pool_tmpjoin(pool, "best package for job ", pool_job2str(pool, target, dep, 0), 0);
+ }
+ return "best rule";
+ case SOLVER_RULE_PKG:
+ return "bad pkg rule type";
+ case SOLVER_RULE_PKG_NOT_INSTALLABLE:
+ ss = pool->solvables + source;
+ if (pool_disabled_solvable(pool, ss))
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " is disabled", 0);
+ if (ss->arch && ss->arch != ARCH_SRC && ss->arch != ARCH_NOSRC &&
+ pool->id2arch && pool_arch2score(pool, ss->arch) == 0)
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " does not have a compatible architecture", 0);
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " is not installable", 0);
+ case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
+ s = pool_tmpjoin(pool, "nothing provides ", pool_dep2str(pool, dep), 0);
+ return pool_tmpappend(pool, s, " needed by ", pool_solvid2str(pool, source));
+ case SOLVER_RULE_PKG_SAME_NAME:
+ s = pool_tmpjoin(pool, "cannot install both ", pool_solvid2str(pool, source), 0);
+ return pool_tmpappend(pool, s, " and ", pool_solvid2str(pool, target));
+ case SOLVER_RULE_PKG_CONFLICTS:
+ s = pool_tmpappend(pool, pool_solvid2str(pool, source), " conflicts with ", pool_dep2str(pool, dep));
+ if (target)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+ return s;
+ case SOLVER_RULE_PKG_SELF_CONFLICT:
+ s = pool_tmpjoin(pool, pool_solvid2str(pool, source), " conflicts with ", 0);
+ return pool_tmpappend(pool, s, pool_dep2str(pool, dep), " provided by itself");
+ case SOLVER_RULE_PKG_OBSOLETES:
+ s = pool_tmpappend(pool, pool_solvid2str(pool, source), " obsoletes ", pool_dep2str(pool, dep));
+ if (target)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+ return s;
+ case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
+ s = pool_tmpjoin(pool, "installed ", pool_solvid2str(pool, source), 0);
+ s = pool_tmpappend(pool, s, " obsoletes ", pool_dep2str(pool, dep));
+ if (target)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+ return s;
+ case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
+ s = pool_tmpappend(pool, pool_solvid2str(pool, source), " implicitly obsoletes ", pool_dep2str(pool, dep));
+ if (target)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+ return s;
+ case SOLVER_RULE_PKG_REQUIRES:
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " requires ", pool_dep2str(pool, dep));
+ case SOLVER_RULE_PKG_RECOMMENDS:
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " recommends ", pool_dep2str(pool, dep));
+ case SOLVER_RULE_PKG_CONSTRAINS:
+ s = pool_tmpappend(pool, pool_solvid2str(pool, source), " has constraint ", pool_dep2str(pool, dep));
+ return pool_tmpappend(pool, s, " conflicting with ", pool_solvid2str(pool, target));
+ case SOLVER_RULE_PKG_SUPPLEMENTS:
+ s = pool_tmpjoin(pool, pool_solvid2str(pool, source), " supplements ", pool_dep2str(pool, dep));
+ if (target)
+ s = pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+ return s;
+ case SOLVER_RULE_YUMOBS:
+ s = pool_tmpjoin(pool, "both ", pool_solvid2str(pool, source), " and ");
+ s = pool_tmpjoin(pool, s, pool_solvid2str(pool, target), " obsolete ");
+ return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0);
+ case SOLVER_RULE_BLACK:
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " can only be installed by a direct request", 0);
+ case SOLVER_RULE_STRICT_REPO_PRIORITY:
+ return pool_tmpjoin(pool, pool_solvid2str(pool, source), " is excluded by strict repo priority", 0);
+ case SOLVER_RULE_LEARNT:
+ return "learnt rule";
+ case SOLVER_RULE_CHOICE:
+ if (source > 0)
+ {
+ const char *s2;
+ type = solver_ruleinfo(solv, source, &source, &target, &dep);
+ s2 = solver_ruleinfo2str(solv, type, source, target, dep);
+ return pool_tmpjoin(pool, s2, " (limited version)", 0);
+ }
+ return "choice rule";
+ case SOLVER_RULE_RECOMMENDS:
+ if (source > 0)
+ {
+ const char *s2;
+ type = solver_ruleinfo(solv, source, &source, &target, &dep);
+ s2 = solver_ruleinfo2str(solv, type, source, target, dep);
+ return pool_tmpjoin(pool, s2, " (limited version)", 0);
+ }
+ return "recommends rule";
+ default:
+ return "bad rule type";
+ }
+}
diff --git a/src/rules.h b/src/rules.h
index 043d0a0..17af2df 100644
--- a/src/rules.h
+++ b/src/rules.h
@@ -13,10 +13,15 @@
#ifndef LIBSOLV_RULES_H
#define LIBSOLV_RULES_H
+#include "pooltypes.h"
+#include "bitmap.h"
+#include "queue.h"
+
#ifdef __cplusplus
extern "C" {
#endif
+
/* ----------------------------------------------
* Rule
*
@@ -60,6 +65,7 @@ typedef enum {
SOLVER_RULE_PKG_INSTALLED_OBSOLETES,
SOLVER_RULE_PKG_RECOMMENDS,
SOLVER_RULE_PKG_CONSTRAINS,
+ SOLVER_RULE_PKG_SUPPLEMENTS,
SOLVER_RULE_UPDATE = 0x200,
SOLVER_RULE_FEATURE = 0x300,
SOLVER_RULE_JOB = 0x400,
@@ -161,6 +167,11 @@ extern Id solver_rule2job(struct s_Solver *solv, Id rid, Id *whatp);
extern Id solver_rule2solvable(struct s_Solver *solv, Id rid);
extern void solver_rule2rules(struct s_Solver *solv, Id rid, Queue *q, int recursive);
extern Id solver_rule2pkgrule(struct s_Solver *solv, Id rid);
+extern const char *solver_ruleinfo2str(struct s_Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep);
+
+/* rule infos for weakdep decisions */
+extern int solver_allweakdepinfos(struct s_Solver *solv, Id p, Queue *rq);
+extern SolverRuleinfo solver_weakdepinfo(struct s_Solver *solv, Id p, Id *fromp, Id *top, Id *depp);
/* orphan handling */
extern void solver_breakorphans(struct s_Solver *solv);
diff --git a/src/solvable.c b/src/solvable.c
index 181d9bc..657a8b8 100644
--- a/src/solvable.c
+++ b/src/solvable.c
@@ -24,6 +24,7 @@
#include "poolvendor.h"
#include "chksum.h"
#include "linkedpkg.h"
+#include "evr.h"
const char *
pool_solvable2str(Pool *pool, Solvable *s)
@@ -188,16 +189,11 @@ solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
}
#ifdef ENABLE_LINKED_PKGS
/* autopattern/product translation magic */
- if (pass)
+ if (pass == 1 && name == s->name)
{
- const char *n = pool_id2str(pool, name);
- if (*n == 'p')
- {
- if (!strncmp("pattern:", n, 8) && (name = find_autopattern_name(pool, s)) != 0)
- pass = -1;
- if (!strncmp("product:", n, 8) && (name = find_autoproduct_name(pool, s)) != 0)
- pass = -1;
- }
+ name = find_autopackage_name(pool, s);
+ if (name && name != s->name)
+ pass = -1; /* start over with new name */
}
#endif
}
@@ -746,3 +742,124 @@ solvable_matchessolvable(Solvable *s, Id keyname, Id solvid, Queue *depq, int ma
queue_free(&qq);
return res;
}
+
+static int
+solvidset2str_evrcmp(Pool *pool, Id a, Id b)
+{
+ Solvable *as = pool->solvables + a, *bs = pool->solvables + b;
+ return as->evr != bs->evr ? pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE) : 0;
+}
+
+static int
+solvidset2str_sortcmp(const void *va, const void *vb, void *vd)
+{
+ Pool *pool = vd;
+ Solvable *as = pool->solvables + *(Id *)va, *bs = pool->solvables + *(Id *)vb;
+ if (as->name != bs->name)
+ {
+ int r = strcmp(pool_id2str(pool, as->name), pool_id2str(pool, bs->name));
+ if (r)
+ return r;
+ return as->name - bs->name;
+ }
+ if (as->evr != bs->evr)
+ {
+ int r = pool_evrcmp(pool, as->evr, bs->evr, EVRCMP_COMPARE);
+ if (r)
+ return r;
+ }
+ return *(Id *)va - *(Id *)vb;
+}
+
+static const char *
+solvidset2str_striprelease(Pool *pool, Id evr, Id otherevr)
+{
+ const char *evrstr = pool_id2str(pool, evr);
+ const char *r = strchr(evrstr, '-');
+ char *evrstr2;
+ int cmp;
+ if (!r)
+ return evrstr;
+ evrstr2 = pool_tmpjoin(pool, evrstr, 0, 0);
+ evrstr2[r - evrstr] = 0;
+ cmp = pool_evrcmp_str(pool, evrstr2, pool_id2str(pool, otherevr), pool->disttype != DISTTYPE_DEB ? EVRCMP_MATCH_RELEASE : EVRCMP_COMPARE);
+ return cmp == 1 ? evrstr2 : evrstr;
+}
+
+const char *
+pool_solvidset2str(Pool *pool, Queue *q)
+{
+ Queue pq;
+ Queue pr;
+ char *s = 0;
+ int i, j, k, kstart;
+ Id name = 0;
+
+ if (!q->count)
+ return "";
+ if (q->count == 1)
+ return pool_solvid2str(pool, q->elements[0]);
+ queue_init_clone(&pq, q);
+ queue_init(&pr);
+ solv_sort(pq.elements, pq.count, sizeof(Id), solvidset2str_sortcmp, pool);
+
+ for (i = 0; i < pq.count; i++)
+ {
+ Id p = pq.elements[i];
+ if (s)
+ s = pool_tmpappend(pool, s, ", ", 0);
+
+ if (i == 0 || pool->solvables[p].name != name)
+ {
+ Id p2, pp2;
+ name = pool->solvables[p].name;
+ queue_empty(&pr);
+ FOR_PROVIDES(p2, pp2, name)
+ if (pool->solvables[p].name == name)
+ queue_push(&pr, p2);
+ if (pr.count > 1)
+ solv_sort(pr.elements, pr.count, sizeof(Id), solvidset2str_sortcmp, pool);
+ }
+
+ for (k = 0; k < pr.count; k++)
+ if (pr.elements[k] == p)
+ break;
+ if (k == pr.count)
+ {
+ /* not in provides, list as singularity */
+ s = pool_tmpappend(pool, s, pool_solvid2str(pool, pq.elements[i]), 0);
+ continue;
+ }
+ if (k && solvidset2str_evrcmp(pool, pr.elements[k], pr.elements[k - 1]) == 0)
+ {
+ /* unclear start, list as single package */
+ s = pool_tmpappend(pool, s, pool_solvid2str(pool, pq.elements[i]), 0);
+ continue;
+ }
+ kstart = k;
+ for (j = i + 1, k = k + 1; j < pq.count; j++, k++)
+ if (k == pr.count || pq.elements[j] != pr.elements[k])
+ break;
+ while (j > i + 1 && k && k < pr.count && solvidset2str_evrcmp(pool, pr.elements[k], pr.elements[k - 1]) == 0)
+ {
+ j--;
+ k--;
+ }
+ if (k == 0 || j == i + 1)
+ {
+ s = pool_tmpappend(pool, s, pool_solvid2str(pool, pq.elements[i]), 0);
+ continue;
+ }
+ /* create an interval */
+ s = pool_tmpappend(pool, s, pool_id2str(pool, name), 0);
+ if (kstart > 0)
+ s = pool_tmpappend(pool, s, " >= ", solvidset2str_striprelease(pool, pool->solvables[pr.elements[kstart]].evr, pool->solvables[pr.elements[kstart - 1]].evr));
+ if (k < pr.count)
+ s = pool_tmpappend(pool, s, " < ", solvidset2str_striprelease(pool, pool->solvables[pr.elements[k]].evr, pool->solvables[pr.elements[k - 1]].evr));
+ i = j - 1;
+ }
+ queue_free(&pq);
+ queue_free(&pr);
+ return s;
+}
+
diff --git a/src/solver.c b/src/solver.c
index 28341d6..bdce9a9 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -151,11 +151,11 @@ makeruledecisions(Solver *solv, int disablerules)
solv->decisionmap[vv] = v > 0 ? 1 : -1;
IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
{
- Solvable *s = solv->pool->solvables + vv;
+ Solvable *s = pool->solvables + vv;
if (v < 0)
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s));
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(pool, s));
else
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing %s (assertion)\n", pool_solvable2str(solv->pool, s));
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing %s (assertion)\n", pool_solvable2str(pool, s));
}
continue;
}
@@ -311,11 +311,11 @@ makeruledecisions(Solver *solv, int disablerules)
solv->decisionmap[vv] = v > 0 ? 1 : -1;
IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
{
- Solvable *s = solv->pool->solvables + vv;
+ Solvable *s = pool->solvables + vv;
if (v < 0)
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(pool, s));
else
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing %s (weak assertion)\n", pool_solvable2str(pool, s));
}
continue;
}
@@ -986,7 +986,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
FOR_RULELITERALS(v, pp, r)
{
if (DECISIONMAP_TRUE(v)) /* the one true literal */
- continue;
+ abort();
vv = v > 0 ? v : -v;
MAPSET(&involved, vv);
}
@@ -1005,8 +1005,12 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
analyze_unsolvable_rule(solv, r, &weakq, &rseen);
FOR_RULELITERALS(v, pp, r)
{
- if (DECISIONMAP_TRUE(v)) /* the one true literal */
+ if (DECISIONMAP_TRUE(v)) /* the one true literal, i.e. our decision */
+ {
+ if (v != solv->decisionq.elements[idx])
+ abort();
continue;
+ }
vv = v > 0 ? v : -v;
MAPSET(&involved, vv);
}
@@ -1117,10 +1121,77 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul
}
static void
+queue_prunezeros(Queue *q)
+{
+ int i, j;
+ for (i = 0; i < q->count; i++)
+ if (q->elements[i] == 0)
+ break;
+ if (i == q->count)
+ return;
+ for (j = i++; i < q->count; i++)
+ if (q->elements[i])
+ q->elements[j++] = q->elements[i];
+ queue_truncate(q, j);
+}
+
+static int
+replaces_installed_package(Pool *pool, Id p, Map *noupdate)
+{
+ Repo *installed = pool->installed;
+ Solvable *s = pool->solvables + p, *s2;
+ Id p2, pp2;
+ Id obs, *obsp;
+
+ if (s->repo == installed && !(noupdate && MAPTST(noupdate, p - installed->start)))
+ return 1;
+ FOR_PROVIDES(p2, pp2, s->name)
+ {
+ s2 = pool->solvables + p2;
+ if (s2->repo == installed && s2->name == s->name && !(noupdate && MAPTST(noupdate, p - installed->start)))
+ return 1;
+ }
+ if (!s->obsoletes)
+ return 0;
+ obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ {
+ FOR_PROVIDES(p2, pp2, obs)
+ {
+ s2 = pool->solvables + p2;
+ if (s2->repo != pool->installed || (noupdate && MAPTST(noupdate, p - installed->start)))
+ continue;
+ if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs))
+ continue;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+ continue;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+prune_dq_for_future_installed(Solver *solv, Queue *dq)
+{
+ Pool *pool = solv->pool;
+ int i, j;
+ for (i = j = 0; i < dq->count; i++)
+ {
+ Id p = dq->elements[i];
+ if (replaces_installed_package(pool, p, &solv->noupdate))
+ dq->elements[j++] = p;
+ }
+ if (j)
+ queue_truncate(dq, j);
+}
+
+
+static void
reorder_dq_for_future_installed(Solver *solv, int level, Queue *dq)
{
Pool *pool = solv->pool;
- int i, j, haveone = 0, dqcount = dq->count;
+ int i, haveone = 0, dqcount = dq->count;
int decisionqcount = solv->decisionq.count;
Id p;
Solvable *s;
@@ -1161,10 +1232,7 @@ reorder_dq_for_future_installed(Solver *solv, int level, Queue *dq)
dq->elements[i] = 0;
}
}
- for (i = j = 0; i < dq->count; i++)
- if (dq->elements[i])
- dq->elements[j++] = dq->elements[i];
- queue_truncate(dq, j);
+ queue_prunezeros(dq);
FOR_REPO_SOLVABLES(solv->installed, p, s)
if (solv->decisionmap[p] == level + 1)
solv->decisionmap[p] = 0;
@@ -1238,6 +1306,46 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
return setpropagatelearn(solv, level, p, disablerules, why, reason);
}
+static void
+prune_yumobs(Solver *solv, Queue *dq, Id ruleid)
+{
+ Pool *pool = solv->pool;
+ Rule *r;
+ Map m;
+ int i, j, rid;
+
+ map_init(&m, 0);
+ for (i = 0; i < dq->count - 1; i++)
+ {
+ Id p2, pp, p = dq->elements[i];
+ if (!p || !pool->solvables[p].obsoletes)
+ continue;
+ for (rid = solv->yumobsrules, r = solv->rules + rid; rid < solv->yumobsrules_end; rid++, r++)
+ if (r->p == -p)
+ break;
+ if (rid == solv->yumobsrules_end)
+ continue;
+ if (!m.size)
+ map_grow(&m, pool->nsolvables);
+ else
+ MAPZERO(&m);
+ for (; rid < solv->yumobsrules_end; rid++, r++)
+ {
+ if (r->p != -p)
+ continue;
+ FOR_RULELITERALS(p2, pp, r)
+ if (p2 > 0)
+ MAPSET(&m, p2);
+ }
+ for (j = i + 1; j < dq->count; j++)
+ if (MAPTST(&m, dq->elements[j]))
+ dq->elements[j] = 0;
+ }
+ map_free(&m);
+ queue_prunezeros(dq);
+}
+
+
/*-------------------------------------------------------------------
*
* select and install
@@ -1258,9 +1366,16 @@ selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid
if (dq->count > 1)
policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
/* if we're resolving rules and didn't resolve the installed packages yet,
- * do some special supplements ordering */
+ * do some special pruning and supplements ordering */
if (dq->count > 1 && solv->do_extra_reordering)
- reorder_dq_for_future_installed(solv, level, dq);
+ {
+ prune_dq_for_future_installed(solv, dq);
+ if (dq->count > 1)
+ reorder_dq_for_future_installed(solv, level, dq);
+ }
+ /* check if the candidates are all connected via yumobs rules */
+ if (dq->count > 1 && solv->yumobsrules_end > solv->yumobsrules)
+ prune_yumobs(solv, dq, ruleid);
/* if we have multiple candidates we open a branch */
if (dq->count > 1)
createbranch(solv, level, dq, 0, ruleid);
@@ -2921,6 +3036,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
continue;
if (solv->favormap && solv->favormap[p] > solv->favormap[solv->branches.elements[lastsi]])
continue; /* current selection is more favored */
+ if (replaces_installed_package(pool, p, &solv->noupdate))
+ continue; /* current selection replaces an installed package */
if (!(MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
{
lasti = lastsi;
@@ -3533,6 +3650,7 @@ solver_solve(Solver *solv, Queue *job)
map_zerosize(&solv->bestupdatemap);
solv->fixmap_all = 0;
map_zerosize(&solv->fixmap);
+ solv->dupinvolvedmap_all = 0;
map_zerosize(&solv->dupmap);
map_zerosize(&solv->dupinvolvedmap);
solv->process_orphans = 0;
@@ -4580,194 +4698,6 @@ solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
}
-/*-------------------------------------------------------------------
- *
- * decision introspection
- */
-
-int
-solver_get_decisionlevel(Solver *solv, Id p)
-{
- return solv->decisionmap[p];
-}
-
-void
-solver_get_decisionqueue(Solver *solv, Queue *decisionq)
-{
- queue_free(decisionq);
- queue_init_clone(decisionq, &solv->decisionq);
-}
-
-int
-solver_get_lastdecisionblocklevel(Solver *solv)
-{
- Id p;
- if (solv->decisionq.count == 0)
- return 0;
- p = solv->decisionq.elements[solv->decisionq.count - 1];
- if (p < 0)
- p = -p;
- return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
-}
-
-void
-solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
-{
- Id p;
- int i;
-
- queue_empty(decisionq);
- for (i = 0; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p < 0)
- p = -p;
- if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
- break;
- }
- if (i == solv->decisionq.count)
- return;
- for (i = 0; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p < 0)
- p = -p;
- if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
- queue_push(decisionq, p);
- else
- break;
- }
-}
-
-int
-solver_describe_decision(Solver *solv, Id p, Id *infop)
-{
- int i;
- Id pp, why;
-
- if (infop)
- *infop = 0;
- if (!solv->decisionmap[p])
- return SOLVER_REASON_UNRELATED;
- pp = solv->decisionmap[p] < 0 ? -p : p;
- for (i = 0; i < solv->decisionq.count; i++)
- if (solv->decisionq.elements[i] == pp)
- break;
- if (i == solv->decisionq.count) /* just in case... */
- return SOLVER_REASON_UNRELATED;
- why = solv->decisionq_why.elements[i];
- if (infop)
- *infop = why > 0 ? why : -why;
- if (why > 0)
- return SOLVER_REASON_UNIT_RULE;
- i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
- return solv->decisionq_reason.elements[i];
-}
-
-
-void
-solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
-{
- Pool *pool = solv->pool;
- int i;
- int level = solv->decisionmap[p];
- int decisionno;
- Solvable *s;
-
- queue_empty(whyq);
- if (level < 0)
- return; /* huh? */
- for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
- if (solv->decisionq.elements[decisionno] == p)
- break;
- if (decisionno == solv->decisionq.count)
- return; /* huh? */
- i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
- if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP)
- return; /* huh? */
-
- /* 1) list all packages that recommend us */
- for (i = 1; i < pool->nsolvables; i++)
- {
- Id *recp, rec, pp2, p2;
- if (solv->decisionmap[i] <= 0 || solv->decisionmap[i] >= level)
- continue;
- s = pool->solvables + i;
- if (!s->recommends)
- continue;
- if (!solv->addalreadyrecommended && s->repo == solv->installed)
- continue;
- recp = s->repo->idarraydata + s->recommends;
- while ((rec = *recp++) != 0)
- {
- int found = 0;
- FOR_PROVIDES(p2, pp2, rec)
- {
- if (p2 == p)
- found = 1;
- else
- {
- /* if p2 is already installed, this recommends is ignored */
- if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
- break;
- }
- }
- if (!p2 && found)
- {
- queue_push(whyq, SOLVER_REASON_RECOMMENDED);
- queue_push2(whyq, i, rec);
- }
- }
- }
- /* 2) list all supplements */
- s = pool->solvables + p;
- if (s->supplements && level > 0)
- {
- Id *supp, sup, pp2, p2;
- /* this is a hack. to use solver_dep_fulfilled we temporarily clear
- * everything above our level in the decisionmap */
- for (i = decisionno; i < solv->decisionq.count; i++ )
- {
- p2 = solv->decisionq.elements[i];
- if (p2 > 0)
- solv->decisionmap[p2] = -solv->decisionmap[p2];
- }
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (solver_dep_fulfilled(solv, sup))
- {
- int found = 0;
- /* let's see if this is an easy supp */
- FOR_PROVIDES(p2, pp2, sup)
- {
- if (!solv->addalreadyrecommended && solv->installed)
- {
- if (pool->solvables[p2].repo == solv->installed)
- continue;
- }
- if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
- {
- queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
- queue_push2(whyq, p2, sup);
- found = 1;
- }
- }
- if (!found)
- {
- /* hard case, just note dependency with no package */
- queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
- queue_push2(whyq, 0, sup);
- }
- }
- for (i = decisionno; i < solv->decisionq.count; i++)
- {
- p2 = solv->decisionq.elements[i];
- if (p2 > 0)
- solv->decisionmap[p2] = -solv->decisionmap[p2];
- }
- }
-}
-
void
pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
{
@@ -4799,7 +4729,7 @@ pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
int
pool_isemptyupdatejob(Pool *pool, Id how, Id what)
{
- Id p, pp, pi, pip;
+ Id p, pp;
Id select = how & SOLVER_SELECTMASK;
if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
return 0;
@@ -4812,85 +4742,11 @@ pool_isemptyupdatejob(Pool *pool, Id how, Id what)
return 0;
/* hard work */
FOR_JOB_SELECT(p, pp, select, what)
- {
- Solvable *s = pool->solvables + p;
- FOR_PROVIDES(pi, pip, s->name)
- {
- Solvable *si = pool->solvables + pi;
- if (si->repo != pool->installed || si->name != s->name)
- continue;
- return 0;
- }
- if (s->obsoletes)
- {
- Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
- while ((obs = *obsp++) != 0)
- {
- FOR_PROVIDES(pi, pip, obs)
- {
- Solvable *si = pool->solvables + pi;
- if (si->repo != pool->installed)
- continue;
- if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
- continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
- continue;
- return 0;
- }
- }
- }
- }
+ if (replaces_installed_package(pool, p, 0))
+ return 0;
return 1;
}
-int
-solver_alternatives_count(Solver *solv)
-{
- Id *elements = solv->branches.elements;
- int res, count;
- for (res = 0, count = solv->branches.count; count; res++)
- count -= elements[count - 2];
- return res;
-}
-
-int
-solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
-{
- int cnt = solver_alternatives_count(solv);
- int count = solv->branches.count;
- Id *elements = solv->branches.elements;
- if (choices)
- queue_empty(choices);
- if (alternative <= 0 || alternative > cnt)
- return 0;
- elements += count;
- for (; cnt > alternative; cnt--)
- elements -= elements[-2];
- if (levelp)
- *levelp = elements[-1];
- if (fromp)
- *fromp = elements[-4];
- if (idp)
- *idp = elements[-3];
- if (chosenp)
- {
- int i;
- *chosenp = 0;
- for (i = elements[-2]; i > 4; i--)
- {
- Id p = -elements[-i];
- if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
- {
- *chosenp = p;
- break;
- }
- }
- }
- if (choices)
- queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
- return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
-}
-
const char *
solver_select2str(Pool *pool, Id select, Id what)
{
@@ -5042,39 +4898,3 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
return pool_tmpappend(pool, s, "]", 0);
}
-const char *
-solver_alternative2str(Solver *solv, int type, Id id, Id from)
-{
- Pool *pool = solv->pool;
- if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
- {
- const char *s = pool_dep2str(pool, id);
- return pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
- }
- if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
- {
- int rtype;
- Id depfrom, depto, dep;
- char buf[64];
- if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
- id = solver_rule2pkgrule(solv, id);
- if (solver_ruleclass(solv, id) == SOLVER_RULE_RECOMMENDS)
- id = solver_rule2pkgrule(solv, id);
- rtype = solver_ruleinfo(solv, id, &depfrom, &depto, &dep);
- if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
- {
- if ((depto & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES)
- return pool_dep2str(pool, dep);
- return solver_select2str(pool, depto & SOLVER_SELECTMASK, dep);
- }
- if (rtype == SOLVER_RULE_PKG_REQUIRES)
- {
- const char *s = pool_dep2str(pool, dep);
- return pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, depfrom));
- }
- sprintf(buf, "Rule #%d", id);
- return pool_tmpjoin(pool, buf, 0, 0);
- }
- return "unknown alternative type";
-}
-
diff --git a/src/solver.h b/src/solver.h
index 287003c..34c045e 100644
--- a/src/solver.h
+++ b/src/solver.h
@@ -302,8 +302,11 @@ typedef struct s_Solver Solver;
#define SOLVER_REASON_WEAKDEP 7
#define SOLVER_REASON_RESOLVE_ORPHAN 8
-#define SOLVER_REASON_RECOMMENDED 16
-#define SOLVER_REASON_SUPPLEMENTED 17
+#define SOLVER_REASON_RECOMMENDED 16 /* deprecated */
+#define SOLVER_REASON_SUPPLEMENTED 17 /* deprecated */
+
+#define SOLVER_REASON_UNSOLVABLE 18
+#define SOLVER_REASON_PREMISE 19
#define SOLVER_FLAG_ALLOW_DOWNGRADE 1
@@ -343,6 +346,16 @@ typedef struct s_Solver Solver;
#define SOLVER_ALTERNATIVE_TYPE_RECOMMENDS 2
#define SOLVER_ALTERNATIVE_TYPE_SUGGESTS 3
+/* solver_get_decisionlist / solver_get_learnt flags */
+#define SOLVER_DECISIONLIST_SOLVABLE (1 << 1)
+#define SOLVER_DECISIONLIST_PROBLEM (1 << 2)
+#define SOLVER_DECISIONLIST_LEARNTRULE (1 << 3)
+#define SOLVER_DECISIONLIST_WITHINFO (1 << 8)
+#define SOLVER_DECISIONLIST_SORTED (1 << 9)
+#define SOLVER_DECISIONLIST_MERGEDINFO (1 << 10)
+
+#define SOLVER_DECISIONLIST_TYPEMASK (0xff)
+
extern Solver *solver_create(Pool *pool);
extern void solver_free(Solver *solv);
extern int solver_solve(Solver *solv, Queue *job);
@@ -363,10 +376,16 @@ extern void pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int fl
extern void solver_get_cleandeps(Solver *solv, Queue *cleandepsq);
extern int solver_describe_decision(Solver *solv, Id p, Id *infop);
-extern void solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq);
+
+extern void solver_get_decisionlist(Solver *solv, Id p, int flags, Queue *decisionlistq);
+extern void solver_get_decisionlist_multiple(Solver *solv, Queue *pq, int flags, Queue *decisionlistq);
+extern void solver_get_learnt(Solver *solv, Id id, int flags, Queue *q);
+extern void solver_decisionlist_solvables(Solver *solv, Queue *decisionlistq, int pos, Queue *q);
+extern int solver_decisionlist_merged(Solver *solv, Queue *decisionlistq, int pos);
extern int solver_alternatives_count(Solver *solv);
extern int solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp);
+extern int solver_alternativeinfo(Solver *solv, int type, Id id, Id from, Id *fromp, Id *top, Id *depp);
extern void solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap);
extern void solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap); /* obsolete */
@@ -378,11 +397,21 @@ extern int solver_calc_installsizechange(Solver *solv);
extern void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what);
extern int pool_isemptyupdatejob(Pool *pool, Id how, Id what);
+/* decisioninfo merging */
+extern int solver_calc_decisioninfo_bits(Solver *solv, Id decision, int type, Id from, Id to, Id dep);
+extern int solver_merge_decisioninfo_bits(Solver *solv, int state1, int type1, Id from1, Id to1, Id dep1, int state2, int type2, Id from2, Id to2, Id dep2);
+
extern const char *solver_select2str(Pool *pool, Id select, Id what);
extern const char *pool_job2str(Pool *pool, Id how, Id what, Id flagmask);
extern const char *solver_alternative2str(Solver *solv, int type, Id id, Id from);
+extern const char *solver_reason2str(Solver *solv, int reason);
+extern const char *solver_decisionreason2str(Solver *solv, Id decision, int reason, Id info);
+extern const char *solver_decisioninfo2str(Solver *solv, int bits, int type, Id from, Id to, Id dep);
+/* deprecated, use solver_allweakdepinfos/solver_weakdepinfo instead */
+extern void solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq);
+
/* iterate over all literals of a rule */
#define FOR_RULELITERALS(l, pp, r) \
for (pp = r->d < 0 ? -r->d - 1 : r->d, \
diff --git a/src/solverdebug.c b/src/solverdebug.c
index 5902cdb..1c53d4e 100644
--- a/src/solverdebug.c
+++ b/src/solverdebug.c
@@ -505,43 +505,17 @@ solver_printcompleteprobleminfo(Solver *solv, Id problem)
queue_free(&q);
}
-static int illegals[] = {
- POLICY_ILLEGAL_DOWNGRADE,
- POLICY_ILLEGAL_NAMECHANGE,
- POLICY_ILLEGAL_ARCHCHANGE,
- POLICY_ILLEGAL_VENDORCHANGE,
- 0
-};
-
void
solver_printsolution(Solver *solv, Id problem, Id solution)
{
Pool *pool = solv->pool;
- Id p, rp, element;
-
- element = 0;
- while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
- {
- if (p > 0 && rp > 0)
- {
- /* for replacements we want to know why it was illegal */
- Solvable *s = pool->solvables + p, *rs = pool->solvables + rp;
- int illegal = policy_is_illegal(solv, s, rs, 0);
- if (illegal)
- {
- int i;
- for (i = 0; illegals[i]; i++)
- if ((illegal & illegals[i]) != 0)
- {
- POOL_DEBUG(SOLV_DEBUG_RESULT, " - allow %s\n", policy_illegal2str(solv, illegals[i], s, rs));
- illegal ^= illegals[i];
- }
- if (!illegal)
- continue;
- }
- }
- POOL_DEBUG(SOLV_DEBUG_RESULT, " - %s\n", solver_solutionelement2str(solv, p, rp));
- }
+ Queue q;
+ int i;
+ queue_init(&q);
+ solver_all_solutionelements(solv, problem, solution, 1, &q);
+ for (i = 0; i < q.count; i += 3)
+ POOL_DEBUG(SOLV_DEBUG_RESULT, " - %s\n", solver_solutionelementtype2str(solv, q.elements[i], q.elements[i + 1], q.elements[i + 2]));
+ queue_free(&q);
}
void
diff --git a/src/transaction.h b/src/transaction.h
index 001412d..8b8fe6d 100644
--- a/src/transaction.h
+++ b/src/transaction.h
@@ -21,12 +21,11 @@
extern "C" {
#endif
-struct s_Pool;
struct s_DUChanges;
struct s_TransactionOrderdata;
typedef struct s_Transaction {
- struct s_Pool *pool; /* back pointer to pool */
+ Pool *pool; /* back pointer to pool */
Queue steps; /* the transaction steps */
@@ -93,8 +92,8 @@ typedef struct s_Transaction {
#define SOLVER_ORDERCYCLE_NORMAL 1
#define SOLVER_ORDERCYCLE_CRITICAL 2
-extern Transaction *transaction_create(struct s_Pool *pool);
-extern Transaction *transaction_create_decisionq(struct s_Pool *pool, Queue *decisionq, Map *multiversionmap);
+extern Transaction *transaction_create(Pool *pool);
+extern Transaction *transaction_create_decisionq(Pool *pool, Queue *decisionq, Map *multiversionmap);
extern Transaction *transaction_create_clone(Transaction *srctrans);
extern void transaction_free(Transaction *trans);