From f1a786b6fe3fc2d53f03b25e303dc45ed7e22ba6 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Fri, 27 Nov 2020 14:44:21 +0900 Subject: [PATCH 1/1] Imported Upstream version 0.7.8 --- NEWS | 13 ++++ VERSION.cmake | 2 +- ext/libsolvext.ver | 1 + ext/repo_rpmdb.c | 2 +- ext/repo_rpmdb_bdb.h | 11 +++- ext/repo_rpmdb_librpm.h | 34 +++++++--- ext/repo_updateinfoxml.c | 123 ++++++++++++++++++++++++++++++---- ext/repo_updateinfoxml.h | 3 + ext/testcase.c | 2 + package/libsolv.changes | 13 ++++ src/knownid.h | 4 ++ src/libsolv.ver | 1 + src/pool.c | 2 +- src/problems.c | 15 +++++ src/problems.h | 11 ++-- src/rules.c | 132 +++++++++++++++++++++++++++++++++++++ src/rules.h | 6 +- src/selection.c | 2 +- src/solvable.c | 41 ++++++++++-- src/solvable.h | 3 +- src/solver.c | 13 ++++ src/solver.h | 4 ++ src/solverdebug.c | 2 + src/transaction.c | 15 ++++- test/testcases/blacklist/ptf | 52 +++++++++++++++ test/testcases/blacklist/retracted | 22 +++++++ tools/repo2solv.c | 1 + 27 files changed, 491 insertions(+), 39 deletions(-) create mode 100644 test/testcases/blacklist/ptf create mode 100644 test/testcases/blacklist/retracted 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 +#>=Pkg: ptf-2 1 1 noarch +#>=Prv: ptf-package() +repo available 0 testtags +#>=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 +#>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 +#>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 +#>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 +#>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 +#>=Pkg: B 1 1 noarch +repo available 0 testtags +#>=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 +#>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); -- 2.7.4