summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS13
-rw-r--r--VERSION.cmake2
-rw-r--r--ext/libsolvext.ver1
-rw-r--r--ext/repo_rpmdb.c2
-rw-r--r--ext/repo_rpmdb_bdb.h11
-rw-r--r--ext/repo_rpmdb_librpm.h34
-rw-r--r--ext/repo_updateinfoxml.c123
-rw-r--r--ext/repo_updateinfoxml.h3
-rw-r--r--ext/testcase.c2
-rw-r--r--package/libsolv.changes13
-rw-r--r--src/knownid.h4
-rw-r--r--src/libsolv.ver1
-rw-r--r--src/pool.c2
-rw-r--r--src/problems.c15
-rw-r--r--src/problems.h11
-rw-r--r--src/rules.c132
-rw-r--r--src/rules.h6
-rw-r--r--src/selection.c2
-rw-r--r--src/solvable.c41
-rw-r--r--src/solvable.h3
-rw-r--r--src/solver.c13
-rw-r--r--src/solver.h4
-rw-r--r--src/solverdebug.c2
-rw-r--r--src/transaction.c15
-rw-r--r--test/testcases/blacklist/ptf52
-rw-r--r--test/testcases/blacklist/retracted22
-rw-r--r--tools/repo2solv.c1
27 files changed, 491 insertions, 39 deletions
diff --git a/NEWS b/NEWS
index 19caab7..467547b 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,19 @@
This file contains the major changes between
libsolv versions:
+Version 0.7.8
+- selected bug fixes:
+ * support arch<->noarch package changes when creating patch
+ conflicts from the updateinfo data
+ * also support other rpm database types
+- new features:
+ * support for SOLVER_BLACKLIST jobs that block the installation
+ of matched packages unless they are directly selected by an
+ SOLVER_INSTALL job
+ * libsolv now also parses the patch status in the updateinfo
+ parser
+ * new solvable_matchessolvable() function
+
Version 0.7.7
- selected bug fixes:
* fix updating of too many packages in focusbest mode
diff --git a/VERSION.cmake b/VERSION.cmake
index 87c236c..491723a 100644
--- a/VERSION.cmake
+++ b/VERSION.cmake
@@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "1")
SET(LIBSOLV_MAJOR "0")
SET(LIBSOLV_MINOR "7")
-SET(LIBSOLV_PATCH "7")
+SET(LIBSOLV_PATCH "8")
diff --git a/ext/libsolvext.ver b/ext/libsolvext.ver
index ef028f0..02cf6d1 100644
--- a/ext/libsolvext.ver
+++ b/ext/libsolvext.ver
@@ -42,6 +42,7 @@ SOLV_1.0 {
repo_add_zyppdb_products;
repo_find_all_pubkeys;
repo_find_pubkey;
+ repo_mark_retracted_packages;
repo_verify_sigdata;
rpm_byfp;
rpm_byrpmdbid;
diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c
index fb1491b..e49188d 100644
--- a/ext/repo_rpmdb.c
+++ b/ext/repo_rpmdb.c
@@ -1605,7 +1605,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
}
/* XXX: should get ro lock of Packages database! */
- if (stat_database(&state, "Packages", &packagesstat, 1))
+ if (stat_database(&state, &packagesstat))
{
freestate(&state);
return -1;
diff --git a/ext/repo_rpmdb_bdb.h b/ext/repo_rpmdb_bdb.h
index ae477f7..574e9a8 100644
--- a/ext/repo_rpmdb_bdb.h
+++ b/ext/repo_rpmdb_bdb.h
@@ -57,7 +57,7 @@ struct rpmdbstate {
static int
-stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror)
+stat_database_name(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror)
{
char *dbpath;
dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname);
@@ -72,6 +72,13 @@ stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int
return 0;
}
+static int
+stat_database(struct rpmdbstate *state, struct stat *statbuf)
+{
+ return stat_database_name(state, "Packages", statbuf, 1);
+}
+
+
static inline Id
db2rpmdbid(unsigned char *db, int byteswapped)
{
@@ -426,7 +433,7 @@ count_headers(struct rpmdbstate *state)
DBT dbkey;
DBT dbdata;
- if (stat_database(state, "Name", &statbuf, 0))
+ if (stat_database_name(state, "Name", &statbuf, 0))
return 0;
memset(&dbkey, 0, sizeof(dbkey));
memset(&dbdata, 0, sizeof(dbdata));
diff --git a/ext/repo_rpmdb_librpm.h b/ext/repo_rpmdb_librpm.h
index 79983d3..6fdcfb0 100644
--- a/ext/repo_rpmdb_librpm.h
+++ b/ext/repo_rpmdb_librpm.h
@@ -31,18 +31,34 @@ struct rpmdbstate {
};
static int
-stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror)
+stat_database(struct rpmdbstate *state, struct stat *statbuf)
{
- char *dbpath;
- dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname);
- if (stat(dbpath, statbuf))
+ static const char *dbname[] = {
+ "Packages",
+ "Packages.db",
+ "rpmdb.sqlite",
+ "data.mdb",
+ "Packages", /* for error reporting */
+ 0,
+ };
+ int i;
+
+ for (i = 0; ; i++)
{
- if (seterror)
- pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
- free(dbpath);
- return -1;
+ char *dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname[i]);
+ if (!stat(dbpath, statbuf))
+ {
+ free(dbpath);
+ return 0;
+ }
+ if (errno != ENOENT || !dbname[i + 1])
+ {
+ pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
+ solv_free(dbpath);
+ return -1;
+ }
+ solv_free(dbpath);
}
- free(dbpath);
return 0;
}
diff --git a/ext/repo_updateinfoxml.c b/ext/repo_updateinfoxml.c
index f375727..5b980a1 100644
--- a/ext/repo_updateinfoxml.c
+++ b/ext/repo_updateinfoxml.c
@@ -220,7 +220,7 @@ startElement(struct solv_xmlparser *xmlp, int state, const char *name, const cha
*/
case STATE_UPDATE:
{
- const char *from = 0, *type = 0, *version = 0;
+ const char *from = 0, *type = 0, *version = 0, *status = 0;
for (; *atts; atts += 2)
{
if (!strcmp(*atts, "from"))
@@ -229,6 +229,8 @@ startElement(struct solv_xmlparser *xmlp, int state, const char *name, const cha
type = atts[1];
else if (!strcmp(*atts, "version"))
version = atts[1];
+ else if (!strcmp(*atts, "status"))
+ status = atts[1];
}
solvable = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
pd->handle = pd->solvable - pool->solvables;
@@ -238,6 +240,8 @@ startElement(struct solv_xmlparser *xmlp, int state, const char *name, const cha
solvable->arch = ARCH_NOARCH;
if (type)
repodata_set_str(pd->data, pd->handle, SOLVABLE_PATCHCATEGORY, type);
+ if (status)
+ repodata_set_poolstr(pd->data, pd->handle, UPDATE_STATUS, status);
pd->buildtime = (time_t)0;
}
break;
@@ -294,8 +298,7 @@ startElement(struct solv_xmlparser *xmlp, int state, const char *name, const cha
{
const char *arch = 0, *name = 0;
Id evr = makeevr_atts(pool, pd, atts); /* parse "epoch", "version", "release" */
- Id n, a = 0;
- Id rel_id;
+ Id n, a, id;
for (; *atts; atts += 2)
{
@@ -304,17 +307,24 @@ startElement(struct solv_xmlparser *xmlp, int state, const char *name, const cha
else if (!strcmp(*atts, "name"))
name = atts[1];
}
- /* generated Id for name */
- n = pool_str2id(pool, name, 1);
- rel_id = n;
- if (arch)
+ n = name ? pool_str2id(pool, name, 1) : 0;
+ a = arch ? pool_str2id(pool, arch, 1) : 0;
+
+ /* generated conflicts for the package */
+ if (a && a != ARCH_NOARCH)
+ {
+ id = pool_rel2id(pool, n, a, REL_ARCH, 1);
+ id = pool_rel2id(pool, id, evr, REL_LT, 1);
+ solvable->conflicts = repo_addid_dep(pd->repo, solvable->conflicts, id, 0);
+ id = pool_rel2id(pool, n, ARCH_NOARCH, REL_ARCH, 1);
+ id = pool_rel2id(pool, id, evr, REL_LT, 1);
+ solvable->conflicts = repo_addid_dep(pd->repo, solvable->conflicts, id, 0);
+ }
+ else
{
- /* generate Id for arch and combine with name */
- a = pool_str2id(pool, arch, 1);
- rel_id = pool_rel2id(pool, n, a, REL_ARCH, 1);
+ id = pool_rel2id(pool, n, evr, REL_LT, 1);
+ solvable->conflicts = repo_addid_dep(pd->repo, solvable->conflicts, id, 0);
}
- rel_id = pool_rel2id(pool, rel_id, evr, REL_LT, 1);
- solvable->conflicts = repo_addid_dep(pd->repo, solvable->conflicts, rel_id, 0);
/* who needs the collection anyway? */
pd->collhandle = repodata_new_handle(pd->data);
@@ -486,3 +496,92 @@ repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags)
return pd.ret;
}
+#ifdef SUSE
+
+static int
+repo_mark_retracted_packages_cmp(const void *ap, const void *bp, void *dp)
+{
+ Id *a = (Id *)ap;
+ Id *b = (Id *)bp;
+ if (a[1] != b[1])
+ return a[1] - b[1];
+ if (a[2] != b[2])
+ return a[2] - b[2];
+ if (a[0] != b[0])
+ return a[0] - b[0];
+ return 0;
+}
+
+
+void
+repo_mark_retracted_packages(Repo *repo, Id retractedmarker)
+{
+ Pool *pool = repo->pool;
+ int i, p;
+ Solvable *s;
+ Id con, *conp;
+ Id retractedname, retractedevr;
+
+ Queue q;
+ queue_init(&q);
+ for (p = 1; p < pool->nsolvables; p++)
+ {
+ const char *status;
+ s = pool->solvables + p;
+ if (strncmp(pool_id2str(pool, s->name), "patch:", 6) != 0)
+ {
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+ continue;
+ queue_push2(&q, p, s->name);
+ queue_push2(&q, s->evr, s->arch);
+ continue;
+ }
+ status = solvable_lookup_str(s, UPDATE_STATUS);
+ if (!status || strcmp(status, "retracted") != 0)
+ continue;
+ if (!s->conflicts)
+ continue;
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+ Reldep *rd;
+ Id name, evr, arch;
+ if (!ISRELDEP(con))
+ continue;
+ rd = GETRELDEP(pool, con);
+ if (rd->flags != REL_LT)
+ continue;
+ name = rd->name;
+ evr = rd->evr;
+ arch = 0;
+ if (ISRELDEP(name))
+ {
+ rd = GETRELDEP(pool, name);
+ name = rd->name;
+ if (rd->flags == REL_ARCH)
+ arch = rd->evr;
+ }
+ queue_push2(&q, 0, name);
+ queue_push2(&q, evr, arch);
+ }
+ }
+ if (q.count)
+ solv_sort(q.elements, q.count / 4, sizeof(Id) * 4, repo_mark_retracted_packages_cmp, repo->pool);
+ retractedname = retractedevr = 0;
+ for (i = 0; i < q.count; i += 4)
+ {
+ if (!q.elements[i])
+ {
+ retractedname = q.elements[i + 1];
+ retractedevr = q.elements[i + 2];
+ }
+ else if (q.elements[i + 1] == retractedname && q.elements[i + 2] == retractedevr)
+ {
+ s = pool->solvables + q.elements[i];
+ s->provides = repo_addid_dep(repo, s->provides, retractedmarker, 0);
+ }
+ }
+ queue_free(&q);
+}
+
+#endif
diff --git a/ext/repo_updateinfoxml.h b/ext/repo_updateinfoxml.h
index bd0a61b..c3da0f6 100644
--- a/ext/repo_updateinfoxml.h
+++ b/ext/repo_updateinfoxml.h
@@ -6,3 +6,6 @@
*/
extern int repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags);
+
+extern void repo_mark_retracted_packages(Repo *repo, Id retractedmarker);
+
diff --git a/ext/testcase.c b/ext/testcase.c
index bd0643a..d6c4a57 100644
--- a/ext/testcase.c
+++ b/ext/testcase.c
@@ -59,6 +59,7 @@ static struct job2str {
{ SOLVER_ALLOWUNINSTALL, "allowuninstall" },
{ SOLVER_FAVOR, "favor" },
{ SOLVER_DISFAVOR, "disfavor" },
+ { SOLVER_BLACKLIST, "blacklist" },
{ 0, 0 }
};
@@ -1190,6 +1191,7 @@ static struct rclass2str {
{ SOLVER_RULE_LEARNT, "learnt" },
{ SOLVER_RULE_BEST, "best" },
{ SOLVER_RULE_YUMOBS, "yumobs" },
+ { SOLVER_RULE_BLACK, "black" },
{ SOLVER_RULE_RECOMMENDS, "recommends" },
{ 0, 0 }
};
diff --git a/package/libsolv.changes b/package/libsolv.changes
index fbb4a72..e060b4d 100644
--- a/package/libsolv.changes
+++ b/package/libsolv.changes
@@ -1,4 +1,17 @@
-------------------------------------------------------------------
+Tue Nov 12 11:35:12 CET 2019 - mls@suse.de
+
+- support arch<->noarch package changes when creating patch
+ conflicts from the updateinfo data
+- support for SOLVER_BLACKLIST jobs that block the installation
+ of matched packages unless they are directly selected by an
+ SOLVER_INSTALL job
+- libsolv now also parses the patch status in the updateinfo
+ parser
+- new solvable_matchessolvable() function
+- bump version to 0.7.8
+
+-------------------------------------------------------------------
Fri Oct 18 10:53:54 CEST 2019 - mls@suse.de
- fix updating of too many packages in focusbest mode
diff --git a/src/knownid.h b/src/knownid.h
index 9d7f157..3a88ee2 100644
--- a/src/knownid.h
+++ b/src/knownid.h
@@ -261,6 +261,10 @@ KNOWNID(UPDATE_MODULE_ARCH, "update:module:arch"), /* architecture */
KNOWNID(SOLVABLE_BUILDVERSION, "solvable:buildversion"), /* conda */
KNOWNID(SOLVABLE_BUILDFLAVOR, "solvable:buildflavor"), /* conda */
+KNOWNID(UPDATE_STATUS, "update:status"), /* "stable", "testing", ...*/
+
+KNOWNID(LIBSOLV_SELF_DESTRUCT_PKG, "libsolv-self-destruct-pkg()"), /* this package will self-destruct on installation */
+
KNOWNID(ID_NUM_INTERNAL, 0)
#ifdef KNOWNID_INITIALIZE
diff --git a/src/libsolv.ver b/src/libsolv.ver
index eafe3e6..ee40d0a 100644
--- a/src/libsolv.ver
+++ b/src/libsolv.ver
@@ -325,6 +325,7 @@ SOLV_1.0 {
solvable_lookup_type;
solvable_lookup_void;
solvable_matchesdep;
+ solvable_matchessolvable;
solvable_selfprovidedep;
solvable_set_deparray;
solvable_set_id;
diff --git a/src/pool.c b/src/pool.c
index 76636a7..0b4b9dd 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -1542,7 +1542,7 @@ pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker
continue;
if (s->repo != pool->installed && !pool_installable(pool, s))
continue;
- if (solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff))
+ if (solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff, 0))
queue_push(q, p);
}
map_free(&missc);
diff --git a/src/problems.c b/src/problems.c
index 6f2ad4b..b46d624 100644
--- a/src/problems.c
+++ b/src/problems.c
@@ -719,6 +719,12 @@ convertsolution(Solver *solv, Id why, Queue *solutionq)
}
return;
}
+ if (why >= solv->blackrules && why < solv->blackrules_end)
+ {
+ queue_push(solutionq, SOLVER_SOLUTION_BLACK);
+ assert(solv->rules[why].p < 0);
+ queue_push(solutionq, -solv->rules[why].p);
+ }
}
/*
@@ -981,6 +987,8 @@ solver_solutionelement_extrajobflags(Solver *solv, Id problem, Id solution)
* -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
* SOLVER_SOLUTION_BEST pkgid
* -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ * SOLVER_SOLUTION_BLACK pkgid
+ * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
* SOLVER_SOLUTION_JOB jobidx
* -> remove job (jobidx - 1, jobidx) from job queue
* SOLVER_SOLUTION_POOLJOB jobidx
@@ -1331,6 +1339,8 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ
s = pool_tmpjoin(pool, "both package ", pool_solvid2str(pool, source), " and ");
s = pool_tmpjoin(pool, s, pool_solvid2str(pool, target), " obsolete ");
return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0);
+ case SOLVER_RULE_BLACK:
+ return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " can only be installed by a direct request");
default:
return "bad problem rule type";
}
@@ -1385,6 +1395,11 @@ solver_solutionelement2str(Solver *solv, Id p, Id rp)
else
return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the old version");
}
+ else if (p == SOLVER_SOLUTION_BLACK)
+ {
+ Solvable *s = pool->solvables + rp;
+ return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), 0);
+ }
else if (p > 0 && rp == 0)
return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
else if (p > 0 && rp > 0)
diff --git a/src/problems.h b/src/problems.h
index 37021e1..45e4e7c 100644
--- a/src/problems.h
+++ b/src/problems.h
@@ -22,11 +22,12 @@ extern "C" {
struct s_Solver;
-#define SOLVER_SOLUTION_JOB (0)
-#define SOLVER_SOLUTION_DISTUPGRADE (-1)
-#define SOLVER_SOLUTION_INFARCH (-2)
-#define SOLVER_SOLUTION_BEST (-3)
-#define SOLVER_SOLUTION_POOLJOB (-4)
+#define SOLVER_SOLUTION_JOB (0)
+#define SOLVER_SOLUTION_DISTUPGRADE (-1)
+#define SOLVER_SOLUTION_INFARCH (-2)
+#define SOLVER_SOLUTION_BEST (-3)
+#define SOLVER_SOLUTION_POOLJOB (-4)
+#define SOLVER_SOLUTION_BLACK (-5)
void solver_recordproblem(struct s_Solver *solv, Id rid);
void solver_fixproblem(struct s_Solver *solv, Id rid);
diff --git a/src/rules.c b/src/rules.c
index 57895c0..cb8d17d 100644
--- a/src/rules.c
+++ b/src/rules.c
@@ -498,6 +498,16 @@ add_package_link(Solver *solv, Solvable *s, Map *m, Queue *workq)
#ifdef ENABLE_COMPLEX_DEPS
+#ifdef SUSE
+static inline int
+suse_isptf(Pool *pool, Solvable *s)
+{
+ if (!strncmp("ptf-", pool_id2str(pool, s->name), 4))
+ return 1;
+ return 0;
+}
+#endif
+
static void
add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *workq, Map *m)
{
@@ -511,6 +521,10 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w
/* CNF expansion for requires, DNF + INVERT expansion for conflicts */
if (type == SOLVER_RULE_PKG_CONFLICTS)
flags |= CPLXDEPS_TODNF | CPLXDEPS_EXPAND | CPLXDEPS_INVERT;
+#ifdef SUSE
+ if (type == SOLVER_RULE_PKG_REQUIRES && suse_isptf(pool, pool->solvables + p))
+ flags |= CPLXDEPS_NAME; /* do not match provides */
+#endif
i = pool_normalize_complex_dep(pool, dep, &bq, flags);
/* handle special cases */
@@ -2101,6 +2115,97 @@ reenableduprule(Solver *solv, Id name)
}
}
+/***********************************************************************
+ ***
+ *** Black rule part
+ ***/
+
+static inline void
+disableblackrule(Solver *solv, Id p)
+{
+ Rule *r;
+ int i;
+ for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++)
+ if (r->p == -p)
+ solver_disablerule(solv, r);
+}
+
+static inline void
+reenableblackrule(Solver *solv, Id p)
+{
+ Pool *pool = solv->pool;
+ Rule *r;
+ int i;
+ for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++)
+ if (r->p == -p)
+ {
+ solver_enablerule(solv, r);
+ IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+ {
+ POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+ solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+ }
+ }
+}
+
+void
+solver_addblackrules(Solver *solv)
+{
+ int i;
+ Id how, select, what, p, pp;
+ Queue *job = &solv->job;
+ Pool *pool = solv->pool;
+ Repo *installed = solv->installed;
+ Map updatemap;
+
+ map_init(&updatemap, 0);
+ solv->blackrules = solv->nrules;
+ if (installed)
+ {
+ for (i = 0; i < job->count; i += 2)
+ {
+ how = job->elements[i];
+ select = job->elements[i] & SOLVER_SELECTMASK;
+ what = job->elements[i + 1];
+ switch (how & SOLVER_JOBMASK)
+ {
+ case SOLVER_BLACKLIST:
+ FOR_JOB_SELECT(p, pp, select, what)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo != installed)
+ continue;
+ if (!updatemap.size)
+ map_grow(&updatemap, pool->ss.nstrings);
+ if (s->name > 0 && s->name < pool->ss.nstrings)
+ MAPSET(&updatemap, s->name);
+ }
+ }
+ }
+ }
+ for (i = 0; i < job->count; i += 2)
+ {
+ how = job->elements[i];
+ select = job->elements[i] & SOLVER_SELECTMASK;
+ what = job->elements[i + 1];
+ switch (how & SOLVER_JOBMASK)
+ {
+ case SOLVER_BLACKLIST:
+ FOR_JOB_SELECT(p, pp, select, what)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo == installed)
+ continue;
+ if (updatemap.size && s->name > 0 && s->name < pool->ss.nstrings && MAPTST(&updatemap, s->name))
+ continue; /* installed package with same name is already blacklisted */
+ solver_addrule(solv, -p, 0, 0);
+ }
+ break;
+ }
+ }
+ map_free(&updatemap);
+ solv->blackrules_end = solv->nrules;
+}
/***********************************************************************
***
@@ -2114,6 +2219,7 @@ reenableduprule(Solver *solv, Id name)
#define DISABLE_UPDATE 1
#define DISABLE_INFARCH 2
#define DISABLE_DUP 3
+#define DISABLE_BLACK 4
static void
jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
@@ -2213,6 +2319,16 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
}
}
}
+ if ((set & SOLVER_SETEVR) != 0 && solv->blackrules != solv->blackrules_end)
+ {
+ if (select == SOLVER_SOLVABLE)
+ queue_push2(q, DISABLE_BLACK, what);
+ else
+ {
+ FOR_JOB_SELECT(p, pp, select, what)
+ queue_push2(q, DISABLE_BLACK, p);
+ }
+ }
if (!installed || installed->end == installed->start)
return;
/* now the hard part: disable some update rules */
@@ -2386,6 +2502,9 @@ solver_disablepolicyrules(Solver *solv)
case DISABLE_DUP:
disableduprule(solv, arg);
break;
+ case DISABLE_BLACK:
+ disableblackrule(solv, arg);
+ break;
default:
break;
}
@@ -2489,6 +2608,9 @@ solver_reenablepolicyrules(Solver *solv, int jobidx)
case DISABLE_DUP:
reenableduprule(solv, arg);
break;
+ case DISABLE_BLACK:
+ reenableblackrule(solv, arg);
+ break;
}
}
queue_free(&q);
@@ -2815,6 +2937,12 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
*depp = solv->yumobsrules_info[rid - solv->yumobsrules];
return SOLVER_RULE_YUMOBS;
}
+ if (rid >= solv->blackrules && rid < solv->blackrules_end)
+ {
+ if (fromp)
+ *fromp = -r->p;
+ return SOLVER_RULE_BLACK;
+ }
if (rid >= solv->choicerules && rid < solv->choicerules_end)
return SOLVER_RULE_CHOICE;
if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
@@ -2845,10 +2973,14 @@ solver_ruleclass(Solver *solv, Id rid)
return SOLVER_RULE_BEST;
if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
return SOLVER_RULE_YUMOBS;
+ if (rid >= solv->blackrules && rid < solv->blackrules_end)
+ return SOLVER_RULE_BLACK;
if (rid >= solv->choicerules && rid < solv->choicerules_end)
return SOLVER_RULE_CHOICE;
if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
return SOLVER_RULE_RECOMMENDS;
+ if (rid >= solv->blackrules && rid < solv->blackrules_end)
+ return SOLVER_RULE_BLACK;
if (rid >= solv->learntrules && rid < solv->nrules)
return SOLVER_RULE_LEARNT;
return SOLVER_RULE_UNKNOWN;
diff --git a/src/rules.h b/src/rules.h
index 6b8511f..9286090 100644
--- a/src/rules.h
+++ b/src/rules.h
@@ -72,7 +72,8 @@ typedef enum {
SOLVER_RULE_LEARNT = 0x800,
SOLVER_RULE_BEST = 0x900,
SOLVER_RULE_YUMOBS = 0xa00,
- SOLVER_RULE_RECOMMENDS = 0xb00
+ SOLVER_RULE_RECOMMENDS = 0xb00,
+ SOLVER_RULE_BLACK = 0xc00
} SolverRuleinfo;
#define SOLVER_RULE_TYPEMASK 0xff00
@@ -134,6 +135,9 @@ extern void solver_addbestrules(struct s_Solver *solv, int havebestinstalljobs,
/* yumobs rules */
extern void solver_addyumobsrules(struct s_Solver *solv);
+/* black rules */
+extern void solver_addblackrules(struct s_Solver *solv);
+
/* recommends rules */
extern void solver_addrecommendsrules(struct s_Solver *solv);
diff --git a/src/selection.c b/src/selection.c
index e58d731..5f01e2b 100644
--- a/src/selection.c
+++ b/src/selection.c
@@ -1502,7 +1502,7 @@ selection_make_matchsolvable_common(Pool *pool, Queue *selection, Queue *solvidq
continue;
if (!solvable_matches_selection_flags(pool, s, flags))
continue;
- if (solvable_matchessolvable_int(s, keyname, marker, solvid, solvidq ? &m : 0, &q, &missc, reloff))
+ if (solvable_matchessolvable_int(s, keyname, marker, solvid, solvidq ? &m : 0, &q, &missc, reloff, 0))
queue_push(selection, p);
}
queue_free(&q);
diff --git a/src/solvable.c b/src/solvable.c
index d3d2d31..474e6f5 100644
--- a/src/solvable.c
+++ b/src/solvable.c
@@ -645,7 +645,7 @@ solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker)
}
int
-solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff)
+solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff, Queue *outdepq)
{
Pool *pool = s->repo->pool;
int i, boff;
@@ -653,6 +653,8 @@ solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map
if (depq->count)
queue_empty(depq);
+ if (outdepq && outdepq->count)
+ queue_empty(outdepq);
solvable_lookup_deparray(s, keyname, depq, marker);
for (i = 0; i < depq->count; i++)
{
@@ -695,15 +697,46 @@ solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map
{
for (; *wp; wp++)
if (MAPTST(solvidmap, *wp))
- return 1;
+ break;
}
else
{
for (; *wp; wp++)
if (*wp == solvid)
- return 1;
+ break;
+ }
+ if (*wp)
+ {
+ if (outdepq)
+ {
+ queue_pushunique(outdepq, dep);
+ continue;
+ }
+ return 1;
}
MAPSET(missc, boff);
}
- return 0;
+ return outdepq && outdepq->count ? 1 : 0;
+}
+
+int
+solvable_matchessolvable(Solvable *s, Id keyname, Id solvid, Queue *depq, int marker)
+{
+ Pool *pool = s->repo->pool;
+ Map missc; /* cache for misses */
+ int res, reloff;
+ Queue qq;
+
+ if (depq && depq->count)
+ queue_empty(depq);
+ if (s - pool->solvables == solvid)
+ return 0; /* no self-matches */
+
+ queue_init(&qq);
+ reloff = pool->ss.nstrings;
+ map_init(&missc, reloff + pool->nrels);
+ res = solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff, depq);
+ map_free(&missc);
+ queue_free(&qq);
+ return res;
}
diff --git a/src/solvable.h b/src/solvable.h
index bf92a00..7788e7c 100644
--- a/src/solvable.h
+++ b/src/solvable.h
@@ -81,9 +81,10 @@ int solvable_identical(Solvable *s1, Solvable *s2);
Id solvable_selfprovidedep(Solvable *s);
int solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker);
+int solvable_matchessolvable(Solvable *s, Id keyname, Id solvid, Queue *depq, int marker);
/* internal */
-int solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff);
+int solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff, Queue *outdepq);
/* weird suse stuff */
diff --git a/src/solver.c b/src/solver.c
index 45f9dbf..6a9d66e 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -3377,6 +3377,7 @@ solver_solve(Solver *solv, Queue *job)
int hasbestinstalljob = 0;
int hasfavorjob = 0;
int haslockjob = 0;
+ int hasblacklistjob = 0;
solve_start = solv_timems(0);
@@ -3987,6 +3988,10 @@ solver_solve(Solver *solv, Queue *job)
POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s %s\n", (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? "favor" : "disfavor", solver_select2str(pool, select, what));
hasfavorjob = 1;
break;
+ case SOLVER_BLACKLIST:
+ POOL_DEBUG(SOLV_DEBUG_JOB, "job: blacklist %s\n", solver_select2str(pool, select, what));
+ hasblacklistjob = 1;
+ break;
default:
POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
break;
@@ -4040,6 +4045,11 @@ solver_solve(Solver *solv, Queue *job)
else
solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
+ if (hasblacklistjob)
+ solver_addblackrules(solv);
+ else
+ solv->blackrules = solv->blackrules_end = solv->nrules;
+
if (solv->havedisfavored && solv->strongrecommends && solv->recommendsruleq)
solver_addrecommendsrules(solv);
else
@@ -4851,6 +4861,9 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
case SOLVER_DISFAVOR:
strstart = "disfavor ";
break;
+ case SOLVER_BLACKLIST:
+ strstart = "blacklist ";
+ break;
default:
strstart = "unknown job ";
break;
diff --git a/src/solver.h b/src/solver.h
index daf4f63..2dec259 100644
--- a/src/solver.h
+++ b/src/solver.h
@@ -76,6 +76,9 @@ struct s_Solver {
Id yumobsrules_end;
Id *yumobsrules_info; /* the dependency for each rule */
+ Id blackrules; /* rules from blacklisted packages */
+ Id blackrules_end;
+
Id choicerules; /* choice rules (always weak) */
Id choicerules_end;
Id *choicerules_info; /* the rule we used to generate the choice rule */
@@ -244,6 +247,7 @@ typedef struct s_Solver Solver;
#define SOLVER_ALLOWUNINSTALL 0x0b00
#define SOLVER_FAVOR 0x0c00
#define SOLVER_DISFAVOR 0x0d00
+#define SOLVER_BLACKLIST 0x0e00
#define SOLVER_JOBMASK 0xff00
diff --git a/src/solverdebug.c b/src/solverdebug.c
index b1b55f4..0b2879b 100644
--- a/src/solverdebug.c
+++ b/src/solverdebug.c
@@ -128,6 +128,8 @@ solver_printruleclass(Solver *solv, int type, Rule *r)
POOL_DEBUG(type, "FEATURE ");
else if (p >= solv->yumobsrules && p < solv->yumobsrules_end)
POOL_DEBUG(type, "YUMOBS ");
+ else if (p >= solv->blackrules && p < solv->blackrules_end)
+ POOL_DEBUG(type, "BLACK ");
else if (p >= solv->recommendsrules && p < solv->recommendsrules_end)
POOL_DEBUG(type, "RECOMMENDS ");
solver_printrule(solv, type, r);
diff --git a/src/transaction.c b/src/transaction.c
index 4a4189e..fb2cc9a 100644
--- a/src/transaction.c
+++ b/src/transaction.c
@@ -646,6 +646,8 @@ create_transaction_info(Transaction *trans, Queue *decisionq)
s = pool->solvables + p;
if (!s->repo || s->repo == installed)
continue;
+ if (!MAPTST(&trans->transactsmap, p))
+ continue;
multi = trans->multiversionmap.size && MAPTST(&trans->multiversionmap, p);
FOR_PROVIDES(p2, pp2, s->name)
{
@@ -726,9 +728,10 @@ transaction_create_decisionq(Pool *pool, Queue *decisionq, Map *multiversionmap)
{
Repo *installed = pool->installed;
int i, needmulti;
- Id p;
+ Id p, pp;
Solvable *s;
Transaction *trans;
+ Map selfdestructmap;
trans = transaction_create(pool);
if (multiversionmap && !multiversionmap->size)
@@ -736,6 +739,13 @@ transaction_create_decisionq(Pool *pool, Queue *decisionq, Map *multiversionmap)
queue_empty(&trans->steps);
map_init(&trans->transactsmap, pool->nsolvables);
needmulti = 0;
+ map_init(&selfdestructmap, 0);
+ FOR_PROVIDES(p, pp, LIBSOLV_SELF_DESTRUCT_PKG)
+ {
+ if (!selfdestructmap.size)
+ map_grow(&selfdestructmap, pool->nsolvables);
+ MAPSET(&selfdestructmap, p);
+ }
for (i = 0; i < decisionq->count; i++)
{
p = decisionq->elements[i];
@@ -746,11 +756,14 @@ transaction_create_decisionq(Pool *pool, Queue *decisionq, Map *multiversionmap)
MAPSET(&trans->transactsmap, -p);
if (!(installed && s->repo == installed) && p > 0)
{
+ if (selfdestructmap.size && MAPTST(&selfdestructmap, p))
+ continue;
MAPSET(&trans->transactsmap, p);
if (multiversionmap && MAPTST(multiversionmap, p))
needmulti = 1;
}
}
+ map_free(&selfdestructmap);
MAPCLR(&trans->transactsmap, SYSTEMSOLVABLE);
if (needmulti)
map_init_clone(&trans->multiversionmap, multiversionmap);
diff --git a/test/testcases/blacklist/ptf b/test/testcases/blacklist/ptf
new file mode 100644
index 0000000..b8765d0
--- /dev/null
+++ b/test/testcases/blacklist/ptf
@@ -0,0 +1,52 @@
+repo system 0 testtags <inline>
+#>=Pkg: ptf-2 1 1 noarch
+#>=Prv: ptf-package()
+repo available 0 testtags <inline>
+#>=Pkg: ptf-1 1 1 noarch
+#>=Prv: ptf-package()
+#>=Pkg: ptf-2 2 1 noarch
+#>=Prv: ptf-package()
+#>=Pkg: A 1 1 noarch
+#>=Req: ptf-1
+
+system i686 * system
+
+#
+# test 1: a ptf package cannot be pulled in via a dependency
+#
+job blacklist provides ptf-package()
+job install name A
+result transaction,problems <inline>
+#>problem 78613afb info package A-1-1.noarch requires ptf-1, but none of the providers can be installed
+#>problem 78613afb solution 23f73f5b deljob install name A
+#>problem 78613afb solution b79aeb6f allow ptf-1-1-1.noarch@available
+
+#
+# test 2: a ptf package cannot be pulled in via a unspecific job
+#
+nextjob
+job blacklist provides ptf-package()
+job install name ptf-1
+result transaction,problems <inline>
+#>problem 021b17e2 info package ptf-1-1-1.noarch cannot only be installed by a direct request
+#>problem 021b17e2 solution 932a6c2f deljob install name ptf-1
+#>problem 021b17e2 solution b79aeb6f allow ptf-1-1-1.noarch@available
+
+#
+# test 3: a ptf package can be pulled in via a specific job
+#
+nextjob
+job blacklist provides ptf-package()
+job install name ptf-1 [setevr]
+result transaction,problems <inline>
+#>install ptf-1-1-1.noarch@available
+
+#
+# test 4: a ptf package can be updated
+#
+nextjob
+job blacklist provides ptf-package()
+job update all packages
+result transaction,problems <inline>
+#>upgrade ptf-2-1-1.noarch@system ptf-2-2-1.noarch@available
+
diff --git a/test/testcases/blacklist/retracted b/test/testcases/blacklist/retracted
new file mode 100644
index 0000000..d75f17d
--- /dev/null
+++ b/test/testcases/blacklist/retracted
@@ -0,0 +1,22 @@
+repo system 0 testtags <inline>
+#>=Pkg: B 1 1 noarch
+repo available 0 testtags <inline>
+#>=Pkg: patch 1 1 noarch
+#>=Con: B < 2-1
+#>=Pkg: B 2 1 noarch
+#>=Prv: retracted-patch-package()
+
+system i686 * system
+
+job blacklist provides retracted-patch-package()
+job install name patch
+#>problem 3a66200a info package patch-1-1.noarch conflicts with B < 2-1 provided by B-1-1.noarch
+#>problem 3a66200a solution 14805cf8 deljob install name patch
+#>problem 3a66200a solution 4a9277b8 allow B-2-1.noarch@available
+#>problem 3a66200a solution 718064ed erase B-1-1.noarch@system
+
+nextjob
+job blacklist provides retracted-patch-package()
+job install pkg B-2-1.noarch@available
+result transaction,problems <inline>
+#>upgrade B-1-1.noarch@system B-2-1.noarch@available
diff --git a/tools/repo2solv.c b/tools/repo2solv.c
index 03491a6..b390743 100644
--- a/tools/repo2solv.c
+++ b/tools/repo2solv.c
@@ -868,6 +868,7 @@ main(int argc, char **argv)
#ifdef SUSE
if (add_auto)
repo_add_autopattern(repo, 0);
+ repo_mark_retracted_packages(repo, pool_str2id(pool, "retracted-patch-package()", 1));
#endif
tool_write(repo, stdout);
pool_free(pool);