summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/bitmap.c50
-rw-r--r--src/bitmap.h7
-rw-r--r--src/libsolv.ver6
-rw-r--r--src/pool.c60
-rw-r--r--src/pool.h2
-rw-r--r--src/problems.c235
-rw-r--r--src/problems.h7
-rw-r--r--src/repo.h9
-rw-r--r--src/rules.c92
-rw-r--r--src/selection.c1478
-rw-r--r--src/selection.h38
-rw-r--r--src/solver.c699
-rw-r--r--src/solver.h1
-rw-r--r--src/userinstalled.c367
15 files changed, 1947 insertions, 1107 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 35516ba..e8951f6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -19,7 +19,8 @@ SET (libsolv_SRCS
queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
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)
+ fileprovides.c diskusage.c suse.c solver_util.c cleandeps.c
+ userinstalled.c)
SET (libsolv_HEADERS
bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
diff --git a/src/bitmap.c b/src/bitmap.c
index 1bf1666..e004bf2 100644
--- a/src/bitmap.c
+++ b/src/bitmap.c
@@ -63,38 +63,48 @@ map_grow(Map *m, int n)
void
map_and(Map *t, Map *s)
{
- unsigned char *ti, *si, *end;
- ti = t->map;
- si = s->map;
- end = ti + (t->size < s->size ? t->size : s->size);
- while (ti < end)
- *ti++ &= *si++;
+ unsigned char *ti, *si, *end;
+ ti = t->map;
+ si = s->map;
+ end = ti + (t->size < s->size ? t->size : s->size);
+ while (ti < end)
+ *ti++ &= *si++;
}
/* bitwise-ors maps t and s, stores the result in t. */
void
map_or(Map *t, Map *s)
{
- unsigned char *ti, *si, *end;
- if (t->size < s->size)
- map_grow(t, s->size << 3);
- ti = t->map;
- si = s->map;
- end = ti + (t->size < s->size ? t->size : s->size);
- while (ti < end)
- *ti++ |= *si++;
+ unsigned char *ti, *si, *end;
+ if (t->size < s->size)
+ map_grow(t, s->size << 3);
+ ti = t->map;
+ si = s->map;
+ end = ti + (t->size < s->size ? t->size : s->size);
+ while (ti < end)
+ *ti++ |= *si++;
}
/* remove all set bits in s from t. */
void
map_subtract(Map *t, Map *s)
{
- unsigned char *ti, *si, *end;
- ti = t->map;
- si = s->map;
- end = ti + (t->size < s->size ? t->size : s->size);
- while (ti < end)
- *ti++ &= ~*si++;
+ unsigned char *ti, *si, *end;
+ ti = t->map;
+ si = s->map;
+ end = ti + (t->size < s->size ? t->size : s->size);
+ while (ti < end)
+ *ti++ &= ~*si++;
+}
+
+void
+map_invertall(Map *m)
+{
+ unsigned char *ti, *end;
+ ti = m->map;
+ end = ti + m->size;
+ while (ti < end)
+ *ti++ ^= 0xff;
}
/* EOF */
diff --git a/src/bitmap.h b/src/bitmap.h
index 5784e6c..0050a6a 100644
--- a/src/bitmap.h
+++ b/src/bitmap.h
@@ -33,6 +33,8 @@ typedef struct _Map {
#define MAPCLR(m, n) ((m)->map[(n) >> 3] &= ~(1 << ((n) & 7)))
/* test bit */
#define MAPTST(m, n) ((m)->map[(n) >> 3] & (1 << ((n) & 7)))
+/* clear some bits at a position */
+#define MAPCLR_AT(m, n) ((m)->map[(n) >> 3] = 0)
extern void map_init(Map *m, int n);
extern void map_init_clone(Map *t, Map *s);
@@ -41,6 +43,7 @@ extern void map_free(Map *m);
extern void map_and(Map *t, Map *s);
extern void map_or(Map *t, Map *s);
extern void map_subtract(Map *t, Map *s);
+extern void map_invertall(Map *m);
static inline void map_empty(Map *m)
{
@@ -62,6 +65,10 @@ static inline int map_tst(Map *m, int n)
{
return MAPTST(m, n);
}
+static inline void map_clr_at(Map *m, int n)
+{
+ MAPCLR_AT(m, n);
+}
#ifdef __cplusplus
}
diff --git a/src/libsolv.ver b/src/libsolv.ver
index 337cd19..64191d4 100644
--- a/src/libsolv.ver
+++ b/src/libsolv.ver
@@ -427,3 +427,9 @@ SOLV_1.1 {
pool_best_solvables;
solver_get_cleandeps;
} SOLV_1.0;
+
+SOLV_1.2 {
+ map_invertall;
+ pool_set_whatprovides;
+ selection_subtract;
+} SOLV_1.1;
diff --git a/src/pool.c b/src/pool.c
index b596ace..ba5e799 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -859,7 +859,7 @@ pool_match_dep(Pool *pool, Id d1, Id d2)
if (!ISRELDEP(d1))
{
if (!ISRELDEP(d2))
- return 0;
+ return 0; /* cannot match as d1 != d2 */
rd2 = GETRELDEP(pool, d2);
return pool_match_dep(pool, d1, rd2->name);
}
@@ -1410,7 +1410,8 @@ pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr)
continue;
if (evr && rd->evr != evr)
continue;
- pool->whatprovides_rel[d] = 0;
+ if (pool->whatprovides_rel[d])
+ pool_set_whatprovides(pool, MAKERELDEP(d), 0);
}
}
@@ -1516,6 +1517,9 @@ pool_error(Pool *pool, int ret, const char *format, ...)
{
va_list args;
int l;
+
+ if (!pool)
+ return ret;
va_start(args, format);
if (!pool->errstr)
{
@@ -1862,24 +1866,66 @@ pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp)
return loc;
}
+void
+pool_set_whatprovides(Pool *pool, Id id, Id providers)
+{
+ int d, nrels = pool->nrels;
+ Reldep *rd;
+ Map m;
+
+ /* set new entry */
+ if (ISRELDEP(id))
+ {
+ d = GETRELID(id);
+ pool->whatprovides_rel[d] = providers;
+ d++;
+ }
+ else
+ {
+ pool->whatprovides[id] = providers;
+ if (id < pool->whatprovidesauxoff)
+ pool->whatprovidesaux[id] = 0; /* sorry */
+ d = 1;
+ }
+ if (!pool->whatprovides_rel)
+ return;
+ /* clear cache of all rels that use it */
+ map_init(&m, 0);
+ for (rd = pool->rels + d; d < nrels; d++, rd++)
+ {
+ if (rd->name == id || rd->evr == id ||
+ (m.size && ISRELDEP(rd->name) && MAPTST(&m, GETRELID(rd->name))) ||
+ (m.size && ISRELDEP(rd->evr) && MAPTST(&m, GETRELID(rd->evr))))
+ {
+ pool->whatprovides_rel[d] = 0; /* clear cache */
+ if (!m.size)
+ map_init(&m, nrels);
+ MAPSET(&m, d);
+ }
+ }
+ map_free(&m);
+}
+
static void
add_new_provider(Pool *pool, Id id, Id p)
{
Queue q;
Id *pp;
+ /* find whatprovides entry */
while (ISRELDEP(id))
{
Reldep *rd = GETRELDEP(pool, id);
id = rd->name;
}
+ /* add new provider to existing list keeping it sorted */
queue_init(&q);
for (pp = pool->whatprovidesdata + pool->whatprovides[id]; *pp; pp++)
{
if (*pp == p)
{
- queue_free(&q);
+ queue_free(&q); /* already have it */
return;
}
if (*pp > p)
@@ -1891,9 +1937,7 @@ add_new_provider(Pool *pool, Id id, Id p)
}
if (p)
queue_push(&q, p);
- pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
- if (id < pool->whatprovidesauxoff)
- pool->whatprovidesaux[id] = 0; /* sorry */
+ pool_set_whatprovides(pool, id, pool_queuetowhatprovides(pool, &q));
queue_free(&q);
}
@@ -1920,9 +1964,7 @@ pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts)
continue;
s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
if (pool->whatprovides)
- add_new_provider(pool, fn, p);
- if (pool->whatprovides_rel)
- pool->whatprovides_rel[GETRELID(id)] = 0; /* clear cache */
+ add_new_provider(pool, id, p);
s = pool->solvables + q;
if (!s->repo)
continue;
diff --git a/src/pool.h b/src/pool.h
index f6a5493..f6573af 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -344,6 +344,8 @@ static inline Id *pool_whatprovides_ptr(Pool *pool, Id d)
void pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
void pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
+void pool_set_whatprovides(Pool *pool, Id id, Id providers);
+
/* search the pool. the following filters are available:
* p - search just this solvable
diff --git a/src/problems.c b/src/problems.c
index 2ffb6f9..7933f7c 100644
--- a/src/problems.c
+++ b/src/problems.c
@@ -24,7 +24,6 @@
#include "evr.h"
#include "solverdebug.h"
-
/**********************************************************************************/
/* a problem is an item on the solver's problem list. It can either be >0, in that
@@ -32,10 +31,9 @@
* consisting of multiple job rules.
*/
-void
+static void
solver_disableproblem(Solver *solv, Id v)
{
- Rule *r;
int i;
Id *jp;
@@ -62,30 +60,30 @@ solver_disableproblem(Solver *solv, Id v)
return;
}
solver_disablerule(solv, solv->rules + v);
-#if 0
- /* XXX: doesn't work */
- if (v >= solv->updaterules && v < solv->updaterules_end)
- {
- /* enable feature rule if we disabled the update rule */
- r = solv->rules + (v - solv->updaterules + solv->featurerules);
- if (r->p)
- solver_enablerule(solv, r);
- }
-#endif
return;
}
v = -(v + 1);
jp = solv->ruletojob.elements;
- for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
+ if (solv->bestrules_pkg)
+ {
+ int ni = solv->bestrules_up - solv->bestrules;
+ for (i = 0; i < ni; i++)
+ {
+ int j = solv->bestrules_pkg[i];
+ if (j < 0 && jp[-j - solv->jobrules] == v)
+ solver_disablerule(solv, solv->rules + solv->bestrules + i);
+ }
+ }
+ for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
if (*jp == v)
- solver_disablerule(solv, r);
+ solver_disablerule(solv, solv->rules + i);
}
/*-------------------------------------------------------------------
* enableproblem
*/
-void
+static void
solver_enableproblem(Solver *solv, Id v)
{
Rule *r;
@@ -133,9 +131,174 @@ solver_enableproblem(Solver *solv, Id v)
}
v = -(v + 1);
jp = solv->ruletojob.elements;
- for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
+ if (solv->bestrules_pkg)
+ {
+ int ni = solv->bestrules_up - solv->bestrules;
+ for (i = 0; i < ni; i++)
+ {
+ int j = solv->bestrules_pkg[i];
+ if (j < 0 && jp[-j - solv->jobrules] == v)
+ solver_enablerule(solv, solv->rules + solv->bestrules + i);
+ }
+ }
+ for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
if (*jp == v)
- solver_enablerule(solv, r);
+ solver_enablerule(solv, solv->rules + i);
+}
+
+
+/*-------------------------------------------------------------------
+ * turn a problem rule into a problem id by normalizing it
+ */
+static Id
+solver_ruletoproblem(Solver *solv, Id rid)
+{
+ if (rid >= solv->jobrules && rid < solv->jobrules_end)
+ rid = -(solv->ruletojob.elements[rid - solv->jobrules] + 1);
+ else if (rid >= solv->bestrules && rid < solv->bestrules_up && solv->bestrules_pkg[rid - solv->bestrules] < 0)
+ rid = -(solv->ruletojob.elements[-solv->bestrules_pkg[rid - solv->bestrules] - solv->jobrules] + 1);
+ else if (rid > solv->infarchrules && rid < solv->infarchrules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[rid].p].name;
+ while (rid > solv->infarchrules && pool->solvables[-solv->rules[rid - 1].p].name == name)
+ rid--;
+ }
+ else if (rid > solv->duprules && rid < solv->duprules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[rid].p].name;
+ while (rid > solv->duprules && pool->solvables[-solv->rules[rid - 1].p].name == name)
+ rid--;
+ }
+ return rid;
+}
+
+/*-------------------------------------------------------------------
+ * when the solver runs into a problem, it needs to disable all
+ * involved non-pkg rules and record the rules for solution
+ * generation.
+ */
+void
+solver_recordproblem(Solver *solv, Id rid)
+{
+ Id v = solver_ruletoproblem(solv, rid);
+ /* return if problem already countains our rule */
+ if (solv->problems.count)
+ {
+ int i;
+ for (i = solv->problems.count - 1; i >= 0; i--)
+ if (solv->problems.elements[i] == 0) /* end of last problem reached? */
+ break;
+ else if (solv->problems.elements[i] == v)
+ return;
+ }
+ queue_push(&solv->problems, v);
+}
+
+/*-------------------------------------------------------------------
+ * this is called when a problem is solved by disabling a rule.
+ * It calls disableproblem and then re-enables policy rules
+ */
+void
+solver_fixproblem(Solver *solv, Id rid)
+{
+ Id v = solver_ruletoproblem(solv, rid);
+ solver_disableproblem(solv, v);
+ if (v < 0)
+ solver_reenablepolicyrules(solv, -v);
+}
+
+/*-------------------------------------------------------------------
+ * disable a set of problems
+ */
+void
+solver_disableproblemset(Solver *solv, int start)
+{
+ int i;
+ for (i = start + 1; i < solv->problems.count - 1; i++)
+ solver_disableproblem(solv, solv->problems.elements[i]);
+}
+
+/*-------------------------------------------------------------------
+ * try to fix a problem by auto-uninstalling packages
+ */
+Id
+solver_autouninstall(Solver *solv, int start)
+{
+ Pool *pool = solv->pool;
+ int i;
+ int lastfeature = 0, lastupdate = 0;
+ Id v;
+ Id extraflags = -1;
+ Map *m = 0;
+
+ if (!solv->allowuninstall && !solv->allowuninstall_all)
+ {
+ if (!solv->allowuninstallmap.size)
+ return 0; /* why did we get called? */
+ m = &solv->allowuninstallmap;
+ }
+ for (i = start + 1; i < solv->problems.count - 1; i++)
+ {
+ v = solv->problems.elements[i];
+ if (v < 0)
+ extraflags &= solv->job.elements[-v - 1];
+ if (v >= solv->updaterules && v < solv->updaterules_end)
+ {
+ Rule *r;
+ if (m && !MAPTST(m, v - solv->updaterules))
+ continue;
+ /* check if identical to feature rule, we don't like that (except for orphans) */
+ r = solv->rules + solv->featurerules + (v - solv->updaterules);
+ if (!r->p)
+ {
+ /* update rule == feature rule */
+ if (v > lastfeature)
+ lastfeature = v;
+ /* prefer orphaned packages in dup mode */
+ if (solv->keep_orphans)
+ {
+ r = solv->rules + v;
+ if (!r->d && !r->w2 && r->p == (solv->installed->start + (v - solv->updaterules)))
+ {
+ lastfeature = v;
+ lastupdate = 0;
+ break;
+ }
+ }
+ continue;
+ }
+ if (v > lastupdate)
+ lastupdate = v;
+ }
+ }
+ if (!lastupdate && !lastfeature)
+ return 0;
+ v = lastupdate ? lastupdate : lastfeature;
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
+ /* should really be solver_fixproblem, but we know v is an update/feature rule */
+ solver_disableproblem(solv, v);
+ if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
+ {
+ /* add the package to the updatepkgs list, this will automatically turn
+ * on cleandeps mode */
+ Id p = solv->rules[v].p;
+ if (!solv->cleandeps_updatepkgs)
+ {
+ solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
+ queue_init(solv->cleandeps_updatepkgs);
+ }
+ if (p > 0)
+ {
+ int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
+ queue_pushunique(solv->cleandeps_updatepkgs, p);
+ if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
+ solver_disablepolicyrules(solv);
+ }
+ }
+ return v;
}
@@ -202,7 +365,6 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
queue_empty(refined);
if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0)
return;
- queue_init(&disabled);
queue_push(refined, sug);
/* re-enable all problem rules with the exception of "sug"(gestion) */
@@ -211,10 +373,14 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
for (i = 0; problem[i]; i++)
if (problem[i] != sug)
solver_enableproblem(solv, problem[i]);
-
if (sug < 0)
solver_reenablepolicyrules(solv, -sug);
- else if (sug >= solv->updaterules && sug < solv->updaterules_end)
+
+ /* here is where the feature rules come into play: if we disabled an
+ * update rule, we enable the corresponding feature rule if there is
+ * one. We do this to make the solver downgrade packages instead of
+ * deinstalling them */
+ if (sug >= solv->updaterules && sug < solv->updaterules_end)
{
/* enable feature rule */
Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
@@ -224,11 +390,15 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
enableweakrules(solv);
+ /* disabled contains all of the rules we disabled in the refinement process */
+ queue_init(&disabled);
for (;;)
{
- int njob, nfeature, nupdate, pass;
+ int nother, nfeature, nupdate, pass;
queue_empty(&solv->problems);
solver_reset(solv);
+ /* we set disablerules to zero because we are only interested in
+ * the first problem and we don't want the solver to disable the problems */
solver_run_sat(solv, 0, 0);
if (!solv->problems.count)
@@ -237,16 +407,18 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
break; /* great, no more problems */
}
disabledcnt = disabled.count;
- /* start with 1 to skip over proof index */
- njob = nfeature = nupdate = 0;
+ nother = nfeature = nupdate = 0;
for (pass = 0; pass < 2; pass++)
{
+ /* start with 1 to skip over proof index */
for (i = 1; i < solv->problems.count - 1; i++)
{
/* ignore solutions in refined */
v = solv->problems.elements[i];
if (v == 0)
break; /* end of problem reached */
+ if (!essentialok && v < 0 && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
+ continue; /* not that one! */
if (sug != v)
{
/* check if v is in the given problems list
@@ -260,14 +432,10 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
}
if (v >= solv->featurerules && v < solv->featurerules_end)
nfeature++;
- else if (v > 0)
+ else if (v > solv->updaterules && v < solv->updaterules_end)
nupdate++;
else
- {
- if (!essentialok && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
- continue; /* not that one! */
- njob++;
- }
+ nother++;
queue_push(&disabled, v);
}
if (disabled.count != disabledcnt)
@@ -280,7 +448,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
refined->count = 0;
break;
}
- if (!njob && nupdate && nfeature)
+ if (!nother && nupdate && nfeature)
{
/* got only update rules, filter out feature rules */
POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "throwing away feature rules\n");
@@ -300,14 +468,14 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
if (!nfeature && v != sug)
queue_push(refined, v); /* do not record feature rules */
solver_disableproblem(solv, v);
+ if (v < 0)
+ solver_reenablepolicyrules(solv, -v);
if (v >= solv->updaterules && v < solv->updaterules_end)
{
Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
if (r->p)
solver_enablerule(solv, r); /* enable corresponding feature rule */
}
- if (v < 0)
- solver_reenablepolicyrules(solv, -v);
}
else
{
@@ -339,6 +507,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti
for (i = 0; i < disabled.count; i++)
solver_enableproblem(solv, disabled.elements[i]);
queue_free(&disabled);
+
/* reset policy rules */
for (i = 0; problem[i]; i++)
solver_enableproblem(solv, problem[i]);
diff --git a/src/problems.h b/src/problems.h
index e5b2279..63319d6 100644
--- a/src/problems.h
+++ b/src/problems.h
@@ -28,8 +28,11 @@ struct _Solver;
#define SOLVER_SOLUTION_BEST (-3)
#define SOLVER_SOLUTION_POOLJOB (-4)
-void solver_disableproblem(struct _Solver *solv, Id v);
-void solver_enableproblem(struct _Solver *solv, Id v);
+void solver_recordproblem(struct _Solver *solv, Id rid);
+void solver_fixproblem(struct _Solver *solv, Id rid);
+Id solver_autouninstall(struct _Solver *solv, int start);
+void solver_disableproblemset(struct _Solver *solv, int start);
+
int solver_prepare_solutions(struct _Solver *solv);
unsigned int solver_problem_count(struct _Solver *solv);
diff --git a/src/repo.h b/src/repo.h
index a63999a..9dcbcca 100644
--- a/src/repo.h
+++ b/src/repo.h
@@ -98,6 +98,15 @@ static inline int pool_disabled_solvable(const Pool *pool, Solvable *s)
return 0;
}
+static inline int pool_badarch_solvable(const Pool *pool, Solvable *s)
+{
+ if (!s->arch)
+ return 1;
+ if (pool->id2arch && (s->arch > pool->lastarch || !pool->id2arch[s->arch]))
+ return 1;
+ return 0;
+}
+
static inline int pool_installable(const Pool *pool, Solvable *s)
{
if (!s->arch || s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
diff --git a/src/rules.c b/src/rules.c
index b5f3e3e..cf368e4 100644
--- a/src/rules.c
+++ b/src/rules.c
@@ -1466,7 +1466,7 @@ disableupdaterule(Solver *solv, Id p)
{
int i, ni;
ni = solv->bestrules_end - solv->bestrules;
- for (i = 0; i < ni; i++)
+ for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
if (solv->bestrules_pkg[i] == p)
solver_disablerule(solv, solv->rules + solv->bestrules + i);
}
@@ -1509,7 +1509,7 @@ reenableupdaterule(Solver *solv, Id p)
{
int i, ni;
ni = solv->bestrules_end - solv->bestrules;
- for (i = 0; i < ni; i++)
+ for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
if (solv->bestrules_pkg[i] == p)
solver_enablerule(solv, solv->rules + solv->bestrules + i);
}
@@ -1922,6 +1922,21 @@ solver_createdupmaps(Solver *solv)
}
if (solv->dupinvolvedmap.size)
MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
+ /* set update for all involved installed packages. We need to do
+ * this before creating the update rules */
+ if (solv->dupinvolvedmap_all)
+ solv->updatemap_all = 1;
+ else if (installed && !solv->updatemap_all && solv->dupinvolvedmap.size)
+ {
+ FOR_REPO_SOLVABLES(installed, p, s)
+ {
+ if (!MAPTST(&solv->dupinvolvedmap, p))
+ continue;
+ if (!solv->updatemap.size)
+ map_grow(&solv->updatemap, installed->end - installed->start);
+ MAPSET(&solv->updatemap, p - installed->start);
+ }
+ }
}
void
@@ -1943,8 +1958,6 @@ solver_addduprules(Solver *solv, Map *addedmap)
Rule *r;
solv->duprules = solv->nrules;
- if (solv->dupinvolvedmap_all)
- solv->updatemap_all = 1;
for (i = 1; i < pool->nsolvables; i++)
{
if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
@@ -1964,12 +1977,6 @@ solver_addduprules(Solver *solv, Map *addedmap)
continue;
if (installed && ps->repo == installed)
{
- if (!solv->updatemap_all)
- {
- if (!solv->updatemap.size)
- map_grow(&solv->updatemap, installed->end - installed->start);
- MAPSET(&solv->updatemap, p - installed->start);
- }
if (!MAPTST(&solv->dupmap, p))
{
Id ip, ipp;
@@ -3257,36 +3264,47 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
{
for (i = 0; i < solv->job.count; i += 2)
{
- if ((solv->job.elements[i] & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
+ Id how = solv->job.elements[i];
+ if ((how & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
{
int j;
Id p2, pp2;
for (j = 0; j < solv->ruletojob.count; j++)
- if (solv->ruletojob.elements[j] == i)
- break;
- if (j == solv->ruletojob.count)
- continue;
- r = solv->rules + solv->jobrules + j;
- queue_empty(&q);
- FOR_RULELITERALS(p2, pp2, r)
- if (p2 > 0)
- queue_push(&q, p2);
- if (!q.count)
- continue; /* orphaned */
- /* select best packages, just look at prio and version */
- oldcnt = q.count;
- policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
- if (q.count == oldcnt)
- continue; /* nothing filtered */
- p2 = queue_shift(&q);
- if (q.count < 2)
- solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
- else
- solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
- queue_push(&r2pkg, -(solv->jobrules + j));
+ {
+ if (solv->ruletojob.elements[j] != i)
+ continue;
+ r = solv->rules + solv->jobrules + j;
+ queue_empty(&q);
+ queue_empty(&q2);
+ FOR_RULELITERALS(p2, pp2, r)
+ {
+ if (p2 > 0)
+ queue_push(&q, p2);
+ else if (p2 < 0)
+ queue_push(&q2, p2);
+ }
+ if (!q.count)
+ continue; /* orphaned */
+ /* select best packages, just look at prio and version */
+ oldcnt = q.count;
+ policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
+ if (q.count == oldcnt)
+ continue; /* nothing filtered */
+ if (q2.count)
+ queue_insertn(&q, 0, q2.count, q2.elements);
+ p2 = queue_shift(&q);
+ if (q.count < 2)
+ solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
+ else
+ solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
+ if ((how & SOLVER_WEAK) != 0)
+ queue_push(&solv->weakruleq, solv->nrules - 1);
+ queue_push(&r2pkg, -(solv->jobrules + j));
+ }
}
}
}
+ solv->bestrules_up = solv->nrules;
if (installed && (solv->bestupdatemap_all || solv->bestupdatemap.size))
{
@@ -3398,6 +3416,8 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
/* yumobs rule handling */
+/* note that we use pool->obsoleteusescolors || pool->implicitobsoleteusescolors
+ * like in policy_findupdatepackages */
static void
find_obsolete_group(Solver *solv, Id obs, Queue *q)
@@ -3422,7 +3442,7 @@ find_obsolete_group(Solver *solv, Id obs, Queue *q)
Id obs2, *obsp2;
if (!os->obsoletes)
continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os))
+ if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
continue;
obsp2 = os->repo->idarraydata + os->obsoletes;
while ((obs2 = *obsp2++) != 0)
@@ -3440,7 +3460,7 @@ find_obsolete_group(Solver *solv, Id obs, Queue *q)
continue;
if (!os->obsoletes)
continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os))
+ if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
continue;
obsp2 = os->repo->idarraydata + os->obsoletes;
while ((obs2 = *obsp2++) != 0)
@@ -3539,7 +3559,7 @@ printf("checking yumobs for %s\n", pool_solvable2str(pool, s));
continue;
if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+ if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, s2))
continue;
queue_pushunique(&qo, obs);
break;
diff --git a/src/selection.c b/src/selection.c
index 16fe3a7..6ca72e5 100644
--- a/src/selection.c
+++ b/src/selection.c
@@ -37,6 +37,7 @@ str2archid(Pool *pool, const char *arch)
return id;
}
+/* remove empty jobs from the selection */
static void
selection_prune(Pool *pool, Queue *selection)
{
@@ -155,33 +156,49 @@ selection_flatten(Pool *pool, Queue *selection)
}
}
+/* only supports simple rels plus REL_ARCH */
+static int
+match_nevr_rel(Pool *pool, Solvable *s, Id rflags, Id revr)
+{
+ if (rflags == REL_ARCH)
+ {
+ if (s->arch != revr)
+ {
+ if (revr != ARCH_SRC || s->arch != ARCH_NOSRC)
+ return 0;
+ }
+ return 1;
+ }
+ if (rflags > 7)
+ return 0;
+ return pool_intersect_evrs(pool, REL_EQ, s->evr, rflags, revr);
+}
+
+/* only supports simple rels plus REL_ARCH */
static void
-selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
+selection_filter_rel_noprune(Pool *pool, Queue *selection, Id relflags, Id relevr)
{
int i;
+ if (!selection->count)
+ return;
+
for (i = 0; i < selection->count; i += 2)
{
Id select = selection->elements[i] & SOLVER_SELECTMASK;
Id id = selection->elements[i + 1];
if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF)
{
- /* done by selection_addsrc, currently implies SELECTION_NAME */
+ /* done by selection_addextra, currently implies SELECTION_NAME */
Queue q;
Id p, pp;
- Id rel = 0, relname = 0;
int miss = 0;
queue_init(&q);
FOR_JOB_SELECT(p, pp, select, id)
{
Solvable *s = pool->solvables + p;
- if (!rel || s->name != relname)
- {
- relname = s->name;
- rel = pool_rel2id(pool, relname, relevr, relflags, 1);
- }
- if (pool_match_nevr(pool, s, rel))
+ if (match_nevr_rel(pool, s, relflags, relevr))
queue_push(&q, p);
else
miss = 1;
@@ -213,31 +230,48 @@ selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1);
}
else
- continue; /* actually internal error */
+ continue; /* actually cannot happen */
+
+ /* now add the setflags we gained */
if (relflags == REL_ARCH)
- selection->elements[i] |= SOLVER_SETARCH;
+ selection->elements[i] |= SOLVER_SETARCH;
if (relflags == REL_EQ && select != SOLVER_SOLVABLE_PROVIDES)
- {
+ {
if (pool->disttype == DISTTYPE_DEB)
- selection->elements[i] |= SOLVER_SETEVR; /* debian can't match version only like rpm */
+ selection->elements[i] |= SOLVER_SETEVR; /* debian can't match version only like rpm */
else
{
const char *rel = strrchr(pool_id2str(pool, relevr), '-');
selection->elements[i] |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
}
- }
+ }
}
+}
+
+/* only supports simple rels plus REL_ARCH */
+/* prunes empty jobs */
+static void
+selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
+{
+ selection_filter_rel_noprune(pool, selection, relflags, relevr);
selection_prune(pool, selection);
}
+/* limit a selection to to repository */
+/* prunes empty jobs */
static void
-selection_filter_installed(Pool *pool, Queue *selection)
+selection_filter_repo(Pool *pool, Queue *selection, Repo *repo)
{
Queue q;
int i, j;
- if (!pool->installed)
- queue_empty(selection);
+ if (!selection->count)
+ return;
+ if (!repo)
+ {
+ queue_empty(selection);
+ return;
+ }
queue_init(&q);
for (i = j = 0; i < selection->count; i += 2)
{
@@ -246,11 +280,11 @@ selection_filter_installed(Pool *pool, Queue *selection)
if (select == SOLVER_SOLVABLE_ALL)
{
select = SOLVER_SOLVABLE_REPO;
- id = pool->installed->repoid;
+ id = repo->repoid;
}
else if (select == SOLVER_SOLVABLE_REPO)
{
- if (id != pool->installed->repoid)
+ if (id != repo->repoid)
select = 0;
}
else
@@ -260,7 +294,7 @@ selection_filter_installed(Pool *pool, Queue *selection)
queue_empty(&q);
FOR_JOB_SELECT(p, pp, select, id)
{
- if (pool->solvables[p].repo != pool->installed)
+ if (pool->solvables[p].repo != repo)
bad = 1;
else
queue_push(&q, p);
@@ -268,7 +302,7 @@ selection_filter_installed(Pool *pool, Queue *selection)
if (bad || !q.count)
{
if (!q.count)
- select = 0;
+ select = 0; /* prune empty jobs */
else if (q.count == 1)
{
select = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
@@ -281,58 +315,138 @@ selection_filter_installed(Pool *pool, Queue *selection)
}
}
}
- if (select)
+ if (!select)
+ continue; /* job is now empty */
+ if (select == SOLVER_SOLVABLE_REPO)
{
- selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SETREPO;
- selection->elements[j++] = id;
+ Id p;
+ Solvable *s;
+ FOR_REPO_SOLVABLES(repo, p, s)
+ break;
+ if (!p)
+ continue; /* repo is empty */
}
+ selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SETREPO;
+ selection->elements[j++] = id;
}
queue_truncate(selection, j);
queue_free(&q);
}
+
+static int
+matchprovides(Pool *pool, Solvable *s, Id dep)
+{
+ Id id, *idp;
+ idp = s->repo->idarraydata + s->provides;
+ while ((id = *idp++) != 0)
+ if (pool_match_dep(pool, id, dep))
+ return 1;
+ return 0;
+}
+
+/* change a SOLVER_SOLVABLE_NAME/PROVIDES selection to something that also includes
+ * extra packages.
+ * extra packages are: src, badarch, disabled
+ */
static void
-selection_addsrc(Pool *pool, Queue *selection, int flags)
+selection_addextra(Pool *pool, Queue *selection, int flags)
{
Queue q;
- Id p, name;
- int i, havesrc;
+ Id p, pp, dep;
+ int i, isextra, haveextra, doprovides;
if ((flags & SELECTION_INSTALLED_ONLY) != 0)
- return; /* sources can't be installed */
+ flags &= ~SELECTION_WITH_SOURCE;
+
+ if (!(flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH)))
+ return; /* nothing to add */
+
queue_init(&q);
for (i = 0; i < selection->count; i += 2)
{
- if (selection->elements[i] != SOLVER_SOLVABLE_NAME)
+ if (selection->elements[i] == SOLVER_SOLVABLE_NAME)
+ doprovides = 0;
+ else if (selection->elements[i] == SOLVER_SOLVABLE_PROVIDES)
+ doprovides = 1;
+ else
continue;
- name = selection->elements[i + 1];
- havesrc = 0;
+ dep = selection->elements[i + 1];
+ haveextra = 0;
queue_empty(&q);
+ if (doprovides)
+ {
+ /* first put all non-extra packages on the queue */
+ FOR_PROVIDES(p, pp, dep)
+ {
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && pool->solvables[p].repo != pool->installed)
+ continue;
+ queue_push(&q, p);
+ }
+ }
FOR_POOL_SOLVABLES(p)
{
Solvable *s = pool->solvables + p;
- if (s->name != name)
+ if (!doprovides && !pool_match_nevr(pool, s, dep))
continue;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ isextra = 0;
if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
{
+ if (!(flags & SELECTION_WITH_SOURCE) && !(flags & SELECTION_SOURCE_ONLY))
+ continue;
+ if (!(flags & SELECTION_SOURCE_ONLY))
+ isextra = 1;
if (pool_disabled_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ isextra = 1;
+ }
+ }
+ else
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ continue;
+ if (s->repo != pool->installed)
+ {
+ if (pool_disabled_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ isextra = 1;
+ }
+ if (pool_badarch_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_BADARCH))
+ continue;
+ isextra = 1;
+ }
+ }
+ }
+ if (doprovides)
+ {
+ if (!isextra)
+ continue; /* already done above in FOR_PROVIDES */
+ if (!s->provides || !matchprovides(pool, s, dep))
continue;
- havesrc = 1;
}
- else if (s->repo != pool->installed && !pool_installable(pool, s))
- continue;
+ haveextra |= isextra;
queue_push(&q, p);
}
- if (!havesrc || !q.count)
+ if (!haveextra || !q.count)
continue;
if (q.count == 1)
{
- selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+ selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
selection->elements[i + 1] = q.elements[0];
}
else
{
- selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
+ if (doprovides)
+ solv_sort(q.elements, q.count, sizeof(Id), selection_solvables_sortcmp, NULL);
+ selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
}
}
@@ -360,173 +474,332 @@ queue_pushunique2(Queue *q, Id id1, Id id2)
queue_push2(q, id1, id2);
}
+
+/***** provides matching *****/
+
static int
-selection_depglob_id(Pool *pool, Queue *selection, Id id, int flags)
+selection_addextra_provides(Pool *pool, Queue *selection, const char *name, int flags)
{
- Id p, pp;
+ Id p, id, *idp;
int match = 0;
+ int doglob, nocase, globflags;
- FOR_PROVIDES(p, pp, id)
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+ return 0; /* neither disabled nor badarch nor src */
+
+ nocase = flags & SELECTION_NOCASE;
+ doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
+ globflags = doglob && nocase ? FNM_CASEFOLD : 0;
+
+ FOR_POOL_SOLVABLES(p)
{
+ const char *n;
Solvable *s = pool->solvables + p;
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ if (!s->provides)
+ continue;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) /* no provides */
+ continue;
+ if (s->repo == pool->installed)
continue;
- match = 1;
- if (s->name == id && (flags & SELECTION_NAME) != 0)
+ if (pool_disabled_solvable(pool, s))
{
- if ((flags & SELECTION_SOURCE_ONLY) != 0)
- id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
- queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
- if ((flags & SELECTION_WITH_SOURCE) != 0)
- selection_addsrc(pool, selection, flags);
- return SELECTION_NAME;
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+ continue;
}
- }
- if ((flags & (SELECTION_SOURCE_ONLY | SELECTION_WITH_SOURCE)) != 0 && (flags & SELECTION_NAME) != 0)
- {
- /* src rpms don't have provides, so we must check every solvable */
- FOR_POOL_SOLVABLES(p) /* slow path */
+ else if (pool_badarch_solvable(pool, s))
{
- Solvable *s = pool->solvables + p;
- if (s->name == id && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
+ if (!(flags & SELECTION_WITH_BADARCH))
+ continue;
+ }
+ else
+ continue;
+ /* here is an extra solvable we need to consider */
+ idp = s->repo->idarraydata + s->provides;
+ while ((id = *idp++) != 0)
+ {
+ while (ISRELDEP(id))
{
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
- continue; /* just in case... src rpms can't be installed */
- if (pool_disabled_solvable(pool, s))
- continue;
- if ((flags & SELECTION_SOURCE_ONLY) != 0)
- id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
- queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
- if ((flags & SELECTION_WITH_SOURCE) != 0)
- selection_addsrc(pool, selection, flags);
- return SELECTION_NAME;
+ Reldep *rd = GETRELDEP(pool, id);
+ id = rd->name;
+ }
+ if (pool->whatprovides[id] > 1)
+ continue; /* we already did that one in the normal code path */
+ n = pool_id2str(pool, id);
+ if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
+ {
+ queue_pushunique2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+ match = 1;
}
}
}
- if (match && (flags & SELECTION_PROVIDES) != 0)
+ return match;
+}
+
+/* this is the fast path of selection_provides: the id for the name
+ * is known and thus we can quickly check the existance of a
+ * package with that provides */
+static int
+selection_provides_id(Pool *pool, Queue *selection, Id id, int flags)
+{
+ Id p, pp;
+
+ FOR_PROVIDES(p, pp, id)
+ {
+ Solvable *s = pool->solvables + p;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ break;
+ }
+ if (p)
{
queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
return SELECTION_PROVIDES;
}
+
+ if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+ {
+ queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+ selection_addextra(pool, selection, flags);
+ if (selection->elements[0] == SOLVER_SOLVABLE_PROVIDES)
+ queue_empty(selection);
+ else
+ {
+ selection->elements[0] = SOLVER_SOLVABLE_PROVIDES;
+ selection->elements[1] = id;
+ }
+ return selection->count ? SELECTION_PROVIDES : 0;
+ }
+
return 0;
}
+/* add missing provides matchers to the selection */
+/* match the provides of a package */
+/* note that we only return raw SOLVER_SOLVABLE_PROVIDES jobs
+ * so that the selection can be modified later. */
static int
-selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
+selection_provides(Pool *pool, Queue *selection, const char *name, int flags)
{
Id id, p, pp;
- int match = 0;
- int doglob = 0;
- int nocase = 0;
- int globflags = 0;
+ int match;
+ int doglob;
+ int nocase;
+ int globflags;
+ const char *n;
if ((flags & SELECTION_SOURCE_ONLY) != 0)
- {
- flags &= ~SELECTION_PROVIDES; /* sources don't provide anything */
- flags &= ~SELECTION_WITH_SOURCE;
- }
-
- if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
- return 0;
-
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
- return 0;
+ return 0; /* sources do not have provides */
nocase = flags & SELECTION_NOCASE;
- if (!nocase && !(flags & SELECTION_SKIP_KIND))
+ if (!nocase)
{
+ /* try the fast path first */
id = pool_str2id(pool, name, 0);
if (id)
{
- /* the id is know, do the fast id matching using the whatprovides lookup */
- int ret = selection_depglob_id(pool, selection, id, flags);
+ /* the id is known, do the fast id matching */
+ int ret = selection_provides_id(pool, selection, id, flags);
if (ret)
return ret;
}
}
- if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
- doglob = 1;
-
- if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob)
- return 0; /* all done above in depglob_id */
-
- if (doglob && nocase)
- globflags = FNM_CASEFOLD;
+ doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
+ if (!nocase && !doglob)
+ {
+ /* all done above in selection_provides_id */
+ return 0;
+ }
- if ((flags & SELECTION_NAME) != 0)
+ /* looks like a glob or nocase match. really hard work. */
+ match = 0;
+ globflags = doglob && nocase ? FNM_CASEFOLD : 0;
+ for (id = 1; id < pool->ss.nstrings; id++)
{
- /* looks like a name glob. hard work. */
- FOR_POOL_SOLVABLES(p)
+ /* do we habe packages providing this id? */
+ if (!pool->whatprovides[id] || pool->whatprovides[id] == 1)
+ continue;
+ n = pool_id2str(pool, id);
+ if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
{
- Solvable *s = pool->solvables + p;
- const char *n;
- if (s->repo != pool->installed && !pool_installable(pool, s))
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0)
{
- if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
- continue;
- if (pool_disabled_solvable(pool, s))
+ FOR_PROVIDES(p, pp, id)
+ if (pool->solvables[p].repo == pool->installed)
+ break;
+ if (!p)
continue;
}
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+ match = 1;
+ }
+ }
+
+ if (flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED))
+ match |= selection_addextra_provides(pool, selection, name, flags);
+
+ return match ? SELECTION_PROVIDES : 0;
+}
+
+/***** name matching *****/
+
+/* this is the fast path of selection_name: the id for the name
+ * is known and thus we can quickly check the existance of a
+ * package with that name */
+static int
+selection_name_id(Pool *pool, Queue *selection, Id id, int flags)
+{
+ Id p, pp, matchid;
+
+ matchid = id;
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ {
+ /* sources cannot be installed */
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+ return 0;
+ /* add ARCH_SRC to match only sources */
+ matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
+ flags &= ~SELECTION_WITH_SOURCE;
+ }
+
+ FOR_PROVIDES(p, pp, matchid)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->name != id)
+ continue;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ /* one match is all we need */
+ queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
+ /* add the requested extra packages */
+ if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+ selection_addextra(pool, selection, flags);
+ return SELECTION_NAME;
+ }
+
+ if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+ {
+ queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
+ selection_addextra(pool, selection, flags);
+ if (selection->elements[0] == SOLVER_SOLVABLE_NAME)
+ queue_empty(selection);
+ return selection->count ? SELECTION_NAME : 0;
+ }
+
+ if ((flags & SELECTION_WITH_SOURCE) != 0 && (flags & SELECTION_INSTALLED_ONLY) == 0)
+ {
+ /* WITH_SOURCE case, but we had no match. try SOURCE_ONLY instead */
+ matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
+ FOR_PROVIDES(p, pp, matchid)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->name != id)
continue;
- id = s->name;
- n = pool_id2str(pool, id);
- if (flags & SELECTION_SKIP_KIND)
- n = skipkind(n);
- if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
- {
- if ((flags & SELECTION_SOURCE_ONLY) != 0)
- id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
- queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id);
- match = 1;
- }
+ queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
+ return SELECTION_NAME;
}
- if (match)
+ }
+ return 0;
+}
+
+/* match the name of a package */
+/* note that for SELECTION_INSTALLED_ONLY the result is not trimmed */
+static int
+selection_name(Pool *pool, Queue *selection, const char *name, int flags)
+{
+ Id id, p;
+ int match;
+ int doglob, nocase;
+ int globflags;
+ const char *n;
+
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ flags &= ~SELECTION_WITH_SOURCE;
+
+ nocase = flags & SELECTION_NOCASE;
+ if (!nocase && !(flags & SELECTION_SKIP_KIND))
+ {
+ /* try the fast path first */
+ id = pool_str2id(pool, name, 0);
+ if (id)
{
- if ((flags & SELECTION_WITH_SOURCE) != 0)
- selection_addsrc(pool, selection, flags);
- return SELECTION_NAME;
+ int ret = selection_name_id(pool, selection, id, flags);
+ if (ret)
+ return ret;
}
}
- if ((flags & SELECTION_PROVIDES))
+ doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
+ if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob)
+ return 0; /* all done above in selection_name_id */
+
+ /* do a name match over all packages. hard work. */
+ match = 0;
+ globflags = doglob && nocase ? FNM_CASEFOLD : 0;
+ FOR_POOL_SOLVABLES(p)
{
- /* looks like a dep glob. really hard work. */
- for (id = 1; id < pool->ss.nstrings; id++)
+ Solvable *s = pool->solvables + p;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
{
- const char *n;
- if (!pool->whatprovides[id] || pool->whatprovides[id] == 1)
+ if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
continue;
- n = pool_id2str(pool, id);
- if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ }
+ else if (s->repo != pool->installed)
+ {
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+ continue;
+ }
+ id = s->name;
+ n = pool_id2str(pool, id);
+ if (flags & SELECTION_SKIP_KIND)
+ n = skipkind(n);
+ if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
{
- if ((flags & SELECTION_INSTALLED_ONLY) != 0)
- {
- FOR_PROVIDES(p, pp, id)
- if (pool->solvables[p].repo == pool->installed)
- break;
- if (!p)
- continue;
- }
- queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
- match = 1;
+ if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+ continue;
+ id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
}
+ queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id);
+ match = 1;
}
- if (match)
- return SELECTION_PROVIDES;
+ }
+ if (match)
+ {
+ /* if there was a match widen the selector to include all extra packages */
+ if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+ selection_addextra(pool, selection, flags);
+ return SELECTION_NAME;
}
return 0;
}
+
+/***** SELECTION_DOTARCH and SELECTION_REL handling *****/
+
+/* like selection_name, but check for a .arch suffix if the match did
+ not work and SELECTION_DOTARCH is used */
static int
-selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
+selection_name_arch(Pool *pool, Queue *selection, const char *name, int flags, int doprovides, int noprune)
{
int ret;
const char *r;
Id archid;
- if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
+ if (doprovides)
+ ret = selection_provides(pool, selection, name, flags);
+ else
+ ret = selection_name(pool, selection, name, flags);
+ if (ret)
return ret;
if (!(flags & SELECTION_DOTARCH))
return 0;
@@ -537,65 +810,22 @@ selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags
rname[r - name] = 0;
if (archid == ARCH_SRC || archid == ARCH_NOSRC)
flags |= SELECTION_SOURCE_ONLY;
- if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
+ if (doprovides)
+ ret = selection_provides(pool, selection, rname, flags);
+ else
+ ret = selection_name(pool, selection, rname, flags);
+ if (ret)
{
- selection_filter_rel(pool, selection, REL_ARCH, archid);
- solv_free(rname);
- return ret | SELECTION_DOTARCH;
+ selection_filter_rel_noprune(pool, selection, REL_ARCH, archid);
+ if (!noprune)
+ selection_prune(pool, selection);
}
solv_free(rname);
+ return ret && selection->count ? ret | SELECTION_DOTARCH : 0;
}
return 0;
}
-static int
-selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
-{
- Dataiterator di;
- Queue q;
- int type;
-
- /* all files in the file list start with a '/' */
- if (*name != '/')
- {
- if (!(flags & SELECTION_GLOB))
- return 0;
- if (*name != '*' && *name != '[' && *name != '?')
- return 0;
- }
- type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
- if ((flags & SELECTION_NOCASE) != 0)
- type |= SEARCH_NOCASE;
- queue_init(&q);
- dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
- while (dataiterator_step(&di))
- {
- Solvable *s = pool->solvables + di.solvid;
- if (!s->repo)
- continue;
- if (s->repo != pool->installed && !pool_installable(pool, s))
- {
- if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
- continue;
- if (pool_disabled_solvable(pool, s))
- continue;
- }
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
- continue;
- queue_push(&q, di.solvid);
- dataiterator_skip_solvable(&di);
- }
- dataiterator_free(&di);
- if (!q.count)
- return 0;
- if (q.count > 1)
- queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
- else
- queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
- queue_free(&q);
- return SELECTION_FILELIST;
-}
-
static char *
splitrel(char *rname, char *r, int *rflagsp)
{
@@ -622,43 +852,178 @@ splitrel(char *rname, char *r, int *rflagsp)
r++;
while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t'))
nend--;
- if (!*rname || !*r)
+ if (nend <= 0 || !*r || !rflags)
return 0;
*rflagsp = rflags;
rname[nend] = 0;
return r;
}
+/* match name/provides, support DOTARCH and REL modifiers
+ */
static int
-selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
+selection_name_arch_rel(Pool *pool, Queue *selection, const char *name, int flags, int doprovides)
{
- int ret, rflags = 0;
- char *r, *rname;
+ int ret, rflags = 0, noprune;
+ char *r = 0, *rname = 0;
- /* relation case, support:
- * depglob rel
- * depglob.arch rel
- */
- rname = solv_strdup(name);
- if ((r = strpbrk(rname, "<=>")) != 0)
+ /* try to split off an relation part */
+ if ((flags & SELECTION_REL) != 0)
{
- if ((r = splitrel(rname, r, &rflags)) == 0)
+ if ((r = strpbrk(name, "<=>")) != 0)
{
- solv_free(rname);
- return 0;
+ rname = solv_strdup(name);
+ r = rname + (r - name);
+ if ((r = splitrel(rname, r, &rflags)) == 0)
+ rname = solv_free(rname);
}
}
- if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
+
+ /* check if we need to call selection_addextra */
+ noprune = doprovides && (flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH));
+
+ if (!r)
{
- if (rflags)
- selection_filter_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
- solv_free(rname);
- return ret | SELECTION_REL;
+ /* could not split off relation */
+ ret = selection_name_arch(pool, selection, name, flags, doprovides, noprune);
+ if (ret && noprune)
+ {
+ selection_addextra(pool, selection, flags);
+ selection_prune(pool, selection);
+ }
+ return ret && selection->count ? ret : 0;
+ }
+
+ /* we could split of a relation. prune name and then filter rel */
+ ret = selection_name_arch(pool, selection, rname, flags, doprovides, noprune);
+ if (ret)
+ {
+ selection_filter_rel_noprune(pool, selection, rflags, pool_str2id(pool, r, 1));
+ if (noprune)
+ selection_addextra(pool, selection, flags);
+ selection_prune(pool, selection);
}
solv_free(rname);
- return 0;
+ return ret && selection->count ? ret | SELECTION_REL : 0;
+}
+
+/***** filelist matching *****/
+
+static int
+selection_filelist_sortcmp(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = dp;
+ const Id *a = ap, *b = bp;
+ if (a[0] != b[0])
+ return strcmp(pool_id2str(pool, a[0]), pool_id2str(pool, b[0]));
+ return a[1] - b[1];
+}
+
+static int
+selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
+{
+ Dataiterator di;
+ Queue q;
+ Id id;
+ int type;
+ int i, j, lastid;
+
+ /* all files in the file list start with a '/' */
+ if (*name != '/')
+ {
+ if (!(flags & SELECTION_GLOB))
+ return 0;
+ if (*name != '*' && *name != '[' && *name != '?')
+ return 0;
+ }
+ type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
+ if ((flags & SELECTION_NOCASE) != 0)
+ type |= SEARCH_NOCASE;
+ queue_init(&q);
+ dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
+ while (dataiterator_step(&di))
+ {
+ Solvable *s = pool->solvables + di.solvid;
+ if (!s->repo)
+ continue;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+ {
+ if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
+ continue;
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ }
+ else
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ continue;
+ if (s->repo != pool->installed)
+ {
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+ continue;
+ }
+ }
+ if ((flags & SELECTION_FLAT) != 0)
+ {
+ /* don't bother with the complex stuff */
+ queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, di.solvid);
+ dataiterator_skip_solvable(&di);
+ continue;
+ }
+ id = pool_str2id(pool, di.kv.str, 1);
+ queue_push2(&q, id, di.solvid);
+ }
+ dataiterator_free(&di);
+ if ((flags & SELECTION_FLAT) != 0)
+ {
+ queue_free(&q);
+ return selection->count ? SELECTION_FILELIST : 0;
+ }
+ if (!q.count)
+ {
+ queue_free(&q);
+ return 0;
+ }
+ solv_sort(q.elements, q.count / 2, 2 * sizeof(Id), selection_filelist_sortcmp, pool);
+ lastid = 0;
+ queue_push2(&q, 0, 0);
+ for (i = j = 0; i < q.count; i += 2)
+ {
+ if (q.elements[i] != lastid)
+ {
+ if (j == 1)
+ queue_pushunique2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
+ else if (j > 1)
+ {
+ int k;
+ Id *idp;
+ /* check if we already have it */
+ for (k = 0; k < selection->count; k += 2)
+ {
+ if (selection->elements[k] != SOLVER_SOLVABLE_ONE_OF)
+ continue;
+ idp = pool->whatprovidesdata + selection->elements[k + 1];
+ if (!memcmp(idp, q.elements, j * sizeof(Id)) && !idp[j])
+ break;
+ }
+ if (k == selection->count)
+ queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_ids2whatprovides(pool, q.elements, j));
+ }
+ lastid = q.elements[i];
+ j = 0;
+ }
+ if (!j || q.elements[j - 1] != q.elements[i])
+ q.elements[j++] = q.elements[i + 1];
+ }
+ queue_free(&q);
+ return SELECTION_FILELIST;
}
+
+/***** canon name matching *****/
+
#if defined(MULTI_SEMANTICS)
# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
#elif defined(DEBIAN)
@@ -669,11 +1034,22 @@ selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
/* magic epoch promotion code, works only for SELECTION_NAME selections */
static void
-selection_filter_evr(Pool *pool, Queue *selection, char *evr)
+selection_filter_evr(Pool *pool, Queue *selection, const char *evr)
{
int i, j;
Queue q;
Id qbuf[10];
+ const char *sp;
+
+ /* do we already have an epoch? */
+ for (sp = evr; *sp >= '0' && *sp <= '9'; sp++)
+ ;
+ if (*sp == ':' && sp != evr)
+ {
+ /* yes, just add the rel filter */
+ selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, evr, 1));
+ return;
+ }
queue_init(&q);
queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
@@ -690,7 +1066,6 @@ selection_filter_evr(Pool *pool, Queue *selection, char *evr)
{
Solvable *s = pool->solvables + p;
const char *sevr = pool_id2str(pool, s->evr);
- const char *sp;
for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
;
if (*sp != ':')
@@ -772,7 +1147,7 @@ selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
rname = solv_strdup(name); /* so we can modify it */
r = rname + (r - name);
*r++ = 0;
- if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+ if ((ret = selection_name(pool, selection, rname, flags)) == 0)
{
solv_free(rname);
return 0;
@@ -785,7 +1160,7 @@ selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
}
selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
solv_free(rname);
- return ret | SELECTION_CANON;
+ return selection->count ? ret | SELECTION_CANON : 0;
}
if (pool->disttype == DISTTYPE_HAIKU)
@@ -795,7 +1170,7 @@ selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
rname = solv_strdup(name); /* so we can modify it */
r = rname + (r - name);
*r++ = 0;
- if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+ if ((ret = selection_name(pool, selection, rname, flags)) == 0)
{
solv_free(rname);
return 0;
@@ -808,7 +1183,7 @@ selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
}
selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
solv_free(rname);
- return ret | SELECTION_CANON;
+ return selection->count ? ret | SELECTION_CANON : 0;
}
if ((r = strrchr(name, '-')) == 0)
@@ -824,7 +1199,7 @@ selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
flags |= SELECTION_SOURCE_ONLY;
/* try with just the version */
- if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+ if ((ret = selection_name(pool, selection, rname, flags)) == 0)
{
/* no luck, try with version-release */
if ((r2 = strrchr(rname, '-')) == 0)
@@ -835,7 +1210,7 @@ selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
*r = '-';
*r2 = 0;
r = r2;
- if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+ if ((ret = selection_name(pool, selection, rname, flags)) == 0)
{
solv_free(rname);
return 0;
@@ -845,33 +1220,167 @@ selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
selection_filter_rel(pool, selection, REL_ARCH, archid);
selection_filter_evr(pool, selection, r + 1); /* magic epoch promotion */
solv_free(rname);
- return ret | SELECTION_CANON;
+ return selection->count ? ret | SELECTION_CANON : 0;
+}
+
+/* return the needed withbits to match the provided selection */
+static int
+selection_extrabits(Pool *pool, Queue *selection, int flags)
+{
+ int i, needflags, isextra;
+ int allflags;
+ Id p;
+ Solvable *s;
+ Queue qlimit;
+
+ allflags = flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH);
+ if (!selection->count)
+ return allflags;
+ if (selection->count == 2 && selection->elements[0] == SOLVER_SOLVABLE_ALL)
+ return allflags; /* don't bother */
+ queue_init(&qlimit);
+ selection_solvables(pool, selection, &qlimit);
+ needflags = 0;
+ for (i = 0; i < qlimit.count; i++)
+ {
+ p = qlimit.elements[i];
+ s = pool->solvables + p;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ isextra = 0;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+ {
+ if (!(flags & SELECTION_WITH_SOURCE))
+ continue;
+ isextra |= SELECTION_WITH_SOURCE;
+ if (pool_disabled_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ isextra |= SELECTION_WITH_DISABLED;
+ }
+ }
+ else
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ continue;
+ if (s->repo != pool->installed)
+ {
+ if (pool_disabled_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ isextra |= SELECTION_WITH_DISABLED;
+ }
+ if (pool_badarch_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_BADARCH))
+ continue;
+ isextra |= SELECTION_WITH_BADARCH;
+ }
+ }
+ }
+ if (isextra)
+ {
+ needflags |= isextra;
+ if (needflags == allflags)
+ break;
+ }
+ }
+ queue_free(&qlimit);
+ return needflags;
}
int
selection_make(Pool *pool, Queue *selection, const char *name, int flags)
{
int ret = 0;
+ if ((flags & SELECTION_MODEBITS) != 0)
+ {
+ Queue q;
+ queue_init(&q);
+ if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT || (flags & SELECTION_MODEBITS) == SELECTION_FILTER)
+ {
+ if (!selection->count)
+ {
+ queue_free(&q);
+ return 0;
+ }
+ if ((flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) != 0)
+ {
+ /* try to drop expensive extra bits */
+ flags = (flags & ~(SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) | selection_extrabits(pool, selection, flags);
+ }
+ }
+ ret = selection_make(pool, &q, name, flags & ~SELECTION_MODEBITS);
+ if ((flags & SELECTION_MODEBITS) == SELECTION_ADD)
+ selection_add(pool, selection, &q);
+ else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT)
+ selection_subtract(pool, selection, &q);
+ else if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
+ {
+ if ((flags & SELECTION_FILTER_SWAPPED) != 0)
+ {
+ selection_filter(pool, &q, selection);
+ queue_free(selection);
+ queue_init_clone(selection, &q);
+ }
+ else
+ selection_filter(pool, selection, &q);
+ }
+ queue_free(&q);
+ return ret;
+ }
queue_empty(selection);
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
+ return 0;
+
+ /* here come our four selection modes */
if ((flags & SELECTION_FILELIST) != 0)
ret = selection_filelist(pool, selection, name, flags);
- if (!ret && (flags & SELECTION_REL) != 0 && strpbrk(name, "<=>") != 0)
- ret = selection_rel(pool, selection, name, flags);
- if (!ret)
- ret = selection_depglob_arch(pool, selection, name, flags);
+ if (!ret && (flags & SELECTION_NAME) != 0)
+ ret = selection_name_arch_rel(pool, selection, name, flags, 0);
+ if (!ret && (flags & SELECTION_PROVIDES) != 0)
+ ret = selection_name_arch_rel(pool, selection, name, flags, 1);
if (!ret && (flags & SELECTION_CANON) != 0)
ret = selection_canon(pool, selection, name, flags);
- if (selection->count && (flags & SELECTION_INSTALLED_ONLY) != 0)
- selection_filter_installed(pool, selection);
- if (ret && !selection->count)
- ret = 0; /* no match -> always return zero */
+
+ /* now do result filtering */
+ if (ret && (flags & SELECTION_INSTALLED_ONLY) != 0)
+ selection_filter_repo(pool, selection, pool->installed);
+
+ /* flatten if requested */
if (ret && (flags & SELECTION_FLAT) != 0)
selection_flatten(pool, selection);
- return ret;
+ return selection->count ? ret : 0;
}
-static inline int
+struct limiter {
+ int start; /* either 2 or repofilter->start */
+ int end; /* either nsolvables or repofilter->end */
+ Id *mapper;
+ Repo *repofilter;
+};
+
+/* add matching src packages to simple SOLVABLE_NAME selections */
+static void
+setup_limiter(Pool *pool, int flags, struct limiter *limiter)
+{
+ limiter->start = 2;
+ limiter->end = pool->nsolvables;
+ limiter->mapper = 0;
+ limiter->repofilter = 0;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+ {
+ Repo *repo = pool->installed;
+ limiter->repofilter = repo;
+ limiter->start = repo ? repo->start : 0;
+ limiter->end = repo ? repo->end : 0;
+ }
+}
+
+static int
matchdep_str(const char *pattern, const char *string, int flags)
{
if (flags & SELECTION_GLOB)
@@ -884,161 +1393,315 @@ matchdep_str(const char *pattern, const char *string, int flags)
return strcmp(pattern, string) == 0 ? 1 : 0;
}
+/* like pool_match_dep but uses matchdep_str to match the name for glob and nocase matching */
static int
-matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags)
+matchdep(Pool *pool, Id id, char *rname, int rflags, Id revr, int flags)
{
if (ISRELDEP(id))
{
Reldep *rd = GETRELDEP(pool, id);
- if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH || rd->flags == REL_WITHOUT || rd->flags == REL_COND || rd->flags == REL_UNLESS)
+ if (rd->flags > 7)
{
- if (matchdep(pool, rd->name, rname, rflags, revr, flags))
- return 1;
- if ((rd->flags == REL_COND || rd->flags == REL_UNLESS) && ISRELDEP(rd->evr))
+ if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH || rd->flags == REL_WITHOUT || rd->flags == REL_COND || rd->flags == REL_UNLESS)
{
- rd = GETRELDEP(pool, rd->evr);
- if (rd->flags != REL_ELSE)
- return 0;
+ if (matchdep(pool, rd->name, rname, rflags, revr, flags))
+ return 1;
+ if ((rd->flags == REL_COND || rd->flags == REL_UNLESS) && ISRELDEP(rd->evr))
+ {
+ rd = GETRELDEP(pool, rd->evr);
+ if (rd->flags != REL_ELSE)
+ return 0;
+ }
+ if (rd->flags != REL_COND && rd->flags != REL_UNLESS && rd->flags != REL_WITHOUT && matchdep(pool, rd->evr, rname, rflags, revr, flags))
+ return 1;
+ return 0;
}
- if (rd->flags != REL_COND && rd->flags != REL_UNLESS && rd->flags != REL_WITHOUT && matchdep(pool, rd->evr, rname, rflags, revr, flags))
- return 1;
- return 0;
+ if (rd->flags == REL_ARCH)
+ return matchdep(pool, rd->name, rname, rflags, revr, flags);
}
- if (rd->flags == REL_ARCH)
- return matchdep(pool, rd->name, rname, rflags, revr, flags);
if (!matchdep(pool, rd->name, rname, rflags, revr, flags))
return 0;
- if (rflags)
- {
- /* XXX: need pool_match_flags_evr here */
- if (!pool_match_dep(pool, pool_rel2id(pool, rd->name, pool_str2id(pool, revr, 1), rflags, 1), id))
- return 0;
- }
+ if (rflags && !pool_intersect_evrs(pool, rd->flags, rd->evr, rflags, revr))
+ return 0;
return 1;
}
return matchdep_str(rname, pool_id2str(pool, id), flags);
}
-/*
- * select against the dependencies in keyname
- * like SELECTION_REL and SELECTION_PROVIDES, but with the
- * deps in keyname instead of provides.
- */
-int
-selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
+static int
+selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker, struct limiter *limiter)
{
- char *rname, *r = 0;
+ int li, i, j;
+ int ret = 0;
+ char *rname = 0, *r = 0;
int rflags = 0;
+ Id revr = 0;
Id p;
Queue q;
queue_empty(selection);
- rname = solv_strdup(name);
- if (!(flags & SELECTION_MATCH_DEPSTR))
+ if (!limiter->end)
+ return 0;
+ if (!name && !dep)
+ return 0;
+
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+ flags &= ~SELECTION_REL;
+
+ if (name)
{
- if ((r = strpbrk(rname, "<=>")) != 0)
+ rname = solv_strdup(name);
+ if ((flags & SELECTION_REL) != 0)
{
- if ((r = splitrel(rname, r, &rflags)) == 0)
+ if ((r = strpbrk(rname, "<=>")) != 0)
{
- solv_free(rname);
- return 0;
+ if ((r = splitrel(rname, r, &rflags)) == 0)
+ {
+ solv_free(rname);
+ return 0;
+ }
}
+ revr = pool_str2id(pool, r, 1);
+ ret |= SELECTION_REL;
+ }
+ if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0)
+ flags &= ~SELECTION_GLOB;
+
+ if ((flags & SELECTION_GLOB) == 0 && (flags & SELECTION_NOCASE) == 0 && (flags & SELECTION_MATCH_DEPSTR) == 0)
+ {
+ /* we can use the faster selection_make_matchdepid */
+ dep = pool_str2id(pool, rname, 1);
+ if (rflags)
+ dep = pool_rel2id(pool, dep, revr, rflags, 1);
+ rname = solv_free(rname);
+ name = 0;
+ }
+ }
+ if (dep)
+ {
+ if (keyname == SOLVABLE_NAME && (flags & SELECTION_MATCH_DEPSTR) != 0)
+ {
+ Reldep *rd;
+ if (!ISRELDEP(dep))
+ return 0;
+ rd = GETRELDEP(pool, dep);
+ if (!rd->name || rd->flags != REL_EQ)
+ return 0;
+ dep = rd->name;
+ rflags = rd->flags;
+ revr = rd->evr;
}
}
- if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0)
- flags &= ~SELECTION_GLOB;
queue_init(&q);
- FOR_POOL_SOLVABLES(p)
+ for (li = limiter->start; li < limiter->end; li++)
{
- Solvable *s = pool->solvables + p;
- int i;
-
- if (s->repo != pool->installed && !pool_installable(pool, s))
+ Solvable *s;
+ p = limiter->mapper ? limiter->mapper[li] : li;
+ s = pool->solvables + p;
+ if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
+ continue;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
{
- if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
+ if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
continue;
- if (pool_disabled_solvable(pool, s))
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
continue;
}
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
- continue;
- if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
- continue;
+ else
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ continue;
+ if (s->repo != pool->installed)
+ {
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+ continue;
+ }
+ }
+ if (keyname == SOLVABLE_NAME) /* nevr match hack */
+ {
+ if (dep)
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+ {
+ if (s->name != dep || s->evr != revr)
+ continue;
+ }
+ else
+ {
+ if (!pool_match_nevr(pool, s, dep))
+ continue;
+ }
+ }
+ else
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */
+ {
+ char *tmp = pool_tmpjoin(pool, pool_id2str(pool, s->name), " = ", pool_id2str(pool, s->evr));
+ if (!matchdep_str(rname, tmp, flags))
+ continue;
+ }
+ else
+ {
+ if (!matchdep(pool, s->name, rname, rflags, revr, flags))
+ continue;
+ if (rflags && !pool_intersect_evrs(pool, rflags, revr, REL_EQ, s->evr))
+ continue;
+ }
+ }
+ queue_push(selection, p);
+ continue;
+ }
queue_empty(&q);
repo_lookup_deparray(s->repo, p, keyname, &q, marker);
- for (i = 0; i < q.count; i++)
+ if (!q.count)
+ continue;
+ if (dep)
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */
+ {
+ for (i = 0; i < q.count; i++)
+ if (q.elements[i] == dep)
+ break;
+ }
+ else
+ {
+ for (i = 0; i < q.count; i++)
+ if (pool_match_dep(pool, q.elements[i], dep))
+ break;
+ }
+ }
+ else
{
- Id id = q.elements[i];
if ((flags & SELECTION_MATCH_DEPSTR) != 0)
{
- if (matchdep_str(rname, pool_dep2str(pool, id), flags))
- break;
- continue;
+ for (i = 0; i < q.count; i++)
+ if (matchdep_str(rname, pool_dep2str(pool, q.elements[i]), flags))
+ break;
+ }
+ else
+ {
+ for (i = 0; i < q.count; i++)
+ if (matchdep(pool, q.elements[i], rname, rflags, revr, flags))
+ break;
}
- if (matchdep(pool, id, rname, rflags, r, flags))
- break;
}
if (i < q.count)
- queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
+ queue_push(selection, p);
}
queue_free(&q);
solv_free(rname);
if (!selection->count)
return 0;
+
+ /* convert package list to selection */
+ j = selection->count;
+ queue_insertn(selection, 0, selection->count, 0);
+ for (i = 0; i < selection->count; )
+ {
+ selection->elements[i++] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+ selection->elements[i++] = selection->elements[j++];
+ }
+
if ((flags & SELECTION_FLAT) != 0)
selection_flatten(pool, selection);
- return SELECTION_PROVIDES;
+ return ret | (keyname == SOLVABLE_NAME ? SELECTION_NAME : SELECTION_PROVIDES);
}
-int
-selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
+static int
+selection_make_matchdeps_common(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker)
{
- Id p;
- Queue q;
+ struct limiter limiter;
- queue_empty(selection);
- if (!dep)
- return 0;
- queue_init(&q);
- FOR_POOL_SOLVABLES(p)
+ setup_limiter(pool, flags, &limiter);
+ if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
{
- Solvable *s = pool->solvables + p;
- int i;
-
- if (s->repo != pool->installed && !pool_installable(pool, s))
+ int ret;
+ Queue q, qlimit;
+ queue_init(&q);
+ queue_init(&qlimit);
+ /* deal with special filter cases */
+ if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER && selection->count == 2 && limiter.end)
{
- if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
- continue;
- if (pool_disabled_solvable(pool, s))
- continue;
+ if ((selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+ flags = (flags & ~SELECTION_MODEBITS) | SELECTION_REPLACE;
+ else if ((selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO)
+ {
+ Repo *repo = pool_id2repo(pool, selection->elements[1]);
+ if (limiter.repofilter && repo != limiter.repofilter)
+ repo = 0;
+ limiter.repofilter = repo;
+ limiter.start = repo ? repo->start : 0;
+ limiter.end = repo ? repo->end : 0;
+ flags = (flags & ~SELECTION_MODEBITS) | SELECTION_REPLACE;
+ }
}
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
- continue;
- if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
- continue;
- queue_empty(&q);
- repo_lookup_deparray(s->repo, p, keyname, &q, marker);
- for (i = 0; i < q.count; i++)
+ if (limiter.end && ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT || (flags & SELECTION_MODEBITS) == SELECTION_FILTER))
+ {
+ selection_solvables(pool, selection, &qlimit);
+ limiter.start = 0;
+ limiter.end = qlimit.count;
+ limiter.mapper = qlimit.elements;
+ }
+ ret = selection_make_matchdeps_common_limited(pool, &q, name, dep, flags & ~SELECTION_MODEBITS, keyname, marker, &limiter);
+ queue_free(&qlimit);
+ if ((flags & SELECTION_MODEBITS) == SELECTION_ADD)
+ selection_add(pool, selection, &q);
+ else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT)
+ selection_subtract(pool, selection, &q);
+ else if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER)
{
- if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */
+ if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
{
- if (q.elements[i] == dep)
- break;
- continue;
+ if ((flags & SELECTION_FILTER_SWAPPED) != 0)
+ {
+ selection_filter(pool, &q, selection);
+ queue_free(selection);
+ queue_init_clone(selection, &q);
+ }
+ else
+ selection_filter(pool, selection, &q);
}
- if (pool_match_dep(pool, q.elements[i], dep))
- break;
}
- if (i < q.count)
- queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
+ else if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
+ {
+ /* special filter case from above */
+ int i;
+ Id f = selection->elements[0] & ~(SOLVER_SELECTMASK|SOLVER_NOAUTOSET); /* job, jobflags, setflags */
+ queue_free(selection);
+ queue_init_clone(selection, &q);
+ for (i = 0; i < selection->count; i += 2)
+ selection->elements[i] = (selection->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | f;
+ }
+ queue_free(&q);
+ return ret;
}
- queue_free(&q);
- if (!selection->count)
- return 0;
- if ((flags & SELECTION_FLAT) != 0)
- selection_flatten(pool, selection);
- return SELECTION_PROVIDES;
+ return selection_make_matchdeps_common_limited(pool, selection, name, dep, flags, keyname, marker, &limiter);
+}
+
+/*
+ * select against the dependencies in keyname
+ * like SELECTION_PROVIDES, but with the deps in keyname instead of provides.
+ * supported match modifiers:
+ * SELECTION_REL
+ * SELECTION_GLOB
+ * SELECTION_NOCASE
+ */
+int
+selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
+{
+ return selection_make_matchdeps_common(pool, selection, name, 0, flags, keyname, marker);
+}
+
+/*
+ * select against the dependency id in keyname
+ */
+int
+selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
+{
+ return selection_make_matchdeps_common(pool, selection, 0, dep, flags, keyname, marker);
}
static inline int
@@ -1064,10 +1727,81 @@ pool_is_kind(Pool *pool, Id name, Id kind)
}
}
-void
-selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
+static void
+selection_filter_map(Pool *pool, Queue *sel, Map *m, int setflags)
{
int i, j, miss;
+ Queue q;
+ Id p, pp;
+
+ queue_init(&q);
+ for (i = j = 0; i < sel->count; i += 2)
+ {
+ Id select = sel->elements[i] & SOLVER_SELECTMASK;
+ queue_empty(&q);
+ miss = 0;
+ if (select == SOLVER_SOLVABLE_ALL)
+ {
+ FOR_POOL_SOLVABLES(p)
+ {
+ if (map_tst(m, p))
+ queue_push(&q, p);
+ else
+ miss = 1;
+ }
+ }
+ else if (select == SOLVER_SOLVABLE_REPO)
+ {
+ Solvable *s;
+ Repo *repo = pool_id2repo(pool, sel->elements[i + 1]);
+ if (repo)
+ {
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ if (map_tst(m, p))
+ queue_push(&q, p);
+ else
+ miss = 1;
+ }
+ }
+ }
+ else
+ {
+ FOR_JOB_SELECT(p, pp, select, sel->elements[i + 1])
+ {
+ if (map_tst(m, p))
+ queue_pushunique(&q, p);
+ else
+ miss = 1;
+ }
+ }
+ if (!q.count)
+ continue;
+ if (!miss)
+ {
+ sel->elements[j] = sel->elements[i] | setflags;
+ sel->elements[j + 1] = sel->elements[i + 1];
+ }
+ else if (q.count > 1)
+ {
+ sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
+ sel->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
+ }
+ else
+ {
+ sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
+ sel->elements[j + 1] = q.elements[0];
+ }
+ j += 2;
+ }
+ queue_truncate(sel, j);
+ queue_free(&q);
+}
+
+static void
+selection_filter_int(Pool *pool, Queue *sel1, Queue *sel2, int invert)
+{
+ int i, j;
Id p, pp, q1filled = 0;
Queue q1;
Map m2;
@@ -1075,10 +1809,12 @@ selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
if (!sel1->count || !sel2->count)
{
+ if (invert && !sel2->count)
+ return;
queue_empty(sel1);
return;
}
- if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+ if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL && !invert)
{
/* XXX: not 100% correct, but very useful */
p = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK); /* job & jobflags */
@@ -1088,6 +1824,8 @@ selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | p ;
return;
}
+
+ /* convert sel2 into a map */
queue_init(&q1);
map_init(&m2, pool->nsolvables);
for (i = 0; i < sel2->count; i += 2)
@@ -1097,6 +1835,8 @@ selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
{
queue_free(&q1);
map_free(&m2);
+ if (invert)
+ queue_empty(sel1);
return;
}
if (select == SOLVER_SOLVABLE_REPO)
@@ -1147,78 +1887,34 @@ selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
map_set(&m2, p);
}
}
- if (sel2->count == 2) /* XXX: AND all setmasks instead? */
- setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
- for (i = j = 0; i < sel1->count; i += 2)
- {
- Id select = sel1->elements[i] & SOLVER_SELECTMASK;
- queue_empty(&q1);
- miss = 0;
- if (select == SOLVER_SOLVABLE_ALL)
- {
- FOR_POOL_SOLVABLES(p)
- {
- if (map_tst(&m2, p))
- queue_push(&q1, p);
- else
- miss = 1;
- }
- }
- else if (select == SOLVER_SOLVABLE_REPO)
- {
- Solvable *s;
- Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
- if (repo)
- {
- FOR_REPO_SOLVABLES(repo, p, s)
- {
- if (map_tst(&m2, p))
- queue_push(&q1, p);
- else
- miss = 1;
- }
- }
- }
- else
- {
- FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
- {
- if (map_tst(&m2, p))
- queue_pushunique(&q1, p);
- else
- miss = 1;
- }
- }
- if (!q1.count)
- continue;
- if (!miss)
- {
- sel1->elements[j] = sel1->elements[i] | setflags;
- sel1->elements[j + 1] = sel1->elements[i + 1];
- }
- else if (q1.count > 1)
- {
- sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
- sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
- }
- else
- {
- sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
- sel1->elements[j + 1] = q1.elements[0];
- }
- j += 2;
- }
- queue_truncate(sel1, j);
queue_free(&q1);
+
+ /* now filter sel1 with the map */
+ if (invert)
+ map_invertall(&m2);
+ if (sel2->count == 2)
+ setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
+ selection_filter_map(pool, sel1, &m2, setflags);
map_free(&m2);
}
void
+selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
+{
+ selection_filter_int(pool, sel1, sel2, 0);
+}
+
+void
selection_add(Pool *pool, Queue *sel1, Queue *sel2)
{
- int i;
- for (i = 0; i < sel2->count; i++)
- queue_push(sel1, sel2->elements[i]);
+ if (sel2->count)
+ queue_insertn(sel1, sel1->count, sel2->count, sel2->elements);
+}
+
+void
+selection_subtract(Pool *pool, Queue *sel1, Queue *sel2)
+{
+ selection_filter_int(pool, sel1, sel2, 1);
}
const char *
diff --git a/src/selection.h b/src/selection.h
index 0dd6150..9938c2f 100644
--- a/src/selection.h
+++ b/src/selection.h
@@ -19,21 +19,45 @@
extern "C" {
#endif
+/* what to match */
#define SELECTION_NAME (1 << 0)
#define SELECTION_PROVIDES (1 << 1)
#define SELECTION_FILELIST (1 << 2)
#define SELECTION_CANON (1 << 3)
-#define SELECTION_DOTARCH (1 << 4)
-#define SELECTION_REL (1 << 5)
-#define SELECTION_INSTALLED_ONLY (1 << 8)
+/* match extensions */
+#define SELECTION_DOTARCH (1 << 4) /* allow ".arch" suffix */
+#define SELECTION_REL (1 << 5) /* allow "<=> rel" suffix */
+
+/* string comparison modifiers */
#define SELECTION_GLOB (1 << 9)
-#define SELECTION_FLAT (1 << 10)
#define SELECTION_NOCASE (1 << 11)
+
+/* extra flags */
+#define SELECTION_FLAT (1 << 10) /* flatten the resulting selection */
+#define SELECTION_SKIP_KIND (1 << 14) /* remove kind: name prefix in SELECTION_NAME matches */
+#define SELECTION_MATCH_DEPSTR (1 << 15) /* match dep2str result */
+
+/* package selection */
+#define SELECTION_INSTALLED_ONLY (1 << 8)
#define SELECTION_SOURCE_ONLY (1 << 12)
#define SELECTION_WITH_SOURCE (1 << 13)
-#define SELECTION_SKIP_KIND (1 << 14)
-#define SELECTION_MATCH_DEPSTR (1 << 15)
+#define SELECTION_WITH_DISABLED (1 << 16)
+#define SELECTION_WITH_BADARCH (1 << 17)
+#define SELECTION_WITH_ALL (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH)
+
+/* result operator */
+#define SELECTION_REPLACE (0 << 28)
+#define SELECTION_ADD (1 << 28)
+#define SELECTION_SUBTRACT (2 << 28)
+#define SELECTION_FILTER (3 << 28)
+
+#define SELECTION_MODEBITS (3 << 28) /* internal */
+
+/* extra SELECTION_FILTER bits */
+#define SELECTION_FILTER_KEEP_IFEMPTY (1 << 30)
+#define SELECTION_FILTER_SWAPPED (1 << 31)
+
extern int selection_make(Pool *pool, Queue *selection, const char *name, int flags);
extern int selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker);
@@ -41,6 +65,8 @@ extern int selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int
extern void selection_filter(Pool *pool, Queue *sel1, Queue *sel2);
extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2);
+extern void selection_subtract(Pool *pool, Queue *sel1, Queue *sel2);
+
extern void selection_solvables(Pool *pool, Queue *selection, Queue *pkgs);
extern const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask);
diff --git a/src/solver.c b/src/solver.c
index 037b33d..6405f4a 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -31,82 +31,6 @@
#define RULES_BLOCK 63
-static Id
-autouninstall(Solver *solv, Id *problem)
-{
- Pool *pool = solv->pool;
- int i;
- int lastfeature = 0, lastupdate = 0;
- Id v;
- Id extraflags = -1;
- Map *m = 0;
-
- if (!solv->allowuninstall && !solv->allowuninstall_all)
- {
- if (!solv->allowuninstallmap.size)
- return 0; /* why did we get called? */
- m = &solv->allowuninstallmap;
- }
- for (i = 0; (v = problem[i]) != 0; i++)
- {
- if (v < 0)
- extraflags &= solv->job.elements[-v - 1];
- if (v >= solv->updaterules && v < solv->updaterules_end)
- {
- Rule *r;
- if (m && !MAPTST(m, v - solv->updaterules))
- continue;
- /* check if identical to feature rule, we don't like that (except for orphans) */
- r = solv->rules + solv->featurerules + (v - solv->updaterules);
- if (!r->p)
- {
- /* update rule == feature rule */
- if (v > lastfeature)
- lastfeature = v;
- /* prefer orphaned packages in dup mode */
- if (solv->keep_orphans)
- {
- r = solv->rules + v;
- if (!r->d && !r->w2 && r->p == (solv->installed->start + (v - solv->updaterules)))
- {
- lastfeature = v;
- lastupdate = 0;
- break;
- }
- }
- continue;
- }
- if (v > lastupdate)
- lastupdate = v;
- }
- }
- if (!lastupdate && !lastfeature)
- return 0;
- v = lastupdate ? lastupdate : lastfeature;
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
- solver_disableproblem(solv, v);
- if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
- {
- /* add the package to the updatepkgs list, this will automatically turn
- * on cleandeps mode */
- Id p = solv->rules[v].p;
- if (!solv->cleandeps_updatepkgs)
- {
- solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
- queue_init(solv->cleandeps_updatepkgs);
- }
- if (p > 0)
- {
- int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
- queue_pushunique(solv->cleandeps_updatepkgs, p);
- if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
- solver_disablepolicyrules(solv);
- }
- }
- return v;
-}
-
/************************************************************************/
/*
@@ -164,17 +88,18 @@ enabledisablelearntrules(Solver *solv)
* If we find a conflict, disable rules and add them to problem queue.
*/
-static void
-makeruledecisions(Solver *solv)
+static int
+makeruledecisions(Solver *solv, int disablerules)
{
Pool *pool = solv->pool;
- int i, ri, ii;
+ int i, ri, ii, ori;
Rule *r, *rr;
Id v, vv;
int decisionstart;
int record_proof = 1;
int oldproblemcount;
int havedisabled = 0;
+ int doautouninstall;
/* The system solvable is always installed first */
assert(solv->decisionq.count == 0);
@@ -222,7 +147,7 @@ makeruledecisions(Solver *solv)
if (!solv->decisionmap[vv]) /* if not yet decided */
{
queue_push(&solv->decisionq, v);
- queue_push(&solv->decisionq_why, r - solv->rules);
+ queue_push(&solv->decisionq_why, ri);
solv->decisionmap[vv] = v > 0 ? 1 : -1;
IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
{
@@ -254,14 +179,13 @@ makeruledecisions(Solver *solv)
/* conflict with a learnt rule */
/* can happen when packages cannot be installed for multiple reasons. */
/* we disable the learnt rule in this case */
- /* (XXX: we should really call analyze_unsolvable_rule here!) */
+ /* (XXX: we should really do something like analyze_unsolvable_rule here!) */
solver_disablerule(solv, r);
continue;
}
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ASSERTION ----------------------\n");
- IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri);
+ assert(ri >= solv->pkgrules_end); /* must not have a conflict in the pkg rules! */
/*
* find the decision which is the "opposite" of the rule
@@ -270,136 +194,94 @@ makeruledecisions(Solver *solv)
if (solv->decisionq.elements[i] == -v)
break;
assert(i < solv->decisionq.count); /* assert that we found it */
- oldproblemcount = solv->problems.count;
-
- /*
- * conflict with system solvable ?
- */
if (v == -SYSTEMSOLVABLE)
+ ori = 0;
+ else
{
- if (record_proof)
- {
- queue_push(&solv->problems, solv->learnt_pool.count);
- queue_push(&solv->learnt_pool, ri);
- queue_push(&solv->learnt_pool, 0);
- }
- else
- queue_push(&solv->problems, 0);
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
- if (ri >= solv->jobrules && ri < solv->jobrules_end)
- v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
- else
- v = ri;
- queue_push(&solv->problems, v);
- queue_push(&solv->problems, 0);
- if (v >= solv->featurerules && v < solv->updaterules_end)
- {
- if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
- if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
- {
- solv->problems.count = oldproblemcount;
- havedisabled = 1;
- break; /* start over */
- }
- }
- solver_disableproblem(solv, v);
- havedisabled = 1;
- break; /* start over */
+ ori = solv->decisionq_why.elements[i]; /* the conflicting rule */
+ assert(ori > 0);
}
- assert(solv->decisionq_why.elements[i] > 0);
- IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + solv->decisionq_why.elements[i]);
-
/*
- * conflict with a pkg rule ?
- */
- if (solv->decisionq_why.elements[i] < solv->pkgrules_end)
+ * record the problem
+ */
+ doautouninstall = 0;
+ oldproblemcount = solv->problems.count;
+ queue_push(&solv->problems, 0); /* start problem */
+ if (ori < solv->pkgrules_end)
{
- if (record_proof)
+ /* easy: conflict with system solvable or pkg rule */
+ assert(v > 0 || v == -SYSTEMSOLVABLE);
+ IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
{
- queue_push(&solv->problems, solv->learnt_pool.count);
- queue_push(&solv->learnt_pool, ri);
- queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
- queue_push(&solv->learnt_pool, 0);
+ if (ori)
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri);
+ else
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri);
+ if (ori)
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ori);
}
- else
- queue_push(&solv->problems, 0);
- assert(v > 0 || v == -SYSTEMSOLVABLE);
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri);
- if (ri >= solv->jobrules && ri < solv->jobrules_end)
- v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
- else
- v = ri;
- queue_push(&solv->problems, v);
- queue_push(&solv->problems, 0);
- if (v >= solv->featurerules && v < solv->updaterules_end)
+ solver_recordproblem(solv, ri);
+ if (ri >= solv->featurerules && ri < solv->updaterules_end)
+ doautouninstall = 1;
+ }
+ else
+ {
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
+ /*
+ * push all of our rules (can only be feature or job rules)
+ * asserting this literal on the problem stack
+ */
+ for (i = solv->pkgrules_end, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
{
- if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
- if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
- {
- solv->problems.count = oldproblemcount;
- havedisabled = 1;
- break; /* start over */
- }
+ if (rr->d < 0 /* disabled */
+ || rr->w2) /* or no assertion */
+ continue;
+ if (rr->p != vv /* not affecting the literal */
+ && rr->p != -vv)
+ continue;
+ if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */
+ continue;
+
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
+ solver_recordproblem(solv, i);
+ if (i >= solv->featurerules && i < solv->updaterules_end)
+ doautouninstall = 1;
}
- solver_disableproblem(solv, v);
- havedisabled = 1;
- break; /* start over */
}
+ queue_push(&solv->problems, 0); /* finish problem */
- /*
- * conflict with another job or update/feature rule
- */
+ /* try autouninstall if requested */
+ if (doautouninstall)
+ {
+ if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
+ if (solver_autouninstall(solv, oldproblemcount) != 0)
+ {
+ solv->problems.count = oldproblemcount;
+ havedisabled = 1;
+ break; /* start over */
+ }
+ }
- /* record proof */
+ /* record the proof if requested */
if (record_proof)
{
- queue_push(&solv->problems, solv->learnt_pool.count);
+ solv->problems.elements[oldproblemcount] = solv->learnt_pool.count;
queue_push(&solv->learnt_pool, ri);
- queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
+ if (ori)
+ queue_push(&solv->learnt_pool, ori);
queue_push(&solv->learnt_pool, 0);
}
- else
- queue_push(&solv->problems, 0);
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
-
- /*
- * push all of our rules (can only be feature or job rules)
- * asserting this literal on the problem stack
- */
- for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
+ if (!disablerules)
{
- if (rr->d < 0 /* disabled */
- || rr->w2) /* or no assertion */
- continue;
- if (rr->p != vv /* not affecting the literal */
- && rr->p != -vv)
- continue;
- if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */
- continue;
-
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
-
- v = i;
- if (i >= solv->jobrules && i < solv->jobrules_end)
- v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
- queue_push(&solv->problems, v);
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
+ return -1;
}
- queue_push(&solv->problems, 0);
-
- if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
- if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
- {
- solv->problems.count = oldproblemcount;
- havedisabled = 1;
- break; /* start over */
- }
-
- for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
- solver_disableproblem(solv, solv->problems.elements[i]);
+ /* disable all problem rules */
+ solver_disableproblemset(solv, oldproblemcount);
havedisabled = 1;
break; /* start over */
}
@@ -444,21 +326,15 @@ makeruledecisions(Solver *solv)
continue;
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
- solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r);
-
- if (ri >= solv->jobrules && ri < solv->jobrules_end)
- v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
- else
- v = ri;
- solver_disableproblem(solv, v);
- if (v < 0)
- solver_reenablepolicyrules(solv, -v);
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
+ solver_fixproblem(solv, ri);
havedisabled = 1;
break; /* start over */
}
if (ii == solv->ruleassertions.count)
break; /* finished! */
}
+ return 1; /* the new level */
}
@@ -1013,36 +889,9 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Queue *weakq, Map *rseen)
}
if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, why) && weakq)
queue_push(weakq, why);
- /* do not add pkg rules to problem */
- if (why < solv->pkgrules_end)
- return;
- /* turn rule into problem */
- if (why >= solv->jobrules && why < solv->jobrules_end)
- why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
- /* normalize dup/infarch rules */
- if (why > solv->infarchrules && why < solv->infarchrules_end)
- {
- Id name = pool->solvables[-solv->rules[why].p].name;
- while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
- why--;
- }
- if (why > solv->duprules && why < solv->duprules_end)
- {
- Id name = pool->solvables[-solv->rules[why].p].name;
- while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
- why--;
- }
-
- /* return if problem already countains our rule */
- if (solv->problems.count)
- {
- for (i = solv->problems.count - 1; i >= 0; i--)
- if (solv->problems.elements[i] == 0) /* end of last problem reached? */
- break;
- else if (solv->problems.elements[i] == why)
- return;
- }
- queue_push(&solv->problems, why);
+ /* add non-pkg rules to problem and disable */
+ if (why >= solv->pkgrules_end)
+ solver_recordproblem(solv, why);
}
@@ -1149,24 +998,18 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
return 0;
}
queue_free(&weakq);
- if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end)
- v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1);
- else
- v = lastweak;
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
solver_disablechoicerules(solv, solv->rules + lastweak);
- solver_disableproblem(solv, v);
- if (v < 0)
- solver_reenablepolicyrules(solv, -v);
+ solver_fixproblem(solv, lastweak);
solver_reset(solv);
return 0;
}
queue_free(&weakq);
if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
- if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
+ if (solver_autouninstall(solv, oldproblemcount) != 0)
{
solv->problems.count = oldproblemcount;
solv->learnt_pool.count = oldlearntpoolcount;
@@ -1184,8 +1027,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
/* + 2: index + trailing zero */
if (disablerules && oldproblemcount + 2 < solv->problems.count)
{
- for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
- solver_disableproblem(solv, solv->problems.elements[i]);
+ solver_disableproblemset(solv, oldproblemcount);
/* XXX: might want to enable all weak rules again */
solver_reset(solv);
return 0;
@@ -2672,13 +2514,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
{
if (level < 0)
break;
- makeruledecisions(solv);
- level = 1;
- if (!disablerules && solv->problems.count)
- {
- level = -1;
- break;
- }
+ level = makeruledecisions(solv, disablerules);
+ if (level < 0)
+ break;
POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "initial propagate (propagate_index: %d; size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
if ((r = propagate(solv, level)) != 0)
{
@@ -3494,7 +3332,6 @@ solver_solve(Solver *solv, Queue *job)
deduceq2addedmap(solv, &addedmap);
if (solv->nrules != initialnrules)
solver_shrinkrules(solv, initialnrules);
- solv->nrules = initialnrules;
solv->lastpkgrule = 0;
solv->pkgrules_end = 0;
@@ -3588,7 +3425,7 @@ solver_solve(Solver *solv, Queue *job)
}
break;
case SOLVER_DROP_ORPHANED:
- if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+ if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
solv->droporphanedmap_all = 1;
FOR_JOB_SELECT(p, pp, select, what)
{
@@ -4021,18 +3858,7 @@ solver_solve(Solver *solv, Queue *job)
/* now create infarch and dup rules */
if (!solv->noinfarchcheck)
- {
- solver_addinfarchrules(solv, &addedmap);
-#if 0
- if (pool->implicitobsoleteusescolors)
- {
- /* currently doesn't work well with infarch rules, so make
- * them weak */
- for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
- queue_push(&solv->weakruleq, i);
- }
-#endif
- }
+ solver_addinfarchrules(solv, &addedmap);
else
solv->infarchrules = solv->infarchrules_end = solv->nrules;
@@ -4049,7 +3875,7 @@ solver_solve(Solver *solv, Queue *job)
if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
solver_addbestrules(solv, hasbestinstalljob);
else
- solv->bestrules = solv->bestrules_end = solv->nrules;
+ solv->bestrules = solv->bestrules_end = solv->bestrules_up = solv->nrules;
if (needduprules)
solver_freedupmaps(solv); /* no longer needed */
@@ -4079,7 +3905,7 @@ solver_solve(Solver *solv, Queue *job)
map_free(&installcandidatemap);
queue_free(&q);
- POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules);
+ POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules, solv->yumobsrules_end - solv->yumobsrules);
POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
/* create weak map */
@@ -4716,351 +4542,6 @@ pool_isemptyupdatejob(Pool *pool, Id how, Id what)
return 1;
}
-static int
-get_userinstalled_cmp(const void *ap, const void *bp, void *dp)
-{
- return *(Id *)ap - *(Id *)bp;
-}
-
-static int
-get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
-{
- Pool *pool = dp;
- return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
-}
-
-static int
-get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp)
-{
- Pool *pool = dp;
- int r;
- r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0]));
- if (r)
- return r;
- return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1]));
-}
-
-static void
-get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
-{
- Id lastp = -1, lasta = -1;
- int i, j;
- if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2))
- return;
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool);
- else if ((flags & GET_USERINSTALLED_NAMES) != 0)
- solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
- else
- solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- {
- for (i = j = 0; i < q->count; i += 2)
- if (q->elements[i] != lastp || q->elements[i + 1] != lasta)
- {
- q->elements[j++] = lastp = q->elements[i];
- q->elements[j++] = lasta = q->elements[i + 1];
- }
- }
- else
- {
- for (i = j = 0; i < q->count; i++)
- if (q->elements[i] != lastp)
- q->elements[j++] = lastp = q->elements[i];
- }
- queue_truncate(q, j);
-}
-
-static void
-namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job)
-{
- int i;
- if (!pool->installed)
- return;
- for (i = 0; i < q->count; i += 2)
- {
- Id p, pp, name = q->elements[i], arch = q->elements[i + 1];
- FOR_PROVIDES(p, pp, name)
- {
- Solvable *s = pool->solvables + p;
- if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch))
- continue;
- if (job)
- queue_push(qout, job);
- queue_push(qout, p);
- }
- }
-}
-
-void
-solver_get_userinstalled(Solver *solv, Queue *q, int flags)
-{
- Pool *pool = solv->pool;
- Id p, p2, pp;
- Solvable *s;
- Repo *installed = solv->installed;
- int i, j;
- Map userinstalled;
-
- map_init(&userinstalled, 0);
- queue_empty(q);
- /* first process jobs */
- for (i = 0; i < solv->job.count; i += 2)
- {
- Id how = solv->job.elements[i];
- Id what, select;
- if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
- {
- if (!userinstalled.size)
- map_grow(&userinstalled, installed->end - installed->start);
- what = solv->job.elements[i + 1];
- select = how & SOLVER_SELECTMASK;
- if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
- {
- FOR_REPO_SOLVABLES(installed, p, s)
- MAPSET(&userinstalled, p - installed->start);
- }
- FOR_JOB_SELECT(p, pp, select, what)
- if (pool->solvables[p].repo == installed)
- MAPSET(&userinstalled, p - installed->start);
- continue;
- }
- if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL)
- continue;
- if ((how & SOLVER_NOTBYUSER) != 0)
- continue;
- what = solv->job.elements[i + 1];
- select = how & SOLVER_SELECTMASK;
- FOR_JOB_SELECT(p, pp, select, what)
- if (solv->decisionmap[p] > 0)
- {
- queue_push(q, p);
-#ifdef ENABLE_LINKED_PKGS
- if (has_package_link(pool, pool->solvables + p))
- {
- int j;
- Queue lq;
- queue_init(&lq);
- find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0);
- for (j = 0; j < lq.count; j++)
- if (solv->decisionmap[lq.elements[j]] > 0)
- queue_push(q, lq.elements[j]);
- }
-#endif
- }
- }
- /* now process updates of userinstalled packages */
- if (installed && userinstalled.size)
- {
- for (i = 1; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p <= 0)
- continue;
- s = pool->solvables + p;
- if (!s->repo)
- continue;
- if (s->repo == installed)
- {
- if (MAPTST(&userinstalled, p - installed->start))
- queue_push(q, p);
- continue;
- }
- /* new package, check if we replace a userinstalled one */
- FOR_PROVIDES(p2, pp, s->name)
- {
- Solvable *ps = pool->solvables + p2;
- if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
- continue;
- if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
- continue;
- if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
- continue;
- queue_push(q, p);
- break;
- }
- if (!p2 && s->repo != installed && s->obsoletes)
- {
- Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
- while ((obs = *obsp++) != 0)
- {
- FOR_PROVIDES(p2, pp, obs)
- {
- Solvable *ps = pool->solvables + p2;
- if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
- continue;
- if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
- continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
- continue;
- queue_push(q, p);
- break;
- }
- if (p2)
- break;
- }
- }
- }
- }
- map_free(&userinstalled);
-
- /* convert to desired output format */
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- {
- int qcount = q->count;
- queue_insertn(q, 0, qcount, 0);
- for (i = j = 0; i < qcount; i++)
- {
- s = pool->solvables + q->elements[i + qcount];
- q->elements[j++] = s->name;
- q->elements[j++] = s->arch;
- }
- }
- else if ((flags & GET_USERINSTALLED_NAMES) != 0)
- {
- for (i = 0; i < q->count; i++)
- {
- s = pool->solvables + q->elements[i];
- q->elements[i] = s->name;
- }
- }
- /* sort and unify */
- get_userinstalled_sort_uniq(pool, q, flags);
-
- /* invert if asked for */
- if ((flags & GET_USERINSTALLED_INVERTED) != 0)
- {
- /* first generate queue with all installed packages */
- Queue invq;
- queue_init(&invq);
- for (i = 1; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p <= 0)
- continue;
- s = pool->solvables + p;
- if (!s->repo)
- continue;
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- queue_push2(&invq, s->name, s->arch);
- else if ((flags & GET_USERINSTALLED_NAMES) != 0)
- queue_push(&invq, s->name);
- else
- queue_push(&invq, p);
- }
- /* push q on invq, just in case... */
- queue_insertn(&invq, invq.count, q->count, q->elements);
- get_userinstalled_sort_uniq(pool, &invq, flags);
- /* subtract queues (easy as they are sorted and invq is a superset of q) */
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- {
- if (q->count)
- {
- for (i = j = 0; i < invq.count; i += 2)
- if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1])
- {
- invq.elements[i] = invq.elements[i + 1] = 0;
- j += 2;
- if (j >= q->count)
- break;
- }
- queue_empty(q);
- }
- for (i = 0; i < invq.count; i += 2)
- if (invq.elements[i])
- queue_push2(q, invq.elements[i], invq.elements[i + 1]);
- }
- else
- {
- if (q->count)
- {
- for (i = j = 0; i < invq.count; i++)
- if (invq.elements[i] == q->elements[j])
- {
- invq.elements[i] = 0;
- if (++j >= q->count)
- break;
- }
- queue_empty(q);
- }
- for (i = 0; i < invq.count; i++)
- if (invq.elements[i])
- queue_push(q, invq.elements[i]);
- }
- queue_free(&invq);
- }
-}
-
-void
-pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
-{
- int i;
-
- if ((flags & GET_USERINSTALLED_INVERTED) != 0)
- {
- Queue invq;
- Id p, lastid;
- Solvable *s;
- int bad;
- if (!pool->installed)
- return;
- queue_init(&invq);
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- flags &= ~GET_USERINSTALLED_NAMES; /* just in case */
- FOR_REPO_SOLVABLES(pool->installed, p, s)
- queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- {
- /* for namearch we convert to packages */
- namearch2solvables(pool, q, &invq, 0);
- get_userinstalled_sort_uniq(pool, &invq, flags);
- namearch2solvables(pool, q, &invq, 0);
- flags = 0;
- }
- else
- {
- queue_insertn(&invq, invq.count, q->count, q->elements);
- get_userinstalled_sort_uniq(pool, &invq, flags);
- /* now the fun part, add q again, sort, and remove all dups */
- queue_insertn(&invq, invq.count, q->count, q->elements);
- }
- if (invq.count > 1)
- {
- if ((flags & GET_USERINSTALLED_NAMES) != 0)
- solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool);
- else
- solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0);
- }
- lastid = -1;
- bad = 1;
- for (i = 0; i < invq.count; i++)
- {
- if (invq.elements[i] == lastid)
- {
- bad = 1;
- continue;
- }
- if (!bad)
- queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
- bad = 0;
- lastid = invq.elements[i];
- }
- if (!bad)
- queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
- queue_free(&invq);
- }
- else
- {
- if (flags & GET_USERINSTALLED_NAMEARCH)
- namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE);
- else
- {
- for (i = 0; i < q->count; i++)
- queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
- }
- }
-}
-
int
solver_alternatives_count(Solver *solv)
{
diff --git a/src/solver.h b/src/solver.h
index 1b85fb3..ebb2232 100644
--- a/src/solver.h
+++ b/src/solver.h
@@ -68,6 +68,7 @@ struct _Solver {
Id duprules_end;
Id bestrules; /* rules from SOLVER_FORCEBEST */
+ Id bestrules_up; /* update rule part starts here*/
Id bestrules_end;
Id *bestrules_pkg;
diff --git a/src/userinstalled.c b/src/userinstalled.c
new file mode 100644
index 0000000..0efcdd7
--- /dev/null
+++ b/src/userinstalled.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2017, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* Functions that help getting/setting userinstalled packages. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "util.h"
+#include "poolarch.h"
+#include "linkedpkg.h"
+
+static int
+get_userinstalled_cmp(const void *ap, const void *bp, void *dp)
+{
+ return *(Id *)ap - *(Id *)bp;
+}
+
+static int
+get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = dp;
+ return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
+}
+
+static int
+get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = dp;
+ int r;
+ r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0]));
+ if (r)
+ return r;
+ return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1]));
+}
+
+static void
+get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
+{
+ Id lastp = -1, lasta = -1;
+ int i, j;
+ if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2))
+ return;
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool);
+ else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
+ else
+ solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ for (i = j = 0; i < q->count; i += 2)
+ if (q->elements[i] != lastp || q->elements[i + 1] != lasta)
+ {
+ q->elements[j++] = lastp = q->elements[i];
+ q->elements[j++] = lasta = q->elements[i + 1];
+ }
+ }
+ else
+ {
+ for (i = j = 0; i < q->count; i++)
+ if (q->elements[i] != lastp)
+ q->elements[j++] = lastp = q->elements[i];
+ }
+ queue_truncate(q, j);
+}
+
+static void
+namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job)
+{
+ int i;
+ if (!pool->installed)
+ return;
+ for (i = 0; i < q->count; i += 2)
+ {
+ Id p, pp, name = q->elements[i], arch = q->elements[i + 1];
+ FOR_PROVIDES(p, pp, name)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch))
+ continue;
+ if (job)
+ queue_push(qout, job);
+ queue_push(qout, p);
+ }
+ }
+}
+
+void
+solver_get_userinstalled(Solver *solv, Queue *q, int flags)
+{
+ Pool *pool = solv->pool;
+ Id p, p2, pp;
+ Solvable *s;
+ Repo *installed = solv->installed;
+ int i, j;
+ Map userinstalled;
+
+ map_init(&userinstalled, 0);
+ queue_empty(q);
+ /* first process jobs */
+ for (i = 0; i < solv->job.count; i += 2)
+ {
+ Id how = solv->job.elements[i];
+ Id what, select;
+ if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+ {
+ if (!userinstalled.size)
+ map_grow(&userinstalled, installed->end - installed->start);
+ what = solv->job.elements[i + 1];
+ select = how & SOLVER_SELECTMASK;
+ if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+ {
+ FOR_REPO_SOLVABLES(installed, p, s)
+ MAPSET(&userinstalled, p - installed->start);
+ }
+ FOR_JOB_SELECT(p, pp, select, what)
+ if (pool->solvables[p].repo == installed)
+ MAPSET(&userinstalled, p - installed->start);
+ continue;
+ }
+ if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL)
+ continue;
+ if ((how & SOLVER_NOTBYUSER) != 0)
+ continue;
+ what = solv->job.elements[i + 1];
+ select = how & SOLVER_SELECTMASK;
+ FOR_JOB_SELECT(p, pp, select, what)
+ if (solv->decisionmap[p] > 0)
+ {
+ queue_push(q, p);
+#ifdef ENABLE_LINKED_PKGS
+ if (has_package_link(pool, pool->solvables + p))
+ {
+ int j;
+ Queue lq;
+ queue_init(&lq);
+ find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0);
+ for (j = 0; j < lq.count; j++)
+ if (solv->decisionmap[lq.elements[j]] > 0)
+ queue_push(q, lq.elements[j]);
+ }
+#endif
+ }
+ }
+ /* now process updates of userinstalled packages */
+ if (installed && userinstalled.size)
+ {
+ for (i = 1; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p <= 0)
+ continue;
+ s = pool->solvables + p;
+ if (!s->repo)
+ continue;
+ if (s->repo == installed)
+ {
+ if (MAPTST(&userinstalled, p - installed->start))
+ queue_push(q, p);
+ continue;
+ }
+ /* new package, check if we replace a userinstalled one */
+ FOR_PROVIDES(p2, pp, s->name)
+ {
+ Solvable *ps = pool->solvables + p2;
+ if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
+ continue;
+ if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
+ continue;
+ if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ queue_push(q, p);
+ break;
+ }
+ if (!p2 && s->repo != installed && s->obsoletes)
+ {
+ Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ {
+ FOR_PROVIDES(p2, pp, obs)
+ {
+ Solvable *ps = pool->solvables + p2;
+ if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
+ continue;
+ if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+ continue;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ queue_push(q, p);
+ break;
+ }
+ if (p2)
+ break;
+ }
+ }
+ }
+ }
+ map_free(&userinstalled);
+
+ /* convert to desired output format */
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ int qcount = q->count;
+ queue_insertn(q, 0, qcount, 0);
+ for (i = j = 0; i < qcount; i++)
+ {
+ s = pool->solvables + q->elements[i + qcount];
+ q->elements[j++] = s->name;
+ q->elements[j++] = s->arch;
+ }
+ }
+ else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ {
+ for (i = 0; i < q->count; i++)
+ {
+ s = pool->solvables + q->elements[i];
+ q->elements[i] = s->name;
+ }
+ }
+ /* sort and unify */
+ get_userinstalled_sort_uniq(pool, q, flags);
+
+ /* invert if asked for */
+ if ((flags & GET_USERINSTALLED_INVERTED) != 0)
+ {
+ /* first generate queue with all installed packages */
+ Queue invq;
+ queue_init(&invq);
+ for (i = 1; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p <= 0)
+ continue;
+ s = pool->solvables + p;
+ if (!s->repo)
+ continue;
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ queue_push2(&invq, s->name, s->arch);
+ else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ queue_push(&invq, s->name);
+ else
+ queue_push(&invq, p);
+ }
+ /* push q on invq, just in case... */
+ queue_insertn(&invq, invq.count, q->count, q->elements);
+ get_userinstalled_sort_uniq(pool, &invq, flags);
+ /* subtract queues (easy as they are sorted and invq is a superset of q) */
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ if (q->count)
+ {
+ for (i = j = 0; i < invq.count; i += 2)
+ if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1])
+ {
+ invq.elements[i] = invq.elements[i + 1] = 0;
+ j += 2;
+ if (j >= q->count)
+ break;
+ }
+ queue_empty(q);
+ }
+ for (i = 0; i < invq.count; i += 2)
+ if (invq.elements[i])
+ queue_push2(q, invq.elements[i], invq.elements[i + 1]);
+ }
+ else
+ {
+ if (q->count)
+ {
+ for (i = j = 0; i < invq.count; i++)
+ if (invq.elements[i] == q->elements[j])
+ {
+ invq.elements[i] = 0;
+ if (++j >= q->count)
+ break;
+ }
+ queue_empty(q);
+ }
+ for (i = 0; i < invq.count; i++)
+ if (invq.elements[i])
+ queue_push(q, invq.elements[i]);
+ }
+ queue_free(&invq);
+ }
+}
+
+void
+pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
+{
+ int i;
+
+ if ((flags & GET_USERINSTALLED_INVERTED) != 0)
+ {
+ Queue invq;
+ Id p, lastid;
+ Solvable *s;
+ int bad;
+ if (!pool->installed)
+ return;
+ queue_init(&invq);
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ flags &= ~GET_USERINSTALLED_NAMES; /* just in case */
+ FOR_REPO_SOLVABLES(pool->installed, p, s)
+ queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ /* for namearch we convert to packages */
+ namearch2solvables(pool, q, &invq, 0);
+ get_userinstalled_sort_uniq(pool, &invq, flags);
+ namearch2solvables(pool, q, &invq, 0);
+ flags = 0;
+ }
+ else
+ {
+ queue_insertn(&invq, invq.count, q->count, q->elements);
+ get_userinstalled_sort_uniq(pool, &invq, flags);
+ /* now the fun part, add q again, sort, and remove all dups */
+ queue_insertn(&invq, invq.count, q->count, q->elements);
+ }
+ if (invq.count > 1)
+ {
+ if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool);
+ else
+ solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0);
+ }
+ lastid = -1;
+ bad = 1;
+ for (i = 0; i < invq.count; i++)
+ {
+ if (invq.elements[i] == lastid)
+ {
+ bad = 1;
+ continue;
+ }
+ if (!bad)
+ queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
+ bad = 0;
+ lastid = invq.elements[i];
+ }
+ if (!bad)
+ queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
+ queue_free(&invq);
+ }
+ else
+ {
+ if (flags & GET_USERINSTALLED_NAMEARCH)
+ namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE);
+ else
+ {
+ for (i = 0; i < q->count; i++)
+ queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
+ }
+ }
+}
+