diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2016-10-27 14:54:23 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2016-10-27 14:54:24 +0900 |
commit | 1a93853889c819ac2d3c8e83e856f4775e664b00 (patch) | |
tree | 283fb5892b7e064fb16c1f192bc61c86110f31c2 | |
parent | 8a7ffe4fc2b44b84fb045f80c1a016b3f200aa8b (diff) | |
download | libsolv-1a93853889c819ac2d3c8e83e856f4775e664b00.tar.gz libsolv-1a93853889c819ac2d3c8e83e856f4775e664b00.tar.bz2 libsolv-1a93853889c819ac2d3c8e83e856f4775e664b00.zip |
Imported Upstream version 0.6.11upstream/0.6.11
Change-Id: Ia7fcc570c551205421c68cc6feb2ecfd3c97e149
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
42 files changed, 1523 insertions, 825 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ab3fec9..45422af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,8 @@ OPTION (ENABLE_CUDFREPO "Build with cudf repository support?" OFF) OPTION (ENABLE_HAIKU "Build with Haiku package support?" OFF) OPTION (ENABLE_APPDATA "Build with AppStream appdata support?" OFF) +OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OFF) + OPTION (ENABLE_LZMA_COMPRESSION "Build with lzma/xz compression support?" OFF) OPTION (ENABLE_BZIP2_COMPRESSION "Build with bzip2 compression support?" OFF) @@ -206,6 +208,22 @@ CHECK_FUNCTION_EXISTS (fopencookie HAVE_FOPENCOOKIE) CHECK_FUNCTION_EXISTS (funopen HAVE_FUNOPEN) TEST_BIG_ENDIAN (WORDS_BIGENDIAN) +IF (${CMAKE_MAJOR_VERSION} GREATER 2) +INCLUDE (CMakePushCheckState) +INCLUDE (CheckCCompilerFlag) +MACRO (check_linker_flag FLAG VAR) + CMAKE_PUSH_CHECK_STATE (RESET) + SET (CMAKE_REQUIRED_FLAGS "${FLAG}") + CHECK_C_COMPILER_FLAG ("" "${VAR}") + CMAKE_POP_CHECK_STATE () +ENDMACRO (check_linker_flag) +check_linker_flag("-Wl,--as-needed" HAVE_LINKER_AS_NEEDED) +check_linker_flag("-Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver" HAVE_LINKER_VERSION_SCRIPT) +ELSE (${CMAKE_MAJOR_VERSION} GREATER 2) +SET (HAVE_LINKER_AS_NEEDED 1) +SET (HAVE_LINKER_VERSION_SCRIPT 1) +ENDIF (${CMAKE_MAJOR_VERSION} GREATER 2) + # should create config.h with #cmakedefine instead... FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN HAVE_RPM_DB_H HAVE_PGPDIGGETPARAMS @@ -307,7 +325,9 @@ ENDIF (ENABLE_RPMDB) IF (ENABLE_HAIKU) SET (SYSTEM_LIBRARIES ${HAIKU_SYSTEM_LIBRARIES} ${SYSTEM_LIBRARIES}) ENDIF (ENABLE_HAIKU) +IF (HAVE_LINKER_AS_NEEDED) SET (SYSTEM_LIBRARIES "-Wl,--as-needed" ${SYSTEM_LIBRARIES}) +ENDIF (HAVE_LINKER_AS_NEEDED) ADD_SUBDIRECTORY (src) ADD_SUBDIRECTORY (ext) diff --git a/VERSION.cmake b/VERSION.cmake index 92a1b90..fe0632b 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "0") SET(LIBSOLV_MAJOR "0") SET(LIBSOLV_MINOR "6") -SET(LIBSOLV_PATCH "10") +SET(LIBSOLV_PATCH "11") diff --git a/bindings/solv.i b/bindings/solv.i index 50f0b50..4030796 100644 --- a/bindings/solv.i +++ b/bindings/solv.i @@ -2801,6 +2801,7 @@ rb_eval_string( static const int SOLVER_FLAG_BREAK_ORPHANS = SOLVER_FLAG_BREAK_ORPHANS; static const int SOLVER_FLAG_FOCUS_INSTALLED = SOLVER_FLAG_FOCUS_INSTALLED; static const int SOLVER_FLAG_YUM_OBSOLETES = SOLVER_FLAG_YUM_OBSOLETES; + static const int SOLVER_FLAG_NEED_UPDATEPROVIDE = SOLVER_FLAG_NEED_UPDATEPROVIDE; static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED; static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE; diff --git a/cmake/modules/FindRuby.cmake b/cmake/modules/FindRuby.cmake index 17ad7ef..827a7a6 100644 --- a/cmake/modules/FindRuby.cmake +++ b/cmake/modules/FindRuby.cmake @@ -112,7 +112,7 @@ IF(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR) _RUBY_CONFIG_VAR("sitelibdir" RUBY_SITELIB_DIR) # vendor_ruby available ? - EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print 'true' unless Config::CONFIG['vendorarchdir'].nil?" + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print 'true' unless RbConfig::CONFIG['vendorarchdir'].nil?" OUTPUT_VARIABLE RUBY_HAS_VENDOR_RUBY ERROR_QUIET) IF(RUBY_HAS_VENDOR_RUBY) diff --git a/doc/libsolv-constantids.3 b/doc/libsolv-constantids.3 index 8511667..a079793 100644 --- a/doc/libsolv-constantids.3 +++ b/doc/libsolv-constantids.3 @@ -2,12 +2,12 @@ .\" Title: Libsolv-Constantids .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/> -.\" Date: 01/21/2014 +.\" Date: 03/19/2015 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "LIBSOLV\-CONSTANTIDS" "3" "01/21/2014" "libsolv" "LIBSOLV" +.TH "LIBSOLV\-CONSTANTIDS" "3" "03/19/2015" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -89,7 +89,7 @@ Stores an array of dependency Ids that describe the capabilities that also must .PP \fBSOLVABLE_RECOMMENDS "solvable:recommends"\fR .RS 4 -Stores an array of dependency Ids that describe the capabilities that also should be installed when this package is installed\&. It\(cqs not an error if not all capabilities can be met\&. +Stores an array of dependency Ids that describe the capabilities that also should be installed when this package is installed\&. It\(cqs not an error if not all capabilites can be met\&. .RE .PP \fBSOLVABLE_SUGGESTS "solvable:suggests"\fR @@ -541,11 +541,6 @@ Namespaces are special modifiers that change the meaning of a dependency\&. Name .sp The dependency markers partition the dependency array in two parts with different semantics\&. .PP -\fBNAMESPACE_INSTALLED "namespace:installed"\fR -.RS 4 -The dependency only selects installed packages\&. -.RE -.PP \fBNAMESPACE_MODALIAS "namespace:modalias"\fR .RS 4 The dependency is a special modalias dependency that matches installed hardware\&. diff --git a/doc/libsolv-constantids.txt b/doc/libsolv-constantids.txt index 7426b8f..7a83b46 100644 --- a/doc/libsolv-constantids.txt +++ b/doc/libsolv-constantids.txt @@ -400,9 +400,6 @@ custom namespaces work you have to implement a namespace callback function. The dependency markers partition the dependency array in two parts with different semantics. -*NAMESPACE_INSTALLED "namespace:installed"*:: - The dependency only selects installed packages. - *NAMESPACE_MODALIAS "namespace:modalias"*:: The dependency is a special modalias dependency that matches installed hardware. diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index bdf949d..360c7dc 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -43,10 +43,13 @@ IF (ENABLE_SUSEREPO) repo_susetags.h repo_zyppdb.h) ENDIF (ENABLE_SUSEREPO) -IF (ENABLE_COMPLEX_DEPS AND (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB)) +# old cmake does not support parenthetical expressions... +IF (ENABLE_COMPLEX_DEPS) +IF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB) SET (libsolvext_SRCS ${libsolvext_SRCS} pool_parserpmrichdep.c) -ENDIF (ENABLE_COMPLEX_DEPS AND (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB)) +ENDIF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB) +ENDIF (ENABLE_COMPLEX_DEPS) IF (SUSE) SET (libsolvext_SRCS ${libsolvext_SRCS} @@ -112,7 +115,9 @@ IF (ENABLE_APPDATA) ENDIF (ENABLE_APPDATA) SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") +IF (HAVE_LINKER_VERSION_SCRIPT) SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/ext/libsolvext.ver") +ENDIF (HAVE_LINKER_VERSION_SCRIPT) IF (DISABLE_SHARED) ADD_LIBRARY (libsolvext STATIC ${libsolvext_SRCS}) diff --git a/ext/repo_deb.c b/ext/repo_deb.c index 05d731b..26c73b0 100644 --- a/ext/repo_deb.c +++ b/ext/repo_deb.c @@ -655,7 +655,9 @@ pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags) l = 0; if (name && autoinstalled > 0) { - if ((flags & GET_USERINSTALLED_NAMES) != 0) + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) + queue_push2(q, name, arch); + else if ((flags & GET_USERINSTALLED_NAMES) != 0) queue_push(q, name); else { diff --git a/ext/testcase.c b/ext/testcase.c index f0057e6..251cd2f 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -78,6 +78,8 @@ static struct resultflags2str { { TESTCASE_RESULT_RECOMMENDED, "recommended" }, { TESTCASE_RESULT_UNNEEDED, "unneeded" }, { TESTCASE_RESULT_ALTERNATIVES, "alternatives" }, + { TESTCASE_RESULT_RULES, "rules" }, + { TESTCASE_RESULT_GENID, "genid" }, { 0, 0 } }; @@ -107,6 +109,7 @@ static struct solverflags2str { { SOLVER_FLAG_BREAK_ORPHANS, "breakorphans", 0 }, { SOLVER_FLAG_FOCUS_INSTALLED, "focusinstalled", 0 }, { SOLVER_FLAG_YUM_OBSOLETES, "yumobsoletes", 0 }, + { SOLVER_FLAG_NEED_UPDATEPROVIDE, "needupdateprovide", 0 }, { 0, 0, 0 } }; @@ -125,6 +128,7 @@ static struct poolflags2str { { POOL_FLAG_HAVEDISTEPOCH, "havedistepoch", 0 }, { POOL_FLAG_NOOBSOLETESMULTIVERSION, "noobsoletesmultiversion", 0 }, { POOL_FLAG_ADDFILEPROVIDESFILTERED, "addfileprovidesfiltered", 0 }, + { POOL_FLAG_NOWHATPROVIDESAUX, "nowhatprovidesaux", 0 }, { 0, 0, 0 } }; @@ -158,6 +162,15 @@ static struct selflags2str { { 0, 0 } }; +static const char *features[] = { +#ifdef ENABLE_LINKED_PACKAGES + "linked_packages", +#endif +#ifdef ENABLE_COMPLEX_DEPS + "complex_deps", +#endif + 0 +}; typedef struct strqueue { char **str; @@ -322,13 +335,13 @@ testcase_id2str(Pool *pool, Id id, int isname) /* we need escaping! */ s2 = s2p = pool_alloctmpspace(pool, strlen(s) + bad * 2 + 1); - ss = s; if (!strncmp(s, "namespace:", 10)) { strcpy(s2p, "namespace\\3a"); s2p += 12; s += 10; } + ss = s; for (; *ss; ss++) { *s2p++ = *ss; @@ -1668,6 +1681,33 @@ static struct class2str { { 0, 0 } }; +static int +dump_genid(Pool *pool, Strqueue *sq, Id id, int cnt) +{ + struct oplist *op; + char cntbuf[20]; + const char *s; + + if (ISRELDEP(id)) + { + Reldep *rd = GETRELDEP(pool, id); + for (op = oplist; op->flags; op++) + if (rd->flags == op->flags) + break; + cnt = dump_genid(pool, sq, rd->name, cnt); + cnt = dump_genid(pool, sq, rd->evr, cnt); + sprintf(cntbuf, "genid %2d: genid ", cnt++); + s = pool_tmpjoin(pool, cntbuf, "op ", op->flags ? op->opname : "unknown"); + } + else + { + sprintf(cntbuf, "genid %2d: genid ", cnt++); + s = pool_tmpjoin(pool, cntbuf, id ? "lit " : "null", id ? pool_id2str(pool, id) : 0); + } + strqueue_push(sq, s); + return cnt; +} + char * testcase_solverresult(Solver *solv, int resultflags) { @@ -1874,7 +1914,90 @@ testcase_solverresult(Solver *solv, int resultflags) queue_free(&q); queue_free(&rq); } + if ((resultflags & TESTCASE_RESULT_RULES) != 0) + { + /* dump all rules */ + Id rid; + SolverRuleinfo rclass; + Queue q; + int i; + queue_init(&q); + for (rid = 1; (rclass = solver_ruleclass(solv, rid)) != SOLVER_RULE_UNKNOWN; rid++) + { + char *prefix; + switch (rclass) + { + case SOLVER_RULE_PKG: + prefix = "pkg "; + break; + case SOLVER_RULE_UPDATE: + prefix = "update "; + break; + case SOLVER_RULE_FEATURE: + prefix = "feature "; + break; + case SOLVER_RULE_JOB: + prefix = "job "; + break; + case SOLVER_RULE_DISTUPGRADE: + prefix = "distupgrade "; + break; + case SOLVER_RULE_INFARCH: + prefix = "infarch "; + break; + case SOLVER_RULE_CHOICE: + prefix = "choice "; + break; + case SOLVER_RULE_LEARNT: + prefix = "learnt "; + break; + case SOLVER_RULE_BEST: + prefix = "best "; + break; + case SOLVER_RULE_YUMOBS: + prefix = "yumobs "; + break; + default: + prefix = "unknown "; + break; + } + prefix = solv_dupjoin("rule ", prefix, testcase_ruleid(solv, rid)); + solver_ruleliterals(solv, rid, &q); + if (rclass == SOLVER_RULE_FEATURE && q.count == 1 && q.elements[0] == -SYSTEMSOLVABLE) + continue; + for (i = 0; i < q.count; i++) + { + Id p = q.elements[i]; + const char *s; + if (p < 0) + s = pool_tmpjoin(pool, prefix, " -", testcase_solvid2str(pool, -p)); + else + s = pool_tmpjoin(pool, prefix, " ", testcase_solvid2str(pool, p)); + strqueue_push(&sq, s); + } + solv_free(prefix); + } + queue_free(&q); + } + if ((resultflags & TESTCASE_RESULT_GENID) != 0) + { + for (i = 0 ; i < solv->job.count; i += 2) + { + Id id, id2; + if (solv->job.elements[i] != (SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES)) + continue; + id = solv->job.elements[i + 1]; + s = testcase_dep2str(pool, id); + strqueue_push(&sq, pool_tmpjoin(pool, "genid dep ", s, 0)); + if ((id2 = testcase_str2dep(pool, s)) != id) + { + s = pool_tmpjoin(pool, "genid roundtrip error: ", testcase_dep2str(pool, id2), 0); + strqueue_push(&sq, s); + } + dump_genid(pool, &sq, id, 1); + } + } strqueue_sort(&sq); result = strqueue_join(&sq); strqueue_free(&sq); @@ -2221,6 +2344,9 @@ testcase_read(Pool *pool, FILE *fp, char *testcase, Queue *job, char **resultp, int prepared = 0; int closefp = !fp; int poolflagsreset = 0; + int missing_features = 0; + Id *genid = 0; + int ngenid = 0; if (!fp && !(fp = fopen(testcase, "r"))) { @@ -2343,20 +2469,38 @@ testcase_read(Pool *pool, FILE *fp, char *testcase, Queue *job, char **resultp, else if (!strcmp(pieces[0], "system") && npieces >= 3) { int i; - prepared = 0; + /* must set the disttype before the arch */ - for (i = 0; disttype2str[i].str != 0; i++) - if (!strcmp(disttype2str[i].str, pieces[2])) - break; - if (!disttype2str[i].str) - pool_debug(pool, SOLV_ERROR, "testcase_read: system: unknown disttype '%s'\n", pieces[2]); - else if (pool->disttype != disttype2str[i].type) + prepared = 0; + if (strcmp(pieces[2], "*") != 0) { + char *dp = pieces[2]; + while (dp && *dp) + { + char *dpe = strchr(dp, ','); + if (dpe) + *dpe = 0; + for (i = 0; disttype2str[i].str != 0; i++) + if (!strcmp(disttype2str[i].str, dp)) + break; + if (dpe) + *dpe++ = ','; + if (disttype2str[i].str) + { #ifdef MULTI_SEMANTICS - pool_setdisttype(pool, disttype2str[i].type); -#else - pool_debug(pool, SOLV_ERROR, "testcase_read: system: cannot change disttype to '%s'\n", pieces[2]); + if (pool->disttype != disttype2str[i].type) + pool_setdisttype(pool, disttype2str[i].type); #endif + if (pool->disttype == disttype2str[i].type) + break; + } + dp = dpe; + } + if (!(dp && *dp)) + { + pool_debug(pool, SOLV_ERROR, "testcase_read: system: could not change disttype to '%s'\n", pieces[2]); + missing_features = 1; + } } if (strcmp(pieces[1], "unset") == 0) pool_setarch(pool, 0); @@ -2511,11 +2655,75 @@ testcase_read(Pool *pool, FILE *fp, char *testcase, Queue *job, char **resultp, else pool_debug(pool, SOLV_ERROR, "disable: unknown package '%s'\n", pieces[2]); } + else if (!strcmp(pieces[0], "feature")) + { + int i, j; + for (i = 1; i < npieces; i++) + { + for (j = 0; features[j]; j++) + if (!strcmp(pieces[i], features[j])) + break; + if (!features[j]) + { + pool_debug(pool, SOLV_ERROR, "testcase_read: missing feature '%s'\n", pieces[i]); + missing_features++; + } + } + if (missing_features) + break; + } + else if (!strcmp(pieces[0], "genid") && npieces > 1) + { + Id id; + /* rejoin */ + if (npieces > 2) + { + char *sp; + for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++) + if (*sp == 0) + *sp = ' '; + } + genid = solv_extend(genid, ngenid, 1, sizeof(*genid), 7); + if (!strcmp(pieces[1], "op") && npieces > 2) + { + struct oplist *op; + for (op = oplist; op->flags; op++) + if (!strncmp(pieces[2], op->opname, strlen(op->opname))) + break; + if (!op->flags) + { + pool_debug(pool, SOLV_ERROR, "testcase_read: genid: unknown op '%s'\n", pieces[2]); + break; + } + if (ngenid < 2) + { + pool_debug(pool, SOLV_ERROR, "testcase_read: genid: out of stack\n"); + break; + } + ngenid -= 2; + id = pool_rel2id(pool, genid[ngenid] , genid[ngenid + 1], op->flags, 1); + } + else if (!strcmp(pieces[1], "lit")) + id = pool_str2id(pool, npieces > 2 ? pieces[2] : "", 1); + else if (!strcmp(pieces[1], "null")) + id = 0; + else if (!strcmp(pieces[1], "dep")) + id = testcase_str2dep(pool, pieces[2]); + else + { + pool_debug(pool, SOLV_ERROR, "testcase_read: genid: unknown command '%s'\n", pieces[1]); + break; + } + genid[ngenid++] = id; + } else { pool_debug(pool, SOLV_ERROR, "testcase_read: cannot parse command '%s'\n", pieces[0]); } } + while (job && ngenid > 0) + queue_push2(job, SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES, genid[--ngenid]); + genid = solv_free(genid); buf = solv_free(buf); pieces = solv_free(pieces); solv_free(testcasedir); @@ -2531,6 +2739,13 @@ testcase_read(Pool *pool, FILE *fp, char *testcase, Queue *job, char **resultp, } if (closefp) fclose(fp); + if (missing_features) + { + solver_free(solv); + solv = 0; + if (resultflagsp) + *resultflagsp = 77; /* hack for testsolv */ + } return solv; } diff --git a/ext/testcase.h b/ext/testcase.h index 14a2cca..78f78b0 100644 --- a/ext/testcase.h +++ b/ext/testcase.h @@ -15,6 +15,8 @@ #define TESTCASE_RESULT_RECOMMENDED (1 << 3) #define TESTCASE_RESULT_UNNEEDED (1 << 4) #define TESTCASE_RESULT_ALTERNATIVES (1 << 5) +#define TESTCASE_RESULT_RULES (1 << 6) +#define TESTCASE_RESULT_GENID (1 << 7) extern Id testcase_str2dep(Pool *pool, const char *s); extern const char *testcase_dep2str(Pool *pool, Id id); diff --git a/package/libsolv.changes b/package/libsolv.changes index ad435b9..5a0a59b 100644 --- a/package/libsolv.changes +++ b/package/libsolv.changes @@ -1,4 +1,19 @@ ------------------------------------------------------------------- +Tue Jun 2 11:41:10 CEST 2015 - mls@suse.de + +- add forgotten sha-512 support to data_skip +- speed up whatprovides lookup with a new helper array +- fix dup with allowuninstall +- improve alreadyinstalled handling of supplements +- some code cleanup +- bump version to 0.6.11 + +------------------------------------------------------------------- +Sat May 2 11:44:08 UTC 2015 - mrueckert@suse.de + +- you really want to use rbconfig there + +------------------------------------------------------------------- Wed Mar 18 11:04:34 CET 2015 - mls@suse.de - fix bug in dislike_old_versions that could lead to a segfault diff --git a/package/libsolv.spec.in b/package/libsolv.spec.in index 934ae2e..f5581b6 100644 --- a/package/libsolv.spec.in +++ b/package/libsolv.spec.in @@ -64,7 +64,7 @@ BuildRequires: perl-devel BuildRequires: swig %endif %if %{with ruby_binding} -%global ruby_vendorarch %(ruby -r rbconfig -e "puts Config::CONFIG['vendorarchdir'].nil? ? Config::CONFIG['sitearchdir'] : Config::CONFIG['vendorarchdir']") +%global ruby_vendorarch %(ruby -r rbconfig -e "puts RbConfig::CONFIG['vendorarchdir'].nil? ? RbConfig::CONFIG['sitearchdir'] : RbConfig::CONFIG['vendorarchdir']") BuildRequires: ruby BuildRequires: ruby-devel BuildRequires: swig diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b78a82a..f60853e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,7 +28,9 @@ SET (libsolv_HEADERS chksum.h dataiterator.h ${CMAKE_BINARY_DIR}/src/solvversion.h) SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") +IF (HAVE_LINKER_VERSION_SCRIPT) SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver") +ENDIF (HAVE_LINKER_VERSION_SCRIPT) IF (DISABLE_SHARED) ADD_LIBRARY (libsolv STATIC ${libsolv_SRCS}) diff --git a/src/cplxdeps.c b/src/cplxdeps.c index 9e42194..1be6868 100644 --- a/src/cplxdeps.c +++ b/src/cplxdeps.c @@ -68,6 +68,33 @@ expand_simpledeps(Pool *pool, Queue *bq, int start, int split) return newsplit; } +#ifdef CPLXDEBUG +static void +print_depblocks(Pool *pool, Queue *bq, int start) +{ + int i; + + for (i = start; i < bq->count; i++) + { + if (bq->elements[i] == pool->nsolvables) + { + Id *dp = pool->whatprovidesdata + bq->elements[++i]; + printf(" ("); + while (*dp) + printf(" %s", pool_solvid2str(pool, *dp++)); + printf(" )"); + } + else if (bq->elements[i] > 0) + printf(" %s", pool_solvid2str(pool, bq->elements[i])); + else if (bq->elements[i] < 0) + printf(" -%s", pool_solvid2str(pool, -bq->elements[i])); + else + printf(" ||"); + } + printf("\n"); +} +#endif + /* invert all literals in the blocks. note that this also turns DNF into CNF and vice versa */ static void invert_depblocks(Pool *pool, Queue *bq, int start) @@ -82,7 +109,7 @@ invert_depblocks(Pool *pool, Queue *bq, int start) bq->elements[i] = -bq->elements[i]; continue; } - /* end of block reached, reorder */ + /* end of block reached, reverse */ if (i - 1 > j) { int k; @@ -104,11 +131,12 @@ invert_depblocks(Pool *pool, Queue *bq, int start) * -1: at least one block */ static int -normalize_dep(Pool *pool, Id dep, Queue *bq, int todnf) +normalize_dep(Pool *pool, Id dep, Queue *bq, int flags) { int bqcnt = bq->count; int bqcnt2; - Id dp; + int todnf = flags & CPLXDEPS_TODNF ? 1 : 0; + Id p, dp; #ifdef CPLXDEBUG printf("normalize_dep %s todnf:%d\n", pool_dep2str(pool, dep), todnf); @@ -118,58 +146,60 @@ normalize_dep(Pool *pool, Id dep, Queue *bq, int todnf) Reldep *rd = GETRELDEP(pool, dep); if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_COND) { - int flags = rd->flags; + int rdflags = rd->flags; int r, mode; /* in inverted mode, COND means AND. otherwise it means OR NOT */ - if (flags == REL_COND && todnf) - flags = REL_AND; - mode = flags == REL_AND ? 0 : 1; + if (rdflags == REL_COND && todnf) + rdflags = REL_AND; + mode = rdflags == REL_AND ? 0 : 1; /* get blocks of first argument */ - r = normalize_dep(pool, rd->name, bq, todnf); + r = normalize_dep(pool, rd->name, bq, flags); if (r == 0) { - if (flags == REL_AND) + if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) == 0) return 0; - if (flags == REL_COND) + if (rdflags == REL_COND) { - r = normalize_dep(pool, rd->evr, bq, todnf ^ 1); + r = normalize_dep(pool, rd->evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX); if (r == 0 || r == 1) return r == 0 ? 1 : 0; invert_depblocks(pool, bq, bqcnt); /* invert block for COND */ return r; } - return normalize_dep(pool, rd->evr, bq, todnf); + return normalize_dep(pool, rd->evr, bq, flags); } if (r == 1) { - if (flags != REL_AND) + if (rdflags != REL_AND) return 1; - return normalize_dep(pool, rd->evr, bq, todnf); + return normalize_dep(pool, rd->evr, bq, flags); } /* get blocks of second argument */ bqcnt2 = bq->count; - /* COND is OR with NEG on evr block, so we invert the todnf flag in that case*/ - r = normalize_dep(pool, rd->evr, bq, flags == REL_COND ? todnf ^ 1 : todnf); + /* COND is OR with NEG on evr block, so we invert the todnf flag in that case */ + r = normalize_dep(pool, rd->evr, bq, rdflags == REL_COND ? ((flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX) : flags); if (r == 0) { - if (flags == REL_OR) + if (rdflags == REL_OR) + return -1; + if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) != 0) return -1; queue_truncate(bq, bqcnt); - return flags == REL_COND ? 1 : 0; + return rdflags == REL_COND ? 1 : 0; } if (r == 1) { - if (flags == REL_OR) + if (rdflags == REL_OR) { queue_truncate(bq, bqcnt); return 1; } return -1; } - if (flags == REL_COND) + if (rdflags == REL_COND) invert_depblocks(pool, bq, bqcnt2); /* invert 2nd block */ if (mode == todnf) { @@ -247,16 +277,29 @@ normalize_dep(Pool *pool, Id dep, Queue *bq, int todnf) return dp == 2 ? 1 : 0; if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE) return 1; - if (todnf) + bqcnt = bq->count; + if ((flags & CPLXDEPS_NAME) != 0) { - for (; pool->whatprovidesdata[dp]; dp++) - queue_push2(bq, pool->whatprovidesdata[dp], 0); + while ((p = pool->whatprovidesdata[dp++]) != 0) + { + if (!pool_match_nevr(pool, pool->solvables + p, dep)) + continue; + queue_push(bq, p); + if (todnf) + queue_push(bq, 0); + } } - else + else if (todnf) { - queue_push2(bq, pool->nsolvables, dp); /* not yet expanded marker */ - queue_push(bq, 0); + while ((p = pool->whatprovidesdata[dp++]) != 0) + queue_push2(bq, p, 0); } + else + queue_push2(bq, pool->nsolvables, dp); /* not yet expanded marker + offset */ + if (bq->count == bqcnt) + return 0; /* no provider */ + if (!todnf) + queue_push(bq, 0); /* finish block */ return -1; } @@ -265,7 +308,7 @@ pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags) { int i, bqcnt = bq->count; - i = normalize_dep(pool, dep, bq, (flags & CPLXDEPS_TODNF) ? 1 : 0); + i = normalize_dep(pool, dep, bq, flags); if ((flags & CPLXDEPS_EXPAND) != 0) { if (i != 0 && i != 1) @@ -284,27 +327,7 @@ pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags) else if (i == 1) printf("ALL\n"); else - { - for (i = bqcnt; i < bq->count; i++) - { - if (bq->elements[i] == pool->nsolvables) - { - Id *dp = pool->whatprovidesdata + bq->elements[++i]; - printf(" ("); - while (*dp) - printf(" %s", pool_solvid2str(pool, *dp++)); - printf(" )"); - } - else if (bq->elements[i] > 0) - printf(" %s", pool_solvid2str(pool, bq->elements[i])); - else if (bq->elements[i] < 0) - printf(" -%s", pool_solvid2str(pool, -bq->elements[i])); - else - printf(" ||"); - } - printf("\n"); - i = -1; - } + print_depblocks(pool, bq, bqcnt); #endif return i; } diff --git a/src/cplxdeps.h b/src/cplxdeps.h index 101d7ad..b553305 100644 --- a/src/cplxdeps.h +++ b/src/cplxdeps.h @@ -28,9 +28,11 @@ pool_is_complex_dep(Pool *pool, Id dep) extern int pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags); -#define CPLXDEPS_TODNF (1 << 0) -#define CPLXDEPS_EXPAND (1 << 1) -#define CPLXDEPS_INVERT (1 << 2) +#define CPLXDEPS_TODNF (1 << 0) +#define CPLXDEPS_EXPAND (1 << 1) +#define CPLXDEPS_INVERT (1 << 2) +#define CPLXDEPS_NAME (1 << 3) +#define CPLXDEPS_DONTFIX (1 << 4) #endif diff --git a/src/libsolv.ver b/src/libsolv.ver index c795b7a..b8d9764 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -74,6 +74,7 @@ SOLV_1.0 { pool_id2langid; pool_id2rel; pool_id2str; + pool_ids2whatprovides; pool_intersect_evrs; pool_isemptyupdatejob; pool_job2solvables; diff --git a/src/policy.c b/src/policy.c index 93d7440..fadfcda 100644 --- a/src/policy.c +++ b/src/policy.c @@ -220,6 +220,11 @@ solver_prune_to_highest_prio_per_name(Solver *solv, Queue *plist) #ifdef ENABLE_COMPLEX_DEPS +/* simple fixed-size hash for package ids */ +#define CPLXDEPHASH_EMPTY(elements) (memset(elements, 0, sizeof(Id) * 256)) +#define CPLXDEPHASH_SET(elements, p) (elements[(p) & 255] |= (1 << ((p) >> 8 & 31))) +#define CPLXDEPHASH_TST(elements, p) (elements[(p) & 255] && (elements[(p) & 255] & (1 << ((p) >> 8 & 31)))) + static void check_complex_dep(Solver *solv, Id dep, Map *m, Queue **cqp) { @@ -241,55 +246,64 @@ check_complex_dep(Solver *solv, Id dep, Map *m, Queue **cqp) qcnt = q.count; for (i = 0; i < qcnt; i++) { - for (; (p = q.elements[i]) != 0; i++) + /* we rely on the fact that blocks are ordered here. + * if we reach a positive element, we know that we + * saw all negative ones */ + for (; (p = q.elements[i]) < 0; i++) { - if (p < 0) - { - if (solv->decisionmap[-p] > 0) - continue; - if (solv->decisionmap[-p] < 0) - break; - queue_push(&q, -p); - } - if (p > 0 && qcnt == q.count) - MAPSET(m, p); + if (solv->decisionmap[-p] < 0) + break; + if (solv->decisionmap[-p] == 0) + queue_push(&q, -p); /* undecided negative literal */ } - if (q.elements[i]) + if (p <= 0) { #if 0 - printf("complex dep block cannot be true\n"); + printf("complex dep block cannot be true or no pos literals\n"); #endif while (q.elements[i]) i++; if (qcnt != q.count) queue_truncate(&q, qcnt); + continue; } - else if (qcnt != q.count) + if (qcnt == q.count) { + /* all negative literals installed, add positive literals to map */ + for (; (p = q.elements[i]) != 0; i++) + MAPSET(m, p); + } + else + { + /* at least one undecided negative literal, postpone */ int j, k; - Queue *cq = *cqp; + Queue *cq; #if 0 printf("add new complex dep block\n"); for (j = qcnt; j < q.count; j++) printf(" - %s\n", pool_solvid2str(pool, q.elements[j])); #endif - if (!cq) + while (q.elements[i]) + i++; + if (!(cq = *cqp)) { cq = solv_calloc(1, sizeof(Queue)); queue_init(cq); + queue_insertn(cq, 0, 256, 0); /* allocate hash area */ *cqp = cq; - queue_insertn(cq, 0, 256, 0); } for (j = qcnt; j < q.count; j++) { p = q.elements[j]; + /* check if we already have this (dep, p) entry */ for (k = 256; k < cq->count; k += 2) if (cq->elements[k + 1] == dep && cq->elements[k] == p) break; if (k == cq->count) { + /* a new one. add to cq and hash */ queue_push2(cq, p, dep); - cq->elements[p & 255] |= (1 << (p >> 8 & 31)); + CPLXDEPHASH_SET(cq->elements, p); } } queue_truncate(&q, qcnt); @@ -299,13 +313,15 @@ check_complex_dep(Solver *solv, Id dep, Map *m, Queue **cqp) } static void -recheck_complex_dep(Solver *solv, Id p, Map *m, Queue **cqp) +recheck_complex_deps(Solver *solv, Id p, Map *m, Queue **cqp) { Queue *cq = *cqp; + Id pp; int i; #if 0 - printf("recheck_complex_dep for package %s\n", pool_solvid2str(solv->pool, p)); + printf("recheck_complex_deps for package %s\n", pool_solvid2str(solv->pool, p)); #endif + /* make sure that we don't have a false hit */ for (i = 256; i < cq->count; i += 2) if (cq->elements[i] == p) break; @@ -313,9 +329,11 @@ recheck_complex_dep(Solver *solv, Id p, Map *m, Queue **cqp) return; /* false alert */ if (solv->decisionmap[p] <= 0) return; /* just in case... */ - memset(cq->elements, 0, sizeof(Id) * 256); + + /* rebuild the hash, call check_complex_dep for our package */ + CPLXDEPHASH_EMPTY(cq->elements); for (i = 256; i < cq->count; i += 2) - if (cq->elements[i] == p) + if ((pp = cq->elements[i]) == p) { Id dep = cq->elements[i + 1]; queue_deleten(cq, i, 2); @@ -323,10 +341,7 @@ recheck_complex_dep(Solver *solv, Id p, Map *m, Queue **cqp) check_complex_dep(solv, dep, m, &cq); } else - { - Id pp = cq->elements[i]; - cq->elements[pp & 255] |= (1 << (pp >> 8 & 31)); - } + CPLXDEPHASH_SET(cq->elements, pp); } #endif @@ -364,12 +379,11 @@ policy_update_recommendsmap(Solver *solv) continue; s = pool->solvables + p; #ifdef ENABLE_COMPLEX_DEPS - if (solv->recommendscplxq && solv->recommendscplxq->elements[p & 255]) - if (solv->recommendscplxq->elements[p & 255] & (1 << (p >> 8 & 31))) - recheck_complex_dep(solv, p, &solv->recommendsmap, &solv->recommendscplxq); - if (solv->suggestscplxq && solv->suggestscplxq->elements[p & 255]) - if (solv->suggestscplxq->elements[p & 255] & (1 << (p >> 8 & 31))) - recheck_complex_dep(solv, p, &solv->suggestsmap, &solv->suggestscplxq); + /* re-check postponed complex blocks */ + if (solv->recommendscplxq && CPLXDEPHASH_TST(solv->recommendscplxq->elements, p)) + recheck_complex_deps(solv, p, &solv->recommendsmap, &solv->recommendscplxq); + if (solv->suggestscplxq && CPLXDEPHASH_TST(solv->suggestscplxq->elements, p)) + recheck_complex_deps(solv, p, &solv->suggestsmap, &solv->suggestscplxq); #endif if (s->recommends) { @@ -877,9 +891,11 @@ sort_by_name_evr_sortcmp(const void *ap, const void *bp, void *dp) Id r = aa[1] - bb[1]; if (r) return r < 0 ? -1 : 1; + if (aa[2] == bb[2]) + return 0; a = aa[2] < 0 ? -aa[2] : aa[2]; b = bb[2] < 0 ? -bb[2] : bb[2]; - if (pool->disttype != DISTTYPE_DEB) + if (pool->disttype != DISTTYPE_DEB && a != b) { /* treat release-less versions different */ const char *as = pool_id2str(pool, a); @@ -1113,10 +1129,10 @@ policy_filter_unwanted(Solver *solv, Queue *plist, int mode) prune_to_best_arch(pool, plist); if (plist->count > 1) prune_to_best_version(pool, plist); - if (plist->count > 1 && mode == POLICY_MODE_CHOOSE) + if (plist->count > 1 && (mode == POLICY_MODE_CHOOSE || mode == POLICY_MODE_CHOOSE_NOREORDER)) { prune_to_recommended(solv, plist); - if (plist->count > 1) + if (plist->count > 1 && mode != POLICY_MODE_CHOOSE_NOREORDER) { /* do some fancy reordering */ #if 0 @@ -1346,7 +1362,7 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) } else if (!allownamechange) continue; - else if (!solv->noupdateprovide && ps->obsoletes) /* provides/obsoletes combination ? */ + else if ((!solv->noupdateprovide || solv->needupdateprovide) && ps->obsoletes) /* provides/obsoletes combination ? */ { /* check if package ps obsoletes installed package s */ /* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless @@ -1386,7 +1402,7 @@ policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) return; /* if we have found some valid candidates and noupdateprovide is not set, we're done. otherwise we fallback to all obsoletes */ - if (!solv->noupdateprovide && haveprovobs) + if (solv->needupdateprovide || (!solv->noupdateprovide && haveprovobs)) return; if (solv->obsoletes && solv->obsoletes[n - solv->installed->start]) { diff --git a/src/policy.h b/src/policy.h index a4dd4c4..73410ee 100644 --- a/src/policy.h +++ b/src/policy.h @@ -19,6 +19,7 @@ extern "C" { #define POLICY_MODE_CHOOSE 0 #define POLICY_MODE_RECOMMEND 1 #define POLICY_MODE_SUGGEST 2 +#define POLICY_MODE_CHOOSE_NOREORDER 3 /* internal, do not use */ #define POLICY_ILLEGAL_DOWNGRADE 1 @@ -194,6 +194,8 @@ pool_get_flag(Pool *pool, int flag) return pool->noobsoletesmultiversion; case POOL_FLAG_ADDFILEPROVIDESFILTERED: return pool->addfileprovidesfiltered; + case POOL_FLAG_NOWHATPROVIDESAUX: + return pool->nowhatprovidesaux; default: break; } @@ -236,6 +238,9 @@ pool_set_flag(Pool *pool, int flag, int value) case POOL_FLAG_ADDFILEPROVIDESFILTERED: pool->addfileprovidesfiltered = value; break; + case POOL_FLAG_NOWHATPROVIDESAUX: + pool->nowhatprovidesaux = value; + break; default: break; } @@ -393,6 +398,34 @@ pool_shrink_whatprovides(Pool *pool) memset(pool->whatprovidesdata + o, 0, r * sizeof(Id)); } +/* this gets rid of all the zeros in the aux */ +static void +pool_shrink_whatprovidesaux(Pool *pool) +{ + int num = pool->whatprovidesauxoff; + Id id; + Offset newoff; + Id *op, *wp = pool->whatprovidesauxdata + 1; + int i; + + for (i = 0; i < num; i++) + { + Offset o = pool->whatprovidesaux[i]; + if (o < 2) + continue; + op = pool->whatprovidesauxdata + o; + pool->whatprovidesaux[i] = wp - pool->whatprovidesauxdata; + if (op < wp) + abort(); + while ((id = *op++) != 0) + *wp++ = id; + } + newoff = wp - pool->whatprovidesauxdata; + solv_realloc(pool->whatprovidesauxdata, newoff * sizeof(Id)); + POOL_DEBUG(SOLV_DEBUG_STATS, "shrunk whatprovidesauxdata from %d to %d\n", pool->whatprovidesauxdataoff, newoff); + pool->whatprovidesauxdataoff = newoff; +} + /* * pool_createwhatprovides() @@ -409,7 +442,8 @@ pool_createwhatprovides(Pool *pool) Id id; Offset *idp, n; Offset *whatprovides; - Id *whatprovidesdata, *d; + Id *whatprovidesdata, *dp, *whatprovidesauxdata; + Offset *whatprovidesaux; Repo *installed = pool->installed; unsigned int now; @@ -477,6 +511,16 @@ pool_createwhatprovides(Pool *pool) whatprovidesdata = solv_calloc(off + extra, sizeof(Id)); whatprovidesdata[2] = SYSTEMSOLVABLE; + /* alloc aux vector */ + whatprovidesauxdata = 0; + if (!pool->nowhatprovidesaux) + { + pool->whatprovidesaux = whatprovidesaux = solv_calloc(num, sizeof(Offset)); + pool->whatprovidesauxoff = num; + pool->whatprovidesauxdataoff = off; + pool->whatprovidesauxdata = whatprovidesauxdata = solv_calloc(pool->whatprovidesauxdataoff, sizeof(Id)); + } + /* now fill data for all provides */ for (i = pool->nsolvables - 1; i > 0; i--) { @@ -491,24 +535,35 @@ pool_createwhatprovides(Pool *pool) pp = s->repo->idarraydata + s->provides; while ((id = *pp++) != 0) { + Id auxid = id; while (ISRELDEP(id)) { Reldep *rd = GETRELDEP(pool, id); id = rd->name; } - d = whatprovidesdata + whatprovides[id]; /* offset into whatprovidesdata */ - if (*d != i) /* don't add same solvable twice */ + dp = whatprovidesdata + whatprovides[id]; /* offset into whatprovidesdata */ + if (*dp != i) /* don't add same solvable twice */ { - d[-1] = i; + dp[-1] = i; whatprovides[id]--; } + else + auxid = 1; + if (whatprovidesauxdata) + whatprovidesauxdata[whatprovides[id]] = auxid; } } + if (pool->whatprovidesaux) + memcpy(pool->whatprovidesaux, pool->whatprovides, num * sizeof(Id)); pool->whatprovidesdata = whatprovidesdata; pool->whatprovidesdataoff = off; pool->whatprovidesdataleft = extra; pool_shrink_whatprovides(pool); + if (pool->whatprovidesaux) + pool_shrink_whatprovidesaux(pool); POOL_DEBUG(SOLV_DEBUG_STATS, "whatprovides memory used: %d K id array, %d K data\n", (pool->ss.nstrings + pool->nrels + WHATPROVIDES_BLOCK) / (int)(1024/sizeof(Id)), (pool->whatprovidesdataoff + pool->whatprovidesdataleft) / (int)(1024/sizeof(Id))); + if (pool->whatprovidesaux) + POOL_DEBUG(SOLV_DEBUG_STATS, "whatprovidesaux memory used: %d K id array, %d K data\n", pool->whatprovidesauxoff / (int)(1024/sizeof(Id)), pool->whatprovidesauxdataoff / (int)(1024/sizeof(Id))); queue_empty(&pool->lazywhatprovidesq); if ((!pool->addedfileprovides && pool->disttype == DISTTYPE_RPM) || pool->addedfileprovides == 1) @@ -527,6 +582,8 @@ pool_createwhatprovides(Pool *pool) if (pool->whatprovides[i] > 1) queue_push2(&pool->lazywhatprovidesq, i, pool->whatprovides[i]); pool->whatprovides[i] = 0; + if (pool->whatprovidesaux) + pool->whatprovidesaux[i] = 0; /* sorry */ } POOL_DEBUG(SOLV_DEBUG_STATS, "lazywhatprovidesq size: %d entries\n", pool->lazywhatprovidesq.count / 2); } @@ -547,6 +604,10 @@ pool_freewhatprovides(Pool *pool) pool->whatprovidesdata = solv_free(pool->whatprovidesdata); pool->whatprovidesdataoff = 0; pool->whatprovidesdataleft = 0; + pool->whatprovidesaux = solv_free(pool->whatprovidesaux); + pool->whatprovidesauxdata = solv_free(pool->whatprovidesauxdata); + pool->whatprovidesauxoff = 0; + pool->whatprovidesauxdataoff = 0; } @@ -560,15 +621,15 @@ pool_freewhatprovides(Pool *pool) * returns: Offset into whatprovidesdata * */ + Id -pool_queuetowhatprovides(Pool *pool, Queue *q) +pool_ids2whatprovides(Pool *pool, Id *ids, int count) { Offset off; - int count = q->count; if (count == 0) /* queue empty -> 1 */ return 1; - if (count == 1 && q->elements[0] == SYSTEMSOLVABLE) + if (count == 1 && *ids == SYSTEMSOLVABLE) return 2; /* extend whatprovidesdata if needed, +1 for 0-termination */ @@ -581,7 +642,7 @@ pool_queuetowhatprovides(Pool *pool, Queue *q) /* copy queue to next free slot */ off = pool->whatprovidesdataoff; - memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id)); + memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, ids, count * sizeof(Id)); /* adapt count and 0-terminate */ pool->whatprovidesdataoff += count; @@ -591,6 +652,17 @@ pool_queuetowhatprovides(Pool *pool, Queue *q) return (Id)off; } +Id +pool_queuetowhatprovides(Pool *pool, Queue *q) +{ + int count = q->count; + if (count == 0) /* queue empty -> 1 */ + return 1; + if (count == 1 && q->elements[0] == SYSTEMSOLVABLE) + return 2; + return pool_ids2whatprovides(pool, q->elements, count); +} + /*************************************************************************/ @@ -1100,11 +1172,14 @@ pool_addrelproviders(Pool *pool, Id d) } else if (flags) { + Id *ppaux = 0; /* simple version comparison relation */ #if 0 POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: what provides %s?\n", pool_dep2str(pool, name)); #endif pp = pool_whatprovides_ptr(pool, name); + if (!ISRELDEP(name) && name < pool->whatprovidesauxoff) + ppaux = pool->whatprovidesaux[name] ? pool->whatprovidesauxdata + pool->whatprovidesaux[name] : 0; while (ISRELDEP(name)) { rd = GETRELDEP(pool, name); @@ -1113,6 +1188,34 @@ pool_addrelproviders(Pool *pool, Id d) while ((p = *pp++) != 0) { Solvable *s = pool->solvables + p; + if (ppaux) + { + pid = *ppaux++; + if (pid && pid != 1) + { +#if 0 + POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: aux hit %d %s\n", p, pool_dep2str(pool, pid)); +#endif + if (!ISRELDEP(pid)) + { + if (pid != name) + continue; /* wrong provides name */ + if (pool->disttype == DISTTYPE_DEB) + continue; /* unversioned provides can never match versioned deps */ + } + else + { + prd = GETRELDEP(pool, pid); + if (prd->name != name) + continue; /* wrong provides name */ + /* right package, both deps are rels. check flags/evr */ + if (!pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr)) + continue; + } + queue_push(&plist, p); + continue; + } + } if (!s->provides) { /* no provides - check nevr */ @@ -1338,7 +1441,7 @@ pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct sea dep = rd->name; else if (rd->flags == REL_NAMESPACE) { - if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES) + if (rd->name == NAMESPACE_SPLITPROVIDES) { csf = isf; if (!csf || MAPTST(&csf->seen, sid)) @@ -2499,6 +2602,8 @@ 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 */ queue_free(&q); } @@ -155,6 +155,12 @@ struct _Pool { int addfileprovidesfiltered; /* 1: only use filtered file list for addfileprovides */ int addedfileprovides; /* true: application called addfileprovides */ Queue lazywhatprovidesq; /* queue to store old whatprovides offsets */ + int nowhatprovidesaux; /* don't allocate and use the whatprovides aux helper */ + Offset *whatprovidesaux; + Offset whatprovidesauxoff; + Id *whatprovidesauxdata; + Offset whatprovidesauxdataoff; + #endif }; @@ -190,6 +196,7 @@ struct _Pool { #define POOL_FLAG_NOOBSOLETESMULTIVERSION 8 #define POOL_FLAG_ADDFILEPROVIDESFILTERED 9 #define POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS 10 +#define POOL_FLAG_NOWHATPROVIDESAUX 11 /* ----------------------------------------------- */ @@ -306,6 +313,7 @@ extern void pool_addfileprovides(Pool *pool); extern void pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst); extern void pool_freewhatprovides(Pool *pool); extern Id pool_queuetowhatprovides(Pool *pool, Queue *q); +extern Id pool_ids2whatprovides(Pool *pool, Id *ids, int count); extern Id pool_searchlazywhatprovidesq(Pool *pool, Id d); extern Id pool_addrelproviders(Pool *pool, Id d); diff --git a/src/problems.c b/src/problems.c index 528aa2e..b57d980 100644 --- a/src/problems.c +++ b/src/problems.c @@ -152,6 +152,8 @@ enableweakrules(Solver *solv) int i; Rule *r; + if (!solv->weakrulemap.size) + return; for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++) { if (r->d >= 0) /* already enabled? */ @@ -227,9 +229,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti int njob, nfeature, nupdate, pass; queue_empty(&solv->problems); solver_reset(solv); - - if (!solv->problems.count) - solver_run_sat(solv, 0, 0); + solver_run_sat(solv, 0, 0); if (!solv->problems.count) { diff --git a/src/repopack.h b/src/repopack.h index f7828ab..3079239 100644 --- a/src/repopack.h +++ b/src/repopack.h @@ -235,8 +235,14 @@ data_skip(unsigned char *dp, int type) return dp + SIZEOF_MD5; case REPOKEY_TYPE_SHA1: return dp + SIZEOF_SHA1; + case REPOKEY_TYPE_SHA224: + return dp + SIZEOF_SHA224; case REPOKEY_TYPE_SHA256: return dp + SIZEOF_SHA256; + case REPOKEY_TYPE_SHA384: + return dp + SIZEOF_SHA384; + case REPOKEY_TYPE_SHA512: + return dp + SIZEOF_SHA512; case REPOKEY_TYPE_IDARRAY: case REPOKEY_TYPE_REL_IDARRAY: while ((*dp & 0xc0) != 0) @@ -307,8 +313,14 @@ data_skip_verify(unsigned char *dp, int type, int maxid, int maxdir) return dp + SIZEOF_MD5; case REPOKEY_TYPE_SHA1: return dp + SIZEOF_SHA1; + case REPOKEY_TYPE_SHA224: + return dp + SIZEOF_SHA224; case REPOKEY_TYPE_SHA256: return dp + SIZEOF_SHA256; + case REPOKEY_TYPE_SHA384: + return dp + SIZEOF_SHA384; + case REPOKEY_TYPE_SHA512: + return dp + SIZEOF_SHA512; case REPOKEY_TYPE_ID: dp = data_read_id(dp, &id); if (id >= maxid) diff --git a/src/rules.c b/src/rules.c index c9bbf81..67de769 100644 --- a/src/rules.c +++ b/src/rules.c @@ -31,7 +31,7 @@ #define RULES_BLOCK 63 -static void addpkgruleinfo(Solver *solv, Id p, Id d, int type, Id dep); +static void addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep); static void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded); /*------------------------------------------------------------------- @@ -66,8 +66,6 @@ dep_possible(Solver *solv, Id dep, Map *m) } if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) return solver_splitprovides(solv, rd->evr, m); - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) - return solver_dep_installed(solv, rd->evr); } } FOR_PROVIDES(p, pp, dep) @@ -243,27 +241,23 @@ hashrule(Solver *solv, Id p, Id d, int n) /* * add rule - * p = direct literal; always < 0 for installed pkg rules - * d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only) - * * * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3) * - * p < 0 : pkg id of A - * d > 0 : Offset in whatprovidesdata (list of providers of b) + * p < 0 : pkg id of A + * d > 0 : Offset in whatprovidesdata (list of providers of b) * * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3) - * p < 0 : pkg id of A - * d < 0 : Id of solvable (e.g. B1) + * p < 0 : pkg id of A + * p2 < 0 : Id of solvable (e.g. B1) * - * d == 0: unary rule, assertion => (A) or (-A) + * d == 0, p2 == 0: unary rule, assertion => (A) or (-A) * * Install: p > 0, d = 0 (A) user requested install * Remove: p < 0, d = 0 (-A) user requested remove (also: uninstallable) * Requires: p < 0, d > 0 (-A|B1|B2|...) d: <list of providers for requirement of p> - * Requires: p > 0, d < 0 (B|-A) hack to save a whatprovides allocation, gets converted into (-A|B) * Updates: p > 0, d > 0 (A|B1|B2|...) d: <list of updates for solvable p> - * Conflicts: p < 0, d < 0 (-A|-B) either p (conflict issuer) or d (conflict provider) (binary rule) + * Conflicts: p < 0, p2 < 0 (-A|-B) either p (conflict issuer) or d (conflict provider) (binary rule) * also used for obsoletes * No-op ?: p = 0, d = 0 (null) (used as placeholder in update/feature rules) * @@ -277,118 +271,87 @@ hashrule(Solver *solv, Id p, Id d, int n) */ Rule * -solver_addrule(Solver *solv, Id p, Id d) +solver_addrule(Solver *solv, Id p, Id p2, Id d) { Pool *pool = solv->pool; - Rule *r = 0; - Id *dp = 0; + Rule *r; + + if (d) + { + assert(!p2 && d > 0); + if (!pool->whatprovidesdata[d]) + d = 0; + else if (!pool->whatprovidesdata[d + 1]) + { + p2 = pool->whatprovidesdata[d]; + d = 0; + } + } - int n = 0; /* number of literals in rule - 1 - 0 = direct assertion (single literal) - 1 = binary rule - >1 = multi-literal rule - */ + /* now we have two cases: + * 1 or 2 literals: d = 0, p, p2 contain the literals + * 3 or more literals: d > 0, p2 == 0, d is offset into whatprovidesdata + */ /* it often happenes that requires lead to adding the same pkg rule * multiple times, so we prune those duplicates right away to make * the work for unifyrules a bit easier */ - if (!solv->pkgrules_end) /* we add pkg rules */ { - r = solv->rules + solv->nrules - 1; /* get the last added rule */ - if (r->p == p && r->d == d && (d != 0 || !r->w2)) - return r; - } - - /* compute number of literals (n) in rule */ - if (d < 0) - { - if (p == -d) - return 0; /* rule is self-fulfilling */ - if (p == d) - d = 0; /* normalize to assertion */ + r = solv->rules + solv->nrules - 1; + if (d) + { + Id *dp; + /* check if rule is identical */ + if (r->p == p) + { + Id *dp2; + if (r->d == d) + return r; + dp2 = pool->whatprovidesdata + r->d; + for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++) + if (*dp != *dp2) + break; + if (*dp == *dp2) + return r; + } + /* check if rule is self-fulfilling */ + for (dp = pool->whatprovidesdata + d; *dp; dp++) + if (*dp == -p) + return 0; /* rule is self-fulfilling */ + } else - n = 1; /* binary rule */ - } - else if (d > 0) - { - for (dp = pool->whatprovidesdata + d; *dp; dp++, n++) - if (*dp == -p) - return 0; /* rule is self-fulfilling */ - if (n == 1) /* convert to binary rule */ - d = dp[-1]; - } - - if (n == 1 && p > d && !solv->pkgrules_end) - { - /* put smallest literal first so we can find dups */ - n = p; p = d; d = n; /* p <-> d */ - n = 1; /* re-set n, was used as temp var */ - } - - /* - * check for duplicate (r is only set if we're adding pkg rules) - */ - if (r) - { - /* check if the last added rule (r) is exactly the same as what we're looking for. */ - if (n == 1 && !r->d && r->p == p && r->w2 == d) - return r; - /* have n-ary rule with same first literal, check other literals */ - if (n > 1 && r->d && r->p == p) { - /* Rule where d is an offset in whatprovidesdata */ - Id *dp2; - if (d == r->d) - return r; - dp2 = pool->whatprovidesdata + r->d; - for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++) - if (*dp != *dp2) - break; - if (*dp == *dp2) + if (p2 && p > p2) + { + Id o = p; /* switch p1 and p2 */ + p = p2; + p2 = o; + } + if (r->p == p && !r->d && r->w2 == p2) return r; + if (p == -p2) + return 0; /* rule is self-fulfilling */ } } - /* - * allocate new rule r - */ solv->rules = solv_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK); r = solv->rules + solv->nrules++; /* point to rule space */ - r->p = p; - if (n == 0) - { - /* direct assertion, no watch needed */ - r->d = 0; - r->w1 = p; - r->w2 = 0; - } - else if (n == 1) - { - /* binary rule */ - r->d = 0; - r->w1 = p; - r->w2 = d; - } - else - { - r->d = d; - r->w1 = p; - r->w2 = pool->whatprovidesdata[d]; - } + r->d = d; + r->w1 = p; + r->w2 = d ? pool->whatprovidesdata[d] : p2; r->n1 = 0; r->n2 = 0; - IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION) { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, " Add rule: "); solver_printrule(solv, SOLV_DEBUG_RULE_CREATION, r); } - return r; } + void solver_shrinkrules(Solver *solv, int nrules) { @@ -434,7 +397,7 @@ makemultiversionconflict(Solver *solv, Id n, Id con) queue_push(&q, p); } if (q.count == 1) - n = -n; /* no other package found, generate normal conflict */ + n = 0; /* no other package found, normal conflict handling */ else n = pool_queuetowhatprovides(pool, &q); queue_free(&q); @@ -442,12 +405,12 @@ makemultiversionconflict(Solver *solv, Id n, Id con) } static inline void -addpkgrule(Solver *solv, Id p, Id d, int type, Id dep) +addpkgrule(Solver *solv, Id p, Id p2, Id d, int type, Id dep) { if (!solv->ruleinfoq) - solver_addrule(solv, p, d); + solver_addrule(solv, p, p2, d); else - addpkgruleinfo(solv, p, d, type, dep); + addpkgruleinfo(solv, p, p2, d, type, dep); } #ifdef ENABLE_LINKED_PKGS @@ -469,19 +432,19 @@ addlinks(Solver *solv, Solvable *s, Id req, Queue *qr, Id prv, Queue *qp, Map *m #endif if (qr->count == 1) - addpkgrule(solv, qr->elements[0], -(s - pool->solvables), SOLVER_RULE_PKG_REQUIRES, req); + addpkgrule(solv, -(s - pool->solvables), qr->elements[0], 0, SOLVER_RULE_PKG_REQUIRES, req); else - addpkgrule(solv, -(s - pool->solvables), pool_queuetowhatprovides(pool, qr), SOLVER_RULE_PKG_REQUIRES, req); + addpkgrule(solv, -(s - pool->solvables), 0, pool_queuetowhatprovides(pool, qr), SOLVER_RULE_PKG_REQUIRES, req); if (qp->count > 1) { Id d = pool_queuetowhatprovides(pool, qp); for (i = 0; i < qr->count; i++) - addpkgrule(solv, -qr->elements[i], d, SOLVER_RULE_PKG_REQUIRES, prv); + addpkgrule(solv, -qr->elements[i], 0, d, SOLVER_RULE_PKG_REQUIRES, prv); } else if (qp->count) { for (i = 0; i < qr->count; i++) - addpkgrule(solv, qp->elements[0], -qr->elements[i], SOLVER_RULE_PKG_REQUIRES, prv); + addpkgrule(solv, -qr->elements[i], qp->elements[0], 0, SOLVER_RULE_PKG_REQUIRES, prv); } if (!m) return; /* nothing more to do if called from getpkgruleinfos() */ @@ -535,13 +498,16 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w { Pool *pool = solv->pool; Repo *installed = solv->installed; - int i, j; + int i, j, flags; Queue bq; queue_init(&bq); - + flags = dontfix ? CPLXDEPS_DONTFIX : 0; /* CNF expansion for requires, DNF + INVERT expansion for conflicts */ - i = pool_normalize_complex_dep(pool, dep, &bq, type == SOLVER_RULE_PKG_REQUIRES ? 0 : (CPLXDEPS_TODNF | CPLXDEPS_EXPAND | CPLXDEPS_INVERT)); + if (type == SOLVER_RULE_PKG_CONFLICTS) + flags |= CPLXDEPS_TODNF | CPLXDEPS_EXPAND | CPLXDEPS_INVERT; + + i = pool_normalize_complex_dep(pool, dep, &bq, flags); /* handle special cases */ if (i == 0) { @@ -552,7 +518,7 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w else { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, p), p, pool_dep2str(pool, dep)); - addpkgrule(solv, -p, 0, type == SOLVER_RULE_PKG_REQUIRES ? SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP : type, dep); + addpkgrule(solv, -p, 0, 0, type == SOLVER_RULE_PKG_REQUIRES ? SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP : type, dep); } queue_free(&bq); return; @@ -579,19 +545,15 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w if (pool->solvables[dp[j]].repo == installed) break; /* provider was installed */ if (!dp[j]) - { - POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", pool_dep2str(pool, dep), pool_solvid2str(pool, p)); - continue; - } - } - if (!*dp) - { - /* nothing provides req! */ - POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, p), p, pool_dep2str(pool, dep)); - addpkgrule(solv, -p, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, dep); - continue; + continue; } - addpkgrule(solv, -p, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, dep); + /* check if the rule contains both p and -p */ + for (j = 0; dp[j] != 0; j++) + if (dp[j] == p) + break; + if (dp[j]) + continue; + addpkgrule(solv, -p, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, dep); /* push all non-visited providers on the work queue */ if (m) for (; *dp; dp++) @@ -601,29 +563,30 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w } if (!bq.elements[i + 1]) { - Id p2 = bq.elements[i]; - /* simple rule with just two literals */ - if (dontfix && p2 < 0 && pool->solvables[-p2].repo == installed) - continue; - if (dontfix && p2 > 0 && pool->solvables[p2].repo != installed) - continue; - if (p == p2) - continue; + Id p2 = bq.elements[i++]; + /* simple rule with just two literals, we'll add a (-p, p2) rule */ + if (dontfix) + { + if (p2 < 0 && pool->solvables[-p2].repo == installed) + continue; + if (p2 > 0 && pool->solvables[p2].repo != installed) + continue; + } if (-p == p2) { if (type == SOLVER_RULE_PKG_CONFLICTS) { if (pool->forbidselfconflicts && !is_otherproviders_dep(pool, dep)) - addpkgrule(solv, -p, 0, SOLVER_RULE_PKG_SELF_CONFLICT, dep); + addpkgrule(solv, -p, 0, 0, SOLVER_RULE_PKG_SELF_CONFLICT, dep); continue; } - addpkgrule(solv, -p, 0, type, dep); + addpkgrule(solv, -p, 0, 0, type, dep); continue; } - if (p2 > 0) - addpkgrule(solv, p2, -p, type, dep); /* hack so that we don't need pool_queuetowhatprovides */ - else - addpkgrule(solv, -p, p2, type, dep); + /* check if the rule contains both p and -p */ + if (p == p2) + continue; + addpkgrule(solv, -p, p2, 0, type, dep); if (m && p2 > 0 && !MAPTST(m, p2)) queue_push(workq, p2); } @@ -667,19 +630,13 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w for (j = 0; j < qcnt; j++) if (qele[j] == p) break; - if (j == qcnt) - { - /* hack: create fake queue 'q' so that we can call pool_queuetowhatprovides */ - Queue q; - memset(&q, 0, sizeof(q)); - q.count = qcnt - 1; - q.elements = qele + 1; - addpkgrule(solv, qele[0], pool_queuetowhatprovides(pool, &q), type, dep); - if (m) - for (j = 0; j < qcnt; j++) - if (qele[j] > 0 && !MAPTST(m, qele[j])) - queue_push(workq, qele[j]); - } + if (j < qcnt) + continue; + addpkgrule(solv, qele[0], 0, pool_ids2whatprovides(pool, qele + 1, qcnt - 1), type, dep); + if (m) + for (j = 0; j < qcnt; j++) + if (qele[j] > 0 && !MAPTST(m, qele[j])) + queue_push(workq, qele[j]); } } queue_free(&bq); @@ -764,7 +721,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) : !pool_installable(pool, s)) { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", pool_solvid2str(pool, n), n); - addpkgrule(solv, -n, 0, SOLVER_RULE_PKG_NOT_INSTALLABLE, 0); + addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_NOT_INSTALLABLE, 0); } } @@ -821,10 +778,16 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) if (!*dp) { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, n), n, pool_dep2str(pool, req)); - addpkgrule(solv, -n, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, req); + addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, req); continue; } + for (i = 0; dp[i] != 0; i++) + if (n == dp[i]) + break; + if (dp[i]) + continue; /* provided by itself, no need to add rule */ + IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION) { POOL_DEBUG(SOLV_DEBUG_RULE_CREATION," %s requires %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req)); @@ -834,7 +797,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) /* add 'requires' dependency */ /* rule: (-requestor|provider1|provider2|...|providerN) */ - addpkgrule(solv, -n, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, req); + addpkgrule(solv, -n, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, req); /* push all non-visited providers on the work queue */ if (m) @@ -888,16 +851,23 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) { if (!pool->forbidselfconflicts || is_otherproviders_dep(pool, con)) continue; - addpkgrule(solv, -n, 0, SOLVER_RULE_PKG_SELF_CONFLICT, con); + addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_SELF_CONFLICT, con); continue; } if (ispatch && solv->multiversion.size && MAPTST(&solv->multiversion, p) && ISRELDEP(con)) { /* our patch conflicts with a multiversion package */ - p = -makemultiversionconflict(solv, p, con); + Id d = makemultiversionconflict(solv, p, con); + if (d) + { + addpkgrule(solv, -n, 0, d, SOLVER_RULE_PKG_CONFLICTS, con); + continue; + } } + if (p == SYSTEMSOLVABLE) + p = 0; /* rule: -n|-p: either solvable _or_ provider of conflict */ - addpkgrule(solv, -n, p == SYSTEMSOLVABLE ? 0 : -p, SOLVER_RULE_PKG_CONFLICTS, con); + addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_CONFLICTS, con); } } } @@ -930,10 +900,12 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) continue; if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) continue; + if (p == SYSTEMSOLVABLE) + p = 0; if (!isinstalled) - addpkgrule(solv, -n, -p, SOLVER_RULE_PKG_OBSOLETES, obs); + addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_OBSOLETES, obs); else - addpkgrule(solv, -n, -p, SOLVER_RULE_PKG_INSTALLED_OBSOLETES, obs); + addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_INSTALLED_OBSOLETES, obs); } } } @@ -959,10 +931,21 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) continue; if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) continue; + if (p == SYSTEMSOLVABLE) + p = 0; if (s->name == ps->name) - addpkgrule(solv, -n, -p, SOLVER_RULE_PKG_SAME_NAME, 0); + { + /* optimization: do not add the same-name conflict rule if it was + * already added when we looket at the other package. + * (this assumes pool_colormatch is symmetric) */ + if (p && m && ps->repo != installed && MAPTST(m, p) && + (ps->arch != ARCH_SRC && ps->arch != ARCH_NOSRC) && + !(solv->multiversion.size && MAPTST(&solv->multiversion, p))) + continue; + addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_SAME_NAME, 0); + } else - addpkgrule(solv, -n, -p, SOLVER_RULE_PKG_IMPLICIT_OBSOLETES, s->name); + addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_IMPLICIT_OBSOLETES, s->name); } } } @@ -1234,7 +1217,7 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) { /* a linked pseudo package. As it is linked, we do not need an update rule */ /* nevertheless we set specialupdaters so we can update */ - solver_addrule(solv, 0, 0); + solver_addrule(solv, 0, 0, 0); if (!allow_all && qs.count) { if (p != -SYSTEMSOLVABLE) @@ -1305,16 +1288,25 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) { /* could fallthrough, but then we would do pool_queuetowhatprovides twice */ queue_free(&qs); - solver_addrule(solv, p, d); /* allow update of s */ + solver_addrule(solv, p, 0, d); /* allow update of s */ return; } } } if (qs.count && p == -SYSTEMSOLVABLE) p = queue_shift(&qs); - d = qs.count ? pool_queuetowhatprovides(pool, &qs) : 0; - queue_free(&qs); - solver_addrule(solv, p, d); /* allow update of s */ + if (qs.count > 1) + { + d = pool_queuetowhatprovides(pool, &qs); + queue_free(&qs); + solver_addrule(solv, p, 0, d); /* allow update of s */ + } + else + { + d = qs.count ? qs.elements[0] : 0; + queue_free(&qs); + solver_addrule(solv, p, d, 0); /* allow update of s */ + } } static inline void @@ -1543,7 +1535,10 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) if (installed && pool->solvables[p].repo == installed && !haveinstalled) continue; /* installed package not in lock-step */ } - solver_addrule(solv, -p, lsq.count ? pool_queuetowhatprovides(pool, &lsq) : 0); + if (lsq.count < 2) + solver_addrule(solv, -p, lsq.count ? lsq.elements[0] : 0, 0); + else + solver_addrule(solv, -p, 0, pool_queuetowhatprovides(pool, &lsq)); } } queue_free(&lsq); @@ -1726,6 +1721,15 @@ solver_createdupmaps(Solver *solv) solver_addtodupmaps(solv, p, how, targeted); } } + else if (select == SOLVER_SOLVABLE_ALL) + { + FOR_POOL_SOLVABLES(p) + { + MAPSET(&solv->dupinvolvedmap, p); + if (installed && pool->solvables[p].repo != installed) + MAPSET(&solv->dupmap, p); + } + } else { targeted = how & SOLVER_TARGETED ? 1 : 0; @@ -1810,13 +1814,13 @@ solver_addduprules(Solver *solv, Map *addedmap) break; } if (!ip) - solver_addrule(solv, -p, 0); /* no match, sorry */ + solver_addrule(solv, -p, 0, 0); /* no match, sorry */ else MAPSET(&solv->dupmap, p); /* for best rules processing */ } } else if (!MAPTST(&solv->dupmap, p)) - solver_addrule(solv, -p, 0); + solver_addrule(solv, -p, 0, 0); } } solv->duprules_end = solv->nrules; @@ -2374,34 +2378,30 @@ solver_reenablepolicyrules_cleandeps(Solver *solv, Id pkg) ***/ static void -addpkgruleinfo(Solver *solv, Id p, Id d, int type, Id dep) +addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep) { Pool *pool = solv->pool; Rule *r; - Id w2, op, od, ow2; - /* check if this creates the rule we're searching for */ - r = solv->rules + solv->ruleinfoq->elements[0]; - op = r->p; - od = r->d < 0 ? -r->d - 1 : r->d; - ow2 = 0; - - /* normalize */ - w2 = d > 0 ? 0 : d; - if (p < 0 && d > 0 && (!pool->whatprovidesdata[d] || !pool->whatprovidesdata[d + 1])) + if (d) { - w2 = pool->whatprovidesdata[d]; - d = 0; - } - if (p > 0 && d < 0) /* this hack is used for package links and complex deps */ - { - w2 = p; - p = d; + assert(!p2 && d > 0); + if (!pool->whatprovidesdata[d]) + d = 0; + else if (!pool->whatprovidesdata[d + 1]) + { + p2 = pool->whatprovidesdata[d]; + d = 0; + } } - if (d > 0) + /* check if this creates the rule we're searching for */ + r = solv->rules + solv->ruleinfoq->elements[0]; + if (d) { - if (p != op && !od) + /* three or more literals */ + Id od = r->d < 0 ? -r->d - 1 : r->d; + if (p != r->p && !od) return; if (d != od) { @@ -2413,46 +2413,33 @@ addpkgruleinfo(Solver *solv, Id p, Id d, int type, Id dep) if (*odp) return; } - w2 = 0; - /* handle multiversion conflict rules */ - if (p < 0 && pool->whatprovidesdata[d] < 0) - { - w2 = pool->whatprovidesdata[d]; - /* XXX: free memory */ - } + if (p < 0 && pool->whatprovidesdata[d] < 0 && type == SOLVER_RULE_PKG_CONFLICTS) + p2 = pool->whatprovidesdata[d]; } else { - if (od) - return; - ow2 = r->w2; - if (p > w2) + /* one or two literals */ + Id op = p, op2 = p2; + if (op2 && op > op2) /* normalize */ { - if (w2 != op || p != ow2) - return; + Id o = op; + op = op2; + op2 = o; } - else + if (r->p != op || r->w2 != op2 || (r->d && r->d != -1)) + return; + if (type == SOLVER_RULE_PKG_CONFLICTS && !p2) + p2 = -SYSTEMSOLVABLE; + if (type == SOLVER_RULE_PKG_SAME_NAME) { - if (p != op || w2 != ow2) - return; + p = op; /* we normalize same name order */ + p2 = op2; } - /* should use a different type instead */ - if (type == SOLVER_RULE_PKG_CONFLICTS && !w2) - w2 = -SYSTEMSOLVABLE; } /* yep, rule matches. record info */ queue_push(solv->ruleinfoq, type); - if (type == SOLVER_RULE_PKG_SAME_NAME) - { - /* we normalize same name order */ - queue_push(solv->ruleinfoq, op < 0 ? -op : 0); - queue_push(solv->ruleinfoq, ow2 < 0 ? -ow2 : 0); - } - else - { - queue_push(solv->ruleinfoq, p < 0 ? -p : 0); - queue_push(solv->ruleinfoq, w2 < 0 ? -w2 : 0); - } + queue_push(solv->ruleinfoq, p < 0 ? -p : 0); + queue_push(solv->ruleinfoq, p2 < 0 ? -p2 : 0); queue_push(solv->ruleinfoq, dep); } @@ -2706,7 +2693,7 @@ solver_ruleclass(Solver *solv, Id rid) return SOLVER_RULE_YUMOBS; if (rid >= solv->choicerules && rid < solv->choicerules_end) return SOLVER_RULE_CHOICE; - if (rid >= solv->learntrules) + if (rid >= solv->learntrules && rid < solv->nrules) return SOLVER_RULE_LEARNT; return SOLVER_RULE_UNKNOWN; } @@ -3068,7 +3055,7 @@ solver_addchoicerules(Solver *solv) lastaddedd = d; lastaddedcnt = q.count; - solver_addrule(solv, r->p, d); + solver_addrule(solv, r->p, 0, d); queue_push(&solv->weakruleq, solv->nrules - 1); solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid; #if 0 @@ -3200,7 +3187,10 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) if (q.count == oldcnt) continue; /* nothing filtered */ p2 = queue_shift(&q); - solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0); + 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)); } } @@ -3267,7 +3257,10 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) } } p2 = queue_shift(&q); - solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0); + 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, p); } } @@ -3481,11 +3474,10 @@ for (j = 0; j < qq.count; j++) if (group != groupk && k > groupstart) { /* add the rule */ - Queue qhelper; - memset(&qhelper, 0, sizeof(qhelper)); - qhelper.count = k - groupstart; - qhelper.elements = qq.elements + groupstart; - solver_addrule(solv, -p, pool_queuetowhatprovides(pool, &qhelper)); + if (k - groupstart == 1) + solver_addrule(solv, -p, qq.elements[groupstart], 0); + else + solver_addrule(solv, -p, 0, pool_ids2whatprovides(pool, qq.elements + groupstart, k - groupstart)); queue_push(&yumobsinfoq, qo.elements[i]); } groupstart = k + 1; @@ -3538,8 +3530,6 @@ dep_pkgcheck(Solver *solv, Id dep, Map *m, Queue *q) } if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) return; - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) - return; } } FOR_PROVIDES(p, pp, dep) @@ -3576,8 +3566,6 @@ check_xsupp(Solver *solv, Queue *depq, Id dep) #else return 0; #endif - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) - return solver_dep_installed(solv, rd->evr); } if (depq && rd->flags == REL_NAMESPACE) { @@ -3783,7 +3771,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) /* have special namespace cleandeps erases */ if (iq.count) { - for (ip = solv->installed->start; ip < solv->installed->end; ip++) + for (ip = installed->start; ip < installed->end; ip++) { s = pool->solvables + ip; if (s->repo != installed) @@ -3792,7 +3780,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) continue; supp = s->repo->idarraydata + s->supplements; while ((sup = *supp++) != 0) - if (check_xsupp(solv, &iq, sup) && !check_xsupp(solv, 0, sup)) + if (ISRELDEP(sup) && check_xsupp(solv, &iq, sup) && !check_xsupp(solv, 0, sup)) { #ifdef CLEANDEPSDEBUG printf("xsupp %s from %s\n", pool_dep2str(pool, sup), pool_solvid2str(pool, ip)); diff --git a/src/rules.h b/src/rules.h index 8f55af3..606819b 100644 --- a/src/rules.h +++ b/src/rules.h @@ -99,7 +99,7 @@ solver_enablerule(struct _Solver *solv, Rule *r) r->d = -r->d - 1; } -extern Rule *solver_addrule(struct _Solver *solv, Id p, Id d); +extern Rule *solver_addrule(struct _Solver *solv, Id p, Id p2, Id d); extern void solver_unifyrules(struct _Solver *solv); extern int solver_rulecmp(struct _Solver *solv, Rule *r1, Rule *r2); extern void solver_shrinkrules(struct _Solver *solv, int nrules); diff --git a/src/solver.c b/src/solver.c index 46d0ca3..f551731 100644 --- a/src/solver.c +++ b/src/solver.c @@ -30,6 +30,7 @@ #define RULES_BLOCK 63 + /******************************************************************** * * dependency check helpers @@ -104,93 +105,66 @@ solver_splitprovides(Solver *solv, Id dep, Map *m) } -/*------------------------------------------------------------------- - * solver_dep_installed - */ - -int -solver_dep_installed(Solver *solv, Id dep) -{ -#if 0 - Pool *pool = solv->pool; - Id p, pp; - - if (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags == REL_AND) - { - if (!solver_dep_installed(solv, rd->name)) - return 0; - return solver_dep_installed(solv, rd->evr); - } - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) - return solver_dep_installed(solv, rd->evr); - } - FOR_PROVIDES(p, pp, dep) - { - if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed)) - return 1; - } -#endif - return 0; -} - -/* mirrors solver_dep_installed, but returns 2 if a - * dependency listed in solv->installsuppdepq was involved */ +/* mirrors solver_dep_fulfilled, but returns 2 if a new package + * was involved */ static int -solver_check_installsuppdepq_dep(Solver *solv, Id dep) +solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep) { Pool *pool = solv->pool; Id p, pp; - Queue *q; + int r; if (ISRELDEP(dep)) { Reldep *rd = GETRELDEP(pool, dep); if (rd->flags == REL_AND) { - int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name); + int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); if (!r1) return 0; - r2 = solver_check_installsuppdepq_dep(solv, rd->evr); + r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); if (!r2) return 0; return r1 == 2 || r2 == 2 ? 2 : 1; } if (rd->flags == REL_OR) { - int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name); - r2 = solver_check_installsuppdepq_dep(solv, rd->evr); + int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); + r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); if (!r1 && !r2) return 0; return r1 == 2 || r2 == 2 ? 2 : 1; } if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) return solver_splitprovides(solv, rd->evr, 0); - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) - return solver_dep_installed(solv, rd->evr); - if (rd->flags == REL_NAMESPACE && (q = solv->installsuppdepq) != 0) + if (rd->flags == REL_NAMESPACE && solv->installsuppdepq) { + Queue *q = solv->installsuppdepq; int i; for (i = 0; i < q->count; i++) if (q->elements[i] == dep || q->elements[i] == rd->name) return 2; } } + r = 0; FOR_PROVIDES(p, pp, dep) if (solv->decisionmap[p] > 0) - return 1; - return 0; + { + Solvable *s = pool->solvables + p; + if (s->repo && s->repo != solv->installed) + return 2; + r = 1; + } + return r; } static int -solver_check_installsuppdepq(Solver *solv, Solvable *s) +solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s) { Id sup, *supp; supp = s->repo->idarraydata + s->supplements; while ((sup = *supp++) != 0) - if (solver_check_installsuppdepq_dep(solv, sup) == 2) + if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2) return 1; return 0; } @@ -208,17 +182,10 @@ autouninstall(Solver *solv, Id *problem) { if (v < 0) extraflags &= solv->job.elements[-v - 1]; - if (v >= solv->featurerules && v < solv->featurerules_end) - if (v > lastfeature) - lastfeature = v; if (v >= solv->updaterules && v < solv->updaterules_end) { - /* check if identical to feature rule */ - Id p = solv->rules[v].p; - Rule *r; - if (p <= 0) - continue; - r = solv->rules + solv->featurerules + (p - solv->installed->start); + /* check if identical to feature rule, we don't like that */ + Rule *r = solv->rules + solv->featurerules + (v - solv->updaterules); if (!r->p) { /* update rule == feature rule */ @@ -362,7 +329,7 @@ makeruledecisions(Solver *solv) continue; /* do weak rules in phase 2 */ - if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri)) + if (ri < solv->learntrules && solv->weakrulemap.size && MAPTST(&solv->weakrulemap, ri)) continue; v = r->p; @@ -504,7 +471,7 @@ makeruledecisions(Solver *solv) if (rr->p != vv /* not affecting the literal */ && rr->p != -vv) continue; - if (MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */ + if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */ continue; POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i); @@ -531,6 +498,8 @@ makeruledecisions(Solver *solv) /* * phase 2: now do the weak assertions */ + if (!solv->weakrulemap.size) + break; /* no weak rules, no phase 2 */ for (ii = 0; ii < solv->ruleassertions.count; ii++) { ri = solv->ruleassertions.elements[ii]; @@ -600,14 +569,9 @@ makewatches(Solver *solv) int nsolvables = solv->pool->nsolvables; solv_free(solv->watches); - /* lower half for removals, upper half for installs */ + /* lower half for removals, upper half for installs */ solv->watches = solv_calloc(2 * nsolvables, sizeof(Id)); -#if 1 - /* do it reverse so pkg rules get triggered first (XXX: obsolete?) */ for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--) -#else - for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++) -#endif { if (!r->w2) /* assertions do not need watches */ continue; @@ -678,7 +642,6 @@ propagate(Solver *solv, int level) Id p, pkg, other_watch; Id *dp; Id *decisionmap = solv->decisionmap; - Id *watches = solv->watches + pool->nsolvables; /* place ptr in middle */ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n"); @@ -686,10 +649,10 @@ propagate(Solver *solv, int level) /* foreach non-propagated decision */ while (solv->propagate_index < solv->decisionq.count) { - /* - * 'pkg' was just decided - * negate because our watches trigger if literal goes FALSE - */ + /* + * 'pkg' was just decided + * negate because our watches trigger if literal goes FALSE + */ pkg = -solv->decisionq.elements[solv->propagate_index++]; IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) @@ -718,11 +681,11 @@ propagate(Solver *solv, int level) solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r); } - /* 'pkg' was just decided (was set to FALSE) - * - * now find other literal watch, check clause - * and advance on linked list - */ + /* + * 'pkg' was just decided (was set to FALSE), so this rule + * may now be unit. + */ + /* find the other watch */ if (pkg == r->w1) { other_watch = r->w2; @@ -734,17 +697,16 @@ propagate(Solver *solv, int level) next_rp = &r->n2; } - /* - * This term is already true (through the other literal) - * so we have nothing to do - */ + /* + * if the other watch is true we have nothing to do + */ if (DECISIONMAP_TRUE(other_watch)) continue; - /* - * The other literal is FALSE or UNDEF - * - */ + /* + * The other literal is FALSE or UNDEF + * + */ if (r->d) { @@ -755,6 +717,8 @@ propagate(Solver *solv, int level) * and not FALSE * * (TRUE is also ok, in that case the rule is fulfilled) + * As speed matters here we do not use the FOR_RULELITERALS + * macro. */ if (r->p /* we have a 'p' */ && r->p != other_watch /* which is not watched */ @@ -786,7 +750,7 @@ propagate(Solver *solv, int level) if (p > 0) POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p)); else - POOL_DEBUG(SOLV_DEBUG_PROPAGATE," -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p)); + POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p)); } *rp = *next_rp; @@ -853,25 +817,96 @@ propagate(Solver *solv, int level) /*------------------------------------------------------------------- * + * revert + * revert decisionq to a level + */ + +static void +revert(Solver *solv, int level) +{ + Pool *pool = solv->pool; + Id v, vv; + while (solv->decisionq.count) + { + v = solv->decisionq.elements[solv->decisionq.count - 1]; + vv = v > 0 ? v : -v; + if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level) + break; + POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]); + solv->decisionmap[vv] = 0; + solv->decisionq.count--; + solv->decisionq_why.count--; + solv->propagate_index = solv->decisionq.count; + } + while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= level) + solv->branches.count -= solv->branches.elements[solv->branches.count - 2]; + if (solv->recommends_index > solv->decisionq.count) + solv->recommends_index = -1; /* rebuild recommends/suggests maps */ + if (solv->decisionq.count < solv->decisioncnt_jobs) + solv->decisioncnt_jobs = 0; + if (solv->decisionq.count < solv->decisioncnt_update) + solv->decisioncnt_update = 0; + if (solv->decisionq.count < solv->decisioncnt_keep) + solv->decisioncnt_keep = 0; + if (solv->decisionq.count < solv->decisioncnt_resolve) + solv->decisioncnt_resolve = 0; + if (solv->decisionq.count < solv->decisioncnt_weak) + solv->decisioncnt_weak= 0; + if (solv->decisionq.count < solv->decisioncnt_orphan) + solv->decisioncnt_orphan = 0; +} + +/*------------------------------------------------------------------- + * + * watch2onhighest - put watch2 on literal with highest level + */ + +static inline void +watch2onhighest(Solver *solv, Rule *r) +{ + int l, wl = 0; + Id d, v, *dp; + + d = r->d < 0 ? -r->d - 1 : r->d; + if (!d) + return; /* binary rule, both watches are set */ + dp = solv->pool->whatprovidesdata + d; + while ((v = *dp++) != 0) + { + l = solv->decisionmap[v < 0 ? -v : v]; + if (l < 0) + l = -l; + if (l > wl) + { + r->w2 = dp[-1]; + wl = l; + } + } +} + + +/*------------------------------------------------------------------- + * * analyze * and learn */ static int -analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp) +analyze(Solver *solv, int level, Rule *c, Rule **lrp) { Pool *pool = solv->pool; - Queue r; - Id r_buf[4]; + Queue q; + Rule *r; + Id q_buf[8]; int rlevel = 1; Map seen; /* global? */ - Id d, v, vv, *dp, why; + Id p = 0, pp, v, vv, why; int l, i, idx; int num = 0, l1num = 0; int learnt_why = solv->learnt_pool.count; Id *decisionmap = solv->decisionmap; - queue_init_buffer(&r, r_buf, sizeof(r_buf)/sizeof(*r_buf)); + queue_init_buffer(&q, q_buf, sizeof(q_buf)/sizeof(*q_buf)); POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level); map_init(&seen, pool->nsolvables); @@ -881,43 +916,31 @@ analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp) IF_POOLDEBUG (SOLV_DEBUG_ANALYZE) solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c); queue_push(&solv->learnt_pool, c - solv->rules); - d = c->d < 0 ? -c->d - 1 : c->d; - dp = d ? pool->whatprovidesdata + d : 0; - /* go through all literals of the rule */ - for (i = -1; ; i++) + FOR_RULELITERALS(v, pp, c) { - if (i == -1) - v = c->p; - else if (d == 0) - v = i ? 0 : c->w2; - else - v = *dp++; - if (v == 0) - break; - if (DECISIONMAP_TRUE(v)) /* the one true literal */ continue; vv = v > 0 ? v : -v; if (MAPTST(&seen, vv)) continue; + MAPSET(&seen, vv); /* mark that we also need to look at this literal */ l = solv->decisionmap[vv]; if (l < 0) l = -l; - MAPSET(&seen, vv); /* mark that we also need to look at this literal */ if (l == 1) l1num++; /* need to do this one in level1 pass */ else if (l == level) num++; /* need to do this one as well */ else { - queue_push(&r, v); /* not level1 or conflict level, add to new rule */ + queue_push(&q, v); /* not level1 or conflict level, add to new rule */ if (l > rlevel) rlevel = l; } } l1retry: if (!num && !--l1num) - break; /* all level 1 literals done */ + break; /* all literals done */ /* find the next literal to investigate */ /* (as num + l1num > 0, we know that we'll always find one) */ @@ -933,14 +956,15 @@ l1retry: if (num && --num == 0) { - *pr = -v; /* so that v doesn't get lost */ + /* done with normal literals, now start level 1 literal processing */ + p = -v; /* so that v doesn't get lost */ if (!l1num) break; POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num); /* clear non-l1 bits from seen map */ - for (i = 0; i < r.count; i++) + for (i = 0; i < q.count; i++) { - v = r.elements[i]; + v = q.elements[i]; MAPCLR(&seen, v > 0 ? v : -v); } /* only level 1 marks left in seen map */ @@ -954,27 +978,49 @@ l1retry: c = solv->rules + why; } map_free(&seen); - - if (r.count == 0) - *dr = 0; - else if (r.count == 1 && r.elements[0] < 0) - *dr = r.elements[0]; - else - *dr = pool_queuetowhatprovides(pool, &r); + assert(p != 0); + assert(rlevel > 0 && rlevel < level); IF_POOLDEBUG (SOLV_DEBUG_ANALYZE) { POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level); - solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, *pr); - for (i = 0; i < r.count; i++) - solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, r.elements[i]); + solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p); + for (i = 0; i < q.count; i++) + solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, q.elements[i]); } /* push end marker on learnt reasons stack */ queue_push(&solv->learnt_pool, 0); - if (whyp) - *whyp = learnt_why; - queue_free(&r); solv->stats_learned++; - return rlevel; + + POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, rlevel); + level = rlevel; + revert(solv, level); + if (q.count < 2) + { + Id d = q.count ? q.elements[0] : 0; + queue_free(&q); + r = solver_addrule(solv, p, d, 0); + } + else + { + Id d = pool_queuetowhatprovides(pool, &q); + queue_free(&q); + r = solver_addrule(solv, p, 0, d); + } + assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules); + queue_push(&solv->learnt_why, learnt_why); + if (r->w2) + { + /* needs watches */ + watch2onhighest(solv, r); + addwatches_rule(solv, r); + } + else + { + /* rule is an assertion */ + queue_push(&solv->ruleassertions, r - solv->rules); + } + *lrp = r; + return level; } @@ -989,7 +1035,6 @@ l1retry: void solver_reset(Solver *solv) { - Pool *pool = solv->pool; int i; Id v; @@ -1008,10 +1053,6 @@ solver_reset(Solver *solv) /* adapt learnt rule status to new set of enabled/disabled rules */ enabledisablelearntrules(solv); - - /* redo all assertion rule decisions */ - makeruledecisions(solv); - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count); } @@ -1041,7 +1082,7 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen) analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen); return; } - if (MAPTST(&solv->weakrulemap, why)) + if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, why)) if (!*lastweakp || why > *lastweakp) *lastweakp = why; /* do not add pkg rules to problem */ @@ -1079,7 +1120,7 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen) /*------------------------------------------------------------------- * - * analyze_unsolvable + * analyze_unsolvable (called from setpropagatelearn) * * We know that the problem is not solvable. Record all involved * rules (i.e. the "proof") into solv->learnt_pool. @@ -1090,11 +1131,11 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen) * If the proof contains at least one weak rule, we disable the * last of them. * - * Otherwise we return 0 if disablerules is not set or disable - * _all_ of the problem rules and return 1. + * Otherwise we return -1 if disablerules is not set or disable + * _all_ of the problem rules and return 0. * - * return: 1 - disabled some rules, try again - * 0 - hopeless + * return: 0 - disabled some rules, try again + * -1 - hopeless */ static int @@ -1102,10 +1143,10 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) { Pool *pool = solv->pool; Rule *r; - Map seen; /* global to speed things up? */ + Map involved; /* global to speed things up? */ Map rseen; - Id d, v, vv, *dp, why; - int l, i, idx; + Id pp, v, vv, why; + int i, idx; Id *decisionmap = solv->decisionmap; int oldproblemcount; int oldlearntpoolcount; @@ -1123,38 +1164,25 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) queue_push(&solv->problems, 0); r = cr; - map_init(&seen, pool->nsolvables); + map_init(&involved, pool->nsolvables); map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0); if (record_proof) queue_push(&solv->learnt_pool, r - solv->rules); lastweak = 0; analyze_unsolvable_rule(solv, r, &lastweak, &rseen); - d = r->d < 0 ? -r->d - 1 : r->d; - dp = d ? pool->whatprovidesdata + d : 0; - for (i = -1; ; i++) + FOR_RULELITERALS(v, pp, r) { - if (i == -1) - v = r->p; - else if (d == 0) - v = i ? 0 : r->w2; - else - v = *dp++; - if (v == 0) - break; if (DECISIONMAP_TRUE(v)) /* the one true literal */ continue; vv = v > 0 ? v : -v; - l = solv->decisionmap[vv]; - if (l < 0) - l = -l; - MAPSET(&seen, vv); + MAPSET(&involved, vv); } idx = solv->decisionq.count; while (idx > 0) { v = solv->decisionq.elements[--idx]; vv = v > 0 ? v : -v; - if (!MAPTST(&seen, vv) || vv == SYSTEMSOLVABLE) + if (!MAPTST(&involved, vv) || vv == SYSTEMSOLVABLE) continue; why = solv->decisionq_why.elements[idx]; assert(why > 0); @@ -1162,28 +1190,15 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) queue_push(&solv->learnt_pool, why); r = solv->rules + why; analyze_unsolvable_rule(solv, r, &lastweak, &rseen); - d = r->d < 0 ? -r->d - 1 : r->d; - dp = d ? pool->whatprovidesdata + d : 0; - for (i = -1; ; i++) + FOR_RULELITERALS(v, pp, r) { - if (i == -1) - v = r->p; - else if (d == 0) - v = i ? 0 : r->w2; - else - v = *dp++; - if (v == 0) - break; if (DECISIONMAP_TRUE(v)) /* the one true literal */ continue; vv = v > 0 ? v : -v; - l = solv->decisionmap[vv]; - if (l < 0) - l = -l; - MAPSET(&seen, vv); + MAPSET(&involved, vv); } } - map_free(&seen); + map_free(&involved); map_free(&rseen); queue_push(&solv->problems, 0); /* mark end of this problem */ @@ -1204,7 +1219,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) if (v < 0) solver_reenablepolicyrules(solv, -v); solver_reset(solv); - return 1; + return 0; } if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0) @@ -1212,7 +1227,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) solv->problems.count = oldproblemcount; solv->learnt_pool.count = oldlearntpoolcount; solver_reset(solv); - return 1; + return 0; } /* finish proof */ @@ -1229,84 +1244,10 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) solver_disableproblem(solv, solv->problems.elements[i]); /* XXX: might want to enable all weak rules again */ solver_reset(solv); - return 1; + return 0; } POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n"); - return 0; -} - - -/********************************************************************/ -/* Decision revert */ - -/*------------------------------------------------------------------- - * - * revert - * revert decisionq to a level - */ - -static void -revert(Solver *solv, int level) -{ - Pool *pool = solv->pool; - Id v, vv; - while (solv->decisionq.count) - { - v = solv->decisionq.elements[solv->decisionq.count - 1]; - vv = v > 0 ? v : -v; - if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level) - break; - POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]); - solv->decisionmap[vv] = 0; - solv->decisionq.count--; - solv->decisionq_why.count--; - solv->propagate_index = solv->decisionq.count; - } - while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= level) - solv->branches.count -= solv->branches.elements[solv->branches.count - 2]; - if (solv->recommends_index > solv->decisionq.count) - solv->recommends_index = -1; /* rebuild recommends/suggests maps */ - if (solv->decisionq.count < solv->decisioncnt_jobs) - solv->decisioncnt_jobs = 0; - if (solv->decisionq.count < solv->decisioncnt_update) - solv->decisioncnt_update = 0; - if (solv->decisionq.count < solv->decisioncnt_keep) - solv->decisioncnt_keep = 0; - if (solv->decisionq.count < solv->decisioncnt_resolve) - solv->decisioncnt_resolve = 0; - if (solv->decisionq.count < solv->decisioncnt_weak) - solv->decisioncnt_weak= 0; - if (solv->decisionq.count < solv->decisioncnt_orphan) - solv->decisioncnt_orphan = 0; -} - - -/*------------------------------------------------------------------- - * - * watch2onhighest - put watch2 on literal with highest level - */ - -static inline void -watch2onhighest(Solver *solv, Rule *r) -{ - int l, wl = 0; - Id d, v, *dp; - - d = r->d < 0 ? -r->d - 1 : r->d; - if (!d) - return; /* binary rule, both watches are set */ - dp = solv->pool->whatprovidesdata + d; - while ((v = *dp++) != 0) - { - l = solv->decisionmap[v < 0 ? -v : v]; - if (l < 0) - l = -l; - if (l > wl) - { - r->w2 = dp[-1]; - wl = l; - } - } + return -1; } @@ -1322,7 +1263,7 @@ watch2onhighest(Solver *solv, Rule *r) * rule to learnt rule set, make decision from learnt * rule (always unit) and re-propagate. * - * returns the new solver level or 0 if unsolvable + * returns the new solver level or -1 if unsolvable * */ @@ -1330,11 +1271,8 @@ static int setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid) { Pool *pool = solv->pool; - Rule *r; - Id p = 0, d = 0; - int l, why; + Rule *r, *lr; - assert(ruleid >= 0); if (decision) { level++; @@ -1345,6 +1283,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul queue_push(&solv->decisionq, decision); queue_push(&solv->decisionq_why, -ruleid); /* <= 0 -> free decision */ } + assert(ruleid >= 0 && level > 0); for (;;) { r = propagate(solv, level); @@ -1353,36 +1292,18 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul if (level == 1) return analyze_unsolvable(solv, r, disablerules); POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules)); - l = analyze(solv, level, r, &p, &d, &why); /* learnt rule in p and d */ - assert(l > 0 && l < level); - POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l); - level = l; - revert(solv, level); - r = solver_addrule(solv, p, d); - assert(r); - assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules); - queue_push(&solv->learnt_why, why); - if (d) - { - /* at least 2 literals, needs watches */ - watch2onhighest(solv, r); - addwatches_rule(solv, r); - } - else - { - /* learnt rule is an assertion */ - queue_push(&solv->ruleassertions, r - solv->rules); - } + level = analyze(solv, level, r, &lr); /* the new rule is unit by design */ - solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level; - queue_push(&solv->decisionq, p); - queue_push(&solv->decisionq_why, r - solv->rules); + decision = lr->p; + solv->decisionmap[decision > 0 ? decision : -decision] = decision > 0 ? level : -level; + queue_push(&solv->decisionq, decision); + queue_push(&solv->decisionq_why, lr - solv->rules); IF_POOLDEBUG (SOLV_DEBUG_ANALYZE) { POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: "); - solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p); + solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, decision); POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: "); - solver_printrule(solv, SOLV_DEBUG_ANALYZE, r); + solver_printrule(solv, SOLV_DEBUG_ANALYZE, lr); } } return level; @@ -1505,7 +1426,7 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) * install best package from the queue. We add an extra package, inst, if * provided. See comment in weak install section. * - * returns the new solver level or 0 if unsolvable + * returns the new solver level or -1 if unsolvable * */ @@ -1651,8 +1572,6 @@ resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq) level = selectandinstall(solv, level, dq, disablerules, i); if (level <= olevel) { - if (level == 0) - return 0; /* unsolvable */ if (level == olevel) { i--; @@ -1791,6 +1710,8 @@ solver_get_flag(Solver *solv, int flag) return solv->focus_installed; case SOLVER_FLAG_YUM_OBSOLETES: return solv->do_yum_obsoletes; + case SOLVER_FLAG_NEED_UPDATEPROVIDE: + return solv->needupdateprovide; default: break; } @@ -1866,14 +1787,17 @@ solver_set_flag(Solver *solv, int flag, int value) case SOLVER_FLAG_YUM_OBSOLETES: solv->do_yum_obsoletes = value; break; + case SOLVER_FLAG_NEED_UPDATEPROVIDE: + solv->needupdateprovide = value; + break; default: break; } return old; } -int -cleandeps_check_mistakes(Solver *solv, int level) +static int +cleandeps_check_mistakes(Solver *solv) { Pool *pool = solv->pool; Rule *r; @@ -1919,8 +1843,6 @@ cleandeps_check_mistakes(Solver *solv, int level) solver_reenablepolicyrules_cleandeps(solv, i); mademistake = 1; } - if (mademistake) - solver_reset(solv); return mademistake; } @@ -2093,7 +2015,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) int i, j, n; Solvable *s; Pool *pool = solv->pool; - Id p, pp, *dp; + Id p, pp, *dp, postponed; int minimizationsteps; int installedpos = solv->installed ? solv->installed->start : 0; @@ -2104,10 +2026,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i); } - POOL_DEBUG(SOLV_DEBUG_SOLVER, "initial decisions: %d\n", solv->decisionq.count); - /* start SAT algorithm */ - level = 1; + level = 0; systemlevel = level + 1; POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n"); @@ -2116,7 +2036,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) /* * here's the main loop: - * 1) propagate new decisions (only needed once) + * 1) decide assertion rules and propagate * 2) fulfill jobs * 3) try to keep installed packages * 4) fulfill all unresolved rules @@ -2132,16 +2052,24 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) /* * initial propagation of the assertions */ - if (level == 1) + if (level <= 0) { - POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagating (propagate_index: %d; size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count); + if (level < 0) + break; + makeruledecisions(solv); + level = 1; + if (!disablerules && solv->problems.count) + { + level = -1; + 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) { - if (analyze_unsolvable(solv, r, disablerules)) - continue; - level = 0; - break; /* unsolvable */ + level = analyze_unsolvable(solv, r, disablerules); + continue; } + systemlevel = level + 1; } /* @@ -2152,11 +2080,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) olevel = level; level = resolve_jobrules(solv, level, disablerules, &dq); if (level < olevel) - { - if (level == 0) - break; /* unsolvable */ - continue; - } + continue; systemlevel = level + 1; } @@ -2273,15 +2197,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) { olevel = level; level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules); - if (level == 0) - { - queue_free(&dq); - queue_free(&dqs); - return; - } if (level <= olevel) { - if (level == 1 || level < passlevel) + if (level < passlevel) break; /* trouble */ if (level < olevel) n = installed->start; /* redo all */ @@ -2308,11 +2226,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i)); level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules); } - if (level == 0) - break; if (level <= olevel) { - if (level == 1 || level < passlevel) + if (level < passlevel) break; /* trouble */ if (level < olevel) n = installed->start; /* redo all */ @@ -2329,8 +2245,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) } installedpos = installed->start; /* reset installedpos */ } - if (level == 0) - break; /* unsolvable */ systemlevel = level + 1; if (pass < 2) continue; /* had trouble, retry */ @@ -2343,11 +2257,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) olevel = level; level = resolve_jobrules(solv, level, disablerules, &dq); if (level < olevel) - { - if (level == 0) - break; /* unsolvable */ - continue; - } + continue; systemlevel = level + 1; } @@ -2360,8 +2270,17 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) if (!solv->decisioncnt_resolve) solv->decisioncnt_resolve = solv->decisionq.count; POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n"); - for (i = 1, n = 1; n < solv->nrules; i++, n++) + postponed = 0; + for (i = 1, n = 1; ; i++, n++) { + if (n >= solv->nrules) + { + if (postponed <= 0) + break; + i = postponed; + postponed = -1; + n = 1; + } if (i == solv->nrules) i = 1; r = solv->rules + i; @@ -2443,22 +2362,27 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) } } + if (dq.count > 1 && postponed >= 0) + { + policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE_NOREORDER); + if (dq.count > 1) + { + if (!postponed) + postponed = i; + continue; + } + } + olevel = level; level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules); - if (level == 0) - break; /* unsolvable */ - if (level < systemlevel || level == 1) + if (level < systemlevel) break; /* trouble */ /* something changed, so look at all rules again */ n = 0; } - if (n != solv->nrules) /* ran into trouble? */ - { - if (level == 0) - break; /* unsolvable */ - continue; /* start over */ - } + if (n < solv->nrules) /* ran into trouble? */ + continue; /* start over */ /* decide leftover cleandeps packages */ if (solv->cleandepsmap.size && solv->installed) @@ -2586,39 +2510,15 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) /* filter out all already supplemented packages if requested */ if (!solv->addalreadyrecommended && dqs.count) { - /* turn off all new packages */ - for (i = 0; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p < 0) - continue; - s = pool->solvables + p; - if (s->repo && s->repo != solv->installed) - solv->decisionmap[p] = -solv->decisionmap[p]; - } /* filter out old supplements */ for (i = j = 0; i < dqs.count; i++) { p = dqs.elements[i]; s = pool->solvables + p; - if (!s->supplements) - continue; - if (!solver_is_supplementing(solv, s)) - dqs.elements[j++] = p; - else if (solv->installsuppdepq && solver_check_installsuppdepq(solv, s)) + if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s)) dqs.elements[j++] = p; } dqs.count = j; - /* undo turning off */ - for (i = 0; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p < 0) - continue; - s = pool->solvables + p; - if (s->repo && s->repo != solv->installed) - solv->decisionmap[p] = -solv->decisionmap[p]; - } } /* multiversion doesn't mix well with supplements. @@ -2665,8 +2565,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) else POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); level = setpropagatelearn(solv, level, p, 0, 0); - if (level == 0) - break; continue; /* back to main loop */ } @@ -2693,8 +2591,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) if (i < dqs.count || solv->decisionq.count < decisioncount) { map_free(&dqmap); - if (level == 0) - break; continue; } @@ -2749,8 +2645,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) break; /* had a problem above, quit loop */ } map_free(&dqmap); - if (level == 0) - break; continue; /* back to main loop so that all deps are checked */ } } @@ -2780,11 +2674,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) break; } if (installedone || i < solv->orphaned.count) - { - if (level == 0) - break; - continue; /* back to main loop */ - } + continue; /* back to main loop */ for (i = 0; i < solv->orphaned.count; i++) { p = solv->orphaned.elements[i]; @@ -2797,11 +2687,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) break; } if (i < solv->orphaned.count) - { - if (level == 0) - break; - continue; /* back to main loop */ - } + continue; /* back to main loop */ if (solv->brokenorphanrules) { solver_check_brokenorphanrules(solv, &dq); @@ -2817,8 +2703,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) if (level < olevel) break; } - if (level == 0) - break; continue; } } @@ -2841,21 +2725,14 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) break; } if (p < solv->installed->end) - { - if (level == 0) - break; - continue; /* back to main loop */ - } + continue; /* back to main loop */ } - if (solv->installed && solv->cleandepsmap.size) + if (solv->installed && solv->cleandepsmap.size && cleandeps_check_mistakes(solv)) { - if (cleandeps_check_mistakes(solv, level)) - { - level = 1; /* restart from scratch */ - systemlevel = level + 1; - continue; - } + solver_reset(solv); + level = 0; /* restart from scratch */ + continue; } if (solv->solution_callback) @@ -2884,8 +2761,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) while (i > 0 && solv->branches.elements[i - 1] > 0) i--; level = takebranch(solv, i, endi, "branching", disablerules); - if (level == 0) - break; continue; } } @@ -2941,8 +2816,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) { minimizationsteps++; level = takebranch(solv, lasti, lastiend, "minimizing", disablerules); - if (level == 0) - break; continue; /* back to main loop */ } } @@ -2955,7 +2828,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n"); queue_free(&dq); queue_free(&dqs); - if (level == 0) + if (level < 0) { /* unsolvable */ solv->decisioncnt_jobs = solv->decisionq.count; @@ -3158,9 +3031,9 @@ solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap) * add a rule created by a job, record job number and weak flag */ static inline void -solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak) +solver_addjobrule(Solver *solv, Id p, Id p2, Id d, Id job, int weak) { - solver_addrule(solv, p, d); + solver_addrule(solv, p, p2, d); queue_push(&solv->ruletojob, job); if (weak) queue_push(&solv->weakruleq, solv->nrules - 1); @@ -3360,6 +3233,39 @@ deduceq2addedmap(Solver *solv, Map *addedmap) } } +#ifdef ENABLE_COMPLEX_DEPS +static int +add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak) +{ + Pool *pool = solv->pool; + Queue bq; + int i, j; + + queue_init(&bq); + i = pool_normalize_complex_dep(pool, dep, &bq, flags | CPLXDEPS_EXPAND); + if (i == 0 || i == 1) + { + queue_free(&bq); + if (i == 0) + solver_addjobrule(solv, -SYSTEMSOLVABLE, 0, 0, jobidx, weak); + return 0; + } + for (i = 0; i < bq.count; i++) + { + if (!bq.elements[i]) + continue; + for (j = 0; bq.elements[i + j + 1]; j++) + ; + if (j > 1) + solver_addjobrule(solv, bq.elements[i], 0, pool_ids2whatprovides(pool, bq.elements + i + 1, j), jobidx, weak); + else + solver_addjobrule(solv, bq.elements[i], bq.elements[i + 1], 0, jobidx, weak); + i += j + 1; + } + queue_free(&bq); + return 1; +} +#endif /* * @@ -3637,7 +3543,7 @@ solver_solve(Solver *solv, Queue *job) if (how & SOLVER_FORCEBEST) solv->bestupdatemap_all = 1; } - if (!solv->dupmap_all) + if (!solv->dupmap_all || solv->allowuninstall) hasdupjob = 1; break; default: @@ -3651,10 +3557,7 @@ solver_solve(Solver *solv, Queue *job) * add rules for suggests, enhances */ oldnrules = solv->nrules; - if (hasdupjob && !solv->updatemap_all && solv->dosplitprovides && solv->installed) - solver_addpkgrulesforweak(solv, &addedmap); - else - solver_addpkgrulesforweak(solv, &addedmap); + solver_addpkgrulesforweak(solv, &addedmap); POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules because of weak dependencies\n", solv->nrules - oldnrules); #ifdef ENABLE_LINKED_PKGS @@ -3719,7 +3622,7 @@ solver_solve(Solver *solv, Queue *job) { if (s->repo != installed) { - solver_addrule(solv, 0, 0); /* create dummy rule */ + solver_addrule(solv, 0, 0, 0); /* create dummy rule */ continue; } solver_addupdaterule(solv, s, 1); /* allow s to be updated */ @@ -3747,7 +3650,7 @@ solver_solve(Solver *solv, Queue *job) if (s->repo != installed) { - solver_addrule(solv, 0, 0); /* create dummy rule */ + solver_addrule(solv, 0, 0, 0); /* create dummy rule */ continue; } solver_addupdaterule(solv, s, 0); /* allowall = 0: downgrades not allowed */ @@ -3798,6 +3701,15 @@ solver_solve(Solver *solv, Queue *job) p = what; d = 0; } +#ifdef ENABLE_COMPLEX_DEPS + else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what)) + { + if (add_complex_jobrules(solv, what, select == SOLVER_SOLVABLE_NAME ? CPLXDEPS_NAME : 0, i, weak)) + if (how & SOLVER_FORCEBEST) + hasbestinstalljob = 1; + break; + } +#endif else { queue_empty(&q); @@ -3828,7 +3740,7 @@ solver_solve(Solver *solv, Queue *job) queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what); } } - solver_addjobrule(solv, p, d, i, weak); + solver_addjobrule(solv, p, 0, d, i, weak); if (how & SOLVER_FORCEBEST) hasbestinstalljob = 1; break; @@ -3841,21 +3753,29 @@ solver_solve(Solver *solv, Queue *job) if (select == SOLVER_SOLVABLE_ALL) /* hmmm ;) */ { FOR_POOL_SOLVABLES(p) - solver_addjobrule(solv, -p, 0, i, weak); + solver_addjobrule(solv, -p, 0, 0, i, weak); } else if (select == SOLVER_SOLVABLE_REPO) { Repo *repo = pool_id2repo(pool, what); if (repo) FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, -p, 0, i, weak); + solver_addjobrule(solv, -p, 0, 0, i, weak); + } +#ifdef ENABLE_COMPLEX_DEPS + else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what)) + { + /* no special "erase a specific solvable" handling? */ + add_complex_jobrules(solv, what, select == SOLVER_SOLVABLE_NAME ? (CPLXDEPS_NAME | CPLXDEPS_TODNF | CPLXDEPS_INVERT) : (CPLXDEPS_TODNF | CPLXDEPS_INVERT), i, weak); + break; } +#endif FOR_JOB_SELECT(p, pp, select, what) { s = pool->solvables + p; if (installed && s->repo == installed) name = !name ? s->name : -1; - solver_addjobrule(solv, -p, 0, i, weak); + solver_addjobrule(solv, -p, 0, 0, i, weak); } /* special case for "erase a specific solvable": we also * erase all other solvables with that name, so that they @@ -3883,7 +3803,7 @@ solver_solve(Solver *solv, Queue *job) if (solv->rules[j].p == -p) break; if (j == k) - solver_addjobrule(solv, -p, 0, i, weak); /* remove by id */ + solver_addjobrule(solv, -p, 0, 0, i, weak); /* remove by id */ } } break; @@ -3909,17 +3829,17 @@ solver_solve(Solver *solv, Queue *job) if (select == SOLVER_SOLVABLE_ALL) { FOR_POOL_SOLVABLES(p) - solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); + solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); } else if (select == SOLVER_SOLVABLE_REPO) { Repo *repo = pool_id2repo(pool, what); if (repo) FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); + solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); } FOR_JOB_SELECT(p, pp, select, what) - solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak); + solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); break; case SOLVER_DISTUPGRADE: POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what)); @@ -4009,11 +3929,14 @@ solver_solve(Solver *solv, Queue *job) POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024); /* create weak map */ - map_init(&solv->weakrulemap, solv->nrules); - for (i = 0; i < solv->weakruleq.count; i++) + if (solv->weakruleq.count) { - p = solv->weakruleq.elements[i]; - MAPSET(&solv->weakrulemap, p); + map_grow(&solv->weakrulemap, solv->nrules); + for (i = 0; i < solv->weakruleq.count; i++) + { + p = solv->weakruleq.elements[i]; + MAPSET(&solv->weakrulemap, p); + } } /* enable cleandepsmap creation if we have updatepkgs */ @@ -4045,10 +3968,6 @@ solver_solve(Solver *solv, Queue *job) if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans) solver_breakorphans(solv); - /* make initial decisions based on assertion rules */ - makeruledecisions(solv); - POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count); - /* * ******************************************** * solve! @@ -4665,21 +4584,69 @@ get_userinstalled_cmp_names(const void *ap, const void *bp, void *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; + Id lastp = -1, lasta = -1; int i, j; - if ((flags & GET_USERINSTALLED_NAMES) != 0) + 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); - for (i = j = 0; i < q->count; i++) - if (q->elements[i] != lastp) - q->elements[j++] = lastp = q->elements[i]; + 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) { @@ -4789,8 +4756,20 @@ solver_get_userinstalled(Solver *solv, Queue *q, int flags) } } map_free(&userinstalled); - /* convert to names if asked */ - if ((flags & GET_USERINSTALLED_NAMES) != 0) + + /* 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++) { @@ -4799,9 +4778,9 @@ solver_get_userinstalled(Solver *solv, Queue *q, int flags) } } /* sort and unify */ - if (q->count > 1) - get_userinstalled_sort_uniq(pool, q, flags); - /* invert if asked */ + get_userinstalled_sort_uniq(pool, q, flags); + + /* invert if asked for */ if ((flags & GET_USERINSTALLED_INVERTED) != 0) { /* first generate queue with all installed packages */ @@ -4815,30 +4794,52 @@ solver_get_userinstalled(Solver *solv, Queue *q, int flags) s = pool->solvables + p; if (!s->repo) continue; - if ((flags & GET_USERINSTALLED_NAMES) != 0) + 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); - if (invq.count > 1) - get_userinstalled_sort_uniq(pool, &invq, flags); + get_userinstalled_sort_uniq(pool, &invq, flags); /* subtract queues (easy as they are sorted and invq is a superset of q) */ - if (q->count) + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) { - 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); + 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]); } - for (i = j = 0; i < invq.count; i++) - if (invq.elements[i]) - queue_push(q, invq.elements[i]); queue_free(&invq); } } @@ -4848,7 +4849,7 @@ pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags) { int i; - if (flags & GET_USERINSTALLED_INVERTED) + if ((flags & GET_USERINSTALLED_INVERTED) != 0) { Queue invq; Id p, lastid; @@ -4857,13 +4858,25 @@ pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags) 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); - queue_insertn(&invq, invq.count, q->count, q->elements); - if (invq.count > 1) - 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 ((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) @@ -4891,8 +4904,13 @@ pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags) } 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]); + 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]); + } } } diff --git a/src/solver.h b/src/solver.h index 1cb9f15..1a47ae0 100644 --- a/src/solver.h +++ b/src/solver.h @@ -155,6 +155,7 @@ struct _Solver { int allowvendorchange; /* allow to change vendor of installed solvables */ int allowuninstall; /* allow removal of installed solvables */ int noupdateprovide; /* true: update packages needs not to provide old package */ + int needupdateprovide; /* true: update packages must provide old package */ int dosplitprovides; /* true: consider legacy split provides */ int dontinstallrecommended; /* true: do not install recommended packages */ int addalreadyrecommended; /* true: also install recommended packages that were already recommended by the installed packages */ @@ -295,9 +296,11 @@ typedef struct _Solver Solver; #define SOLVER_FLAG_BREAK_ORPHANS 19 #define SOLVER_FLAG_FOCUS_INSTALLED 20 #define SOLVER_FLAG_YUM_OBSOLETES 21 +#define SOLVER_FLAG_NEED_UPDATEPROVIDE 22 -#define GET_USERINSTALLED_NAMES (1 << 0) /* package names instead if ids */ +#define GET_USERINSTALLED_NAMES (1 << 0) /* package names instead of ids */ #define GET_USERINSTALLED_INVERTED (1 << 1) /* autoinstalled */ +#define GET_USERINSTALLED_NAMEARCH (1 << 2) /* package/arch tuples instead of ids */ #define SOLVER_ALTERNATIVE_TYPE_RULE 1 #define SOLVER_ALTERNATIVE_TYPE_RECOMMENDS 2 diff --git a/src/solver_private.h b/src/solver_private.h index f30b03a..f8df8c7 100644 --- a/src/solver_private.h +++ b/src/solver_private.h @@ -16,7 +16,6 @@ extern void solver_run_sat(Solver *solv, int disablerules, int doweak); extern void solver_reset(Solver *solv); -extern int solver_dep_installed(Solver *solv, Id dep); extern int solver_splitprovides(Solver *solv, Id dep, Map *m); static inline int @@ -42,8 +41,6 @@ solver_dep_fulfilled(Solver *solv, Id dep) } if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) return solver_splitprovides(solv, rd->evr, 0); - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED) - return solver_dep_installed(solv, rd->evr); } FOR_PROVIDES(p, pp, dep) { diff --git a/src/solverdebug.c b/src/solverdebug.c index 3e84046..39f5d78 100644 --- a/src/solverdebug.c +++ b/src/solverdebug.c @@ -108,7 +108,7 @@ solver_printruleclass(Solver *solv, int type, Rule *r) Id p = r - solv->rules; assert(p >= 0); if (p < solv->learntrules) - if (MAPTST(&solv->weakrulemap, p)) + if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, p)) POOL_DEBUG(type, "WEAK "); if (solv->learntrules && p >= solv->learntrules) POOL_DEBUG(type, "LEARNT "); diff --git a/test/runtestcases b/test/runtestcases index 2edf743..3d73663 100755 --- a/test/runtestcases +++ b/test/runtestcases @@ -3,15 +3,23 @@ cmd=$1 dir=$2 -if test -z "$dir"; then +if test -z "$cmd" -o -z "$dir"; then echo "Usage: runtestcases <cmd> <dir>"; exit 1 fi ex=0 for tc in $(find $dir -name \*.t) ; do - if ! $cmd $tc > /dev/null ; then - echo "failed test: ${tc#$dir/}" + $cmd $tc >/dev/null + tex=$? + tcn="${tc#$dir/} .................................................." + tcn="${tcn:0:50}" + if test "$tex" -eq 0 ; then + echo "$tcn Passed" + elif test "$tex" -eq 77 ; then + echo "$tcn Skipped" + else + echo "$tcn***Failed" ex=1 fi done diff --git a/test/testcases/cleandeps/mistake.t b/test/testcases/cleandeps/mistake.t index b51ff69..48099a8 100644 --- a/test/testcases/cleandeps/mistake.t +++ b/test/testcases/cleandeps/mistake.t @@ -4,11 +4,11 @@ repo system 0 testtags <inline> #>=Pkg: B 2 1 noarch repo test 0 testtags <inline> #>=Pkg: A 2 1 noarch -#>=Req: B = 1 +#>=Req: B = 1-1 #>=Pkg: B 1 1 noarch -system i686 rpm system -job install name A = 2 [cleandeps] +system unset deb system +job install name A = 2-1 [cleandeps] result transaction,problems <inline> -#>problem b5abcb9c info package A-2-1.noarch requires B = 1, but none of the providers can be installed -#>problem b5abcb9c solution 37b448af deljob install name A = 2 [cleandeps] +#>problem b5abcb9c info package A-2-1.noarch requires B = 1-1, but none of the providers can be installed +#>problem b5abcb9c solution 3b3a37c0 deljob install name A = 2-1 [cleandeps] #>problem b5abcb9c solution 3c170283 replace B-2-1.noarch@system B-1-1.noarch@test diff --git a/test/testcases/distupgrade/dup_allowuninstall b/test/testcases/distupgrade/dup_allowuninstall new file mode 100644 index 0000000..86a8af9 --- /dev/null +++ b/test/testcases/distupgrade/dup_allowuninstall @@ -0,0 +1,13 @@ +repo system 0 testtags <inline> +#>=Pkg: a 1 1 i686 +#>=Pkg: b 2 1 i686 +repo available 0 testtags <inline> +#>=Pkg: a 2 1 i586 +#>=Con: b = 1-1 +#>=Pkg: b 1 1 i586 +system i686 * system +solverflags !dupallowarchchange allowuninstall +job distupgrade all packages +result transaction,problems <inline> +#>erase b-2-1.i686@system +#>upgrade a-1-1.i686@system a-2-1.i586@available diff --git a/test/testcases/distupgrade/dup_noarchchange b/test/testcases/distupgrade/dup_noarchchange new file mode 100644 index 0000000..f500d9b --- /dev/null +++ b/test/testcases/distupgrade/dup_noarchchange @@ -0,0 +1,15 @@ +repo system 0 testtags <inline> +#>=Pkg: a 1 1 i686 +#>=Pkg: b 1 1 i686 +repo available 0 testtags <inline> +#>=Pkg: a 2 1 i586 +#>=Pkg: b 2 1 i586 +#>=Pkg: b 2 1 i686 +system i686 * system +solverflags !dupallowarchchange +job distupgrade all packages +result transaction,problems <inline> +#>problem c43b1300 info problem with installed package a-1-1.i686 +#>problem c43b1300 solution c43b1300 replace a-1-1.i686@system a-2-1.i586@available +#>upgrade a-1-1.i686@system a-2-1.i586@available +#>upgrade b-1-1.i686@system b-2-1.i686@available diff --git a/test/testcases/evrcmp/conflicts.repo b/test/testcases/evrcmp/conflicts.repo index 90dd239..c979cb0 100644 --- a/test/testcases/evrcmp/conflicts.repo +++ b/test/testcases/evrcmp/conflicts.repo @@ -1,4 +1,4 @@ -Ver: 2.0 +=Ver: 2.0 # =Pkg: CEQ2 1 1 noarch =Con: B = 2 diff --git a/test/testcases/sat/assert.t b/test/testcases/sat/assert.t index 5d1ca1d..b3a2482 100644 --- a/test/testcases/sat/assert.t +++ b/test/testcases/sat/assert.t @@ -3,7 +3,7 @@ repo system 0 testtags <inline> #>=Prv: AA #>=Pkg: B 1 1 x86_64 #>=Prv: AA -system x86_64 rpm system +system x86_64 * system job erase provides AA [weak] job install pkg B-1-1.x86_64@system result transaction,problems <inline> diff --git a/test/testcases/sat/mm-packages.repo.gz b/test/testcases/sat/mm-packages.repo.gz Binary files differdeleted file mode 100644 index fd4aa08..0000000 --- a/test/testcases/sat/mm-packages.repo.gz +++ /dev/null diff --git a/test/testcases/sat/mm-system.repo.gz b/test/testcases/sat/mm-system.repo.gz Binary files differdeleted file mode 100644 index ef1ac5f..0000000 --- a/test/testcases/sat/mm-system.repo.gz +++ /dev/null diff --git a/test/testcases/sat/mm-test.t b/test/testcases/sat/mm-test.t index 573dbb0..6665cad 100644 --- a/test/testcases/sat/mm-test.t +++ b/test/testcases/sat/mm-test.t @@ -1,9 +1,46 @@ # # testcase to check enabling/disabling of learnt rules # -repo system 0 testtags mm-system.repo.gz -repo test 0 testtags mm-packages.repo.gz -system i686 rpm system +repo system 0 testtags <inline> +#>=Ver: 2.0 +#>=Pkg: A 1.0 1 noarch +#>=Req: D +#>=Prv: A = 1.0-1 +#>=Con: C +#>=Pkg: C 1.0 1 noarch +#>=Prv: foo +#>=Prv: C = 1.0-1 +#>=Con: D +#>=Pkg: D 1.0 1 noarch +#>=Prv: D = 1.0-1 +#>=Pkg: A2 1.0 1 noarch +#>=Req: D2 +#>=Prv: A2 = 1.0-1 +#>=Con: C2 +#>=Pkg: C2 1.0 1 noarch +#>=Prv: foo +#>=Prv: C2 = 1.0-1 +#>=Con: D2 +#>=Pkg: D2 1.0 1 noarch +#>=Prv: D2 = 1.0-1 +repo test 0 testtags <inline> +#>=Ver: 2.0 +#>=Pkg: C 2.0 1 noarch +#>=Prv: C = 2.0-1 +#>=Pkg: A 2.0 1 noarch +#>=Prv: A = 2.0-1 +#>=Pkg: D 2.0 1 noarch +#>=Prv: D = 2.0-1 +#>=Pkg: C2 2.0 1 noarch +#>=Prv: C2 = 2.0-1 +#>=Pkg: A2 2.0 1 noarch +#>=Prv: A2 = 2.0-1 +#>=Pkg: D2 2.0 1 noarch +#>=Prv: D2 = 2.0-1 +#>=Pkg: E 2.0 1 noarch +#>=Req: foo +#>=Prv: E = 2.0-1 +system unset * system job install provides E job verify all packages result transaction,problems <inline> diff --git a/test/testcases/targeted/targeted_dup.t b/test/testcases/targeted/targeted_dup.t index d85f477..bce3fef 100644 --- a/test/testcases/targeted/targeted_dup.t +++ b/test/testcases/targeted/targeted_dup.t @@ -11,7 +11,7 @@ repo available 0 testtags <inline> #>=Obs: A = 1-1 #>=Pkg: D 2 1 noarch #>=Pkg: D 3 1 noarch -system i686 rpm system +system unset * system # first check untargeted job distupgrade name A = 1-1 diff --git a/test/testcases/targeted/targeted_up.t b/test/testcases/targeted/targeted_up.t index 2b21c6b..1ab09e4 100644 --- a/test/testcases/targeted/targeted_up.t +++ b/test/testcases/targeted/targeted_up.t @@ -11,7 +11,7 @@ repo available 0 testtags <inline> #>=Obs: A = 1-1 #>=Pkg: D 2 1 noarch #>=Pkg: D 3 1 noarch -system i686 rpm system +system unset * system # first check untargeted job update name A = 1-1 diff --git a/test/testcases/testcase/str2dep.t b/test/testcases/testcase/str2dep.t new file mode 100644 index 0000000..d08c110 --- /dev/null +++ b/test/testcases/testcase/str2dep.t @@ -0,0 +1,185 @@ +# testcase for testcase_str2dep and testcase_dep2str + +# +# first test literal escaping +# +genid dep <NULL> +result genid <inline> +#>genid 1: genid null +#>genid dep <NULL> +nextjob + +genid dep \00 +result genid <inline> +#>genid 1: genid lit +#>genid dep \00 +nextjob + +genid dep \21\20\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f\3a\3b\3c\3d\3e\3f\40\5b\5c\5d\5e\5f\60\7b\7c\7d\7e +result genid <inline> +#>genid 1: genid lit ! "#$%&'()*+,-./:;<=>?@[\]^_`{|}~ +#>genid dep \21\20"#$%&'\28\29*+,-./:;<=>?@[\5c]^_`{|}~ +# make vim happy again: ' +nextjob + +genid dep foo(bar) +result genid <inline> +#>genid 1: genid lit foo(bar) +#>genid dep foo(bar) +nextjob + +genid dep foo()bar\29 +result genid <inline> +#>genid 1: genid lit foo()bar) +#>genid dep foo\28\29bar\29 +nextjob + +# +# test namespace hack +# +genid dep namespace:foo(bar) +result genid <inline> +#>genid 1: genid lit namespace:foo +#>genid 2: genid lit bar +#>genid 3: genid op <NAMESPACE> +#>genid dep namespace:foo(bar) +nextjob +genid lit namespace:foo(bar) +result genid <inline> +#>genid 1: genid lit namespace:foo(bar) +#>genid dep namespace\3afoo\28bar\29 +nextjob + +# +# test :any hack +# +genid dep foo:any +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit any +#>genid 3: genid op <MULTIARCH> +#>genid dep foo:any +nextjob +genid lit foo:any +result genid <inline> +#>genid 1: genid lit foo:any +#>genid dep foo\3aany +nextjob + +# +# test simple ops +# +genid dep foo < 1-1 +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit 1-1 +#>genid 3: genid op < +#>genid dep foo < 1-1 +nextjob + +genid dep foo = 1-1 +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit 1-1 +#>genid 3: genid op = +#>genid dep foo = 1-1 +nextjob + +genid dep foo > 1-1 +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit 1-1 +#>genid 3: genid op > +#>genid dep foo > 1-1 +nextjob + +genid dep foo >= 1-1 +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit 1-1 +#>genid 3: genid op >= +#>genid dep foo >= 1-1 +nextjob + +genid dep foo <= 1-1 +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit 1-1 +#>genid 3: genid op <= +#>genid dep foo <= 1-1 +nextjob + +# test arch op +genid dep foo . i586 +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit i586 +#>genid 3: genid op . +#>genid dep foo . i586 +nextjob + +# test haiku compat dep +genid dep foo = 2-1 compat >= 1-1 +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit 2-1 +#>genid 3: genid lit 1-1 +#>genid 4: genid op compat >= +#>genid 5: genid op = +#>genid dep foo = 2-1 compat >= 1-1 +nextjob + +# +# test complex (aka rich) deps +# + +genid dep foo & bar +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit bar +#>genid 3: genid op & +#>genid dep foo & bar +nextjob + +genid dep foo & bar & baz +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit bar +#>genid 3: genid lit baz +#>genid 4: genid op & +#>genid 5: genid op & +#>genid dep foo & bar & baz +nextjob + +genid dep foo & bar | baz +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit bar +#>genid 3: genid lit baz +#>genid 4: genid op | +#>genid 5: genid op & +#>genid dep foo & (bar | baz) +nextjob + +genid dep (foo & bar) | baz +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit bar +#>genid 3: genid op & +#>genid 4: genid lit baz +#>genid 5: genid op | +#>genid dep (foo & bar) | baz +nextjob + +genid dep (foo & bar > 2) | baz +result genid <inline> +#>genid 1: genid lit foo +#>genid 2: genid lit bar +#>genid 3: genid lit 2 +#>genid 4: genid op > +#>genid 5: genid op & +#>genid 6: genid lit baz +#>genid 7: genid op | +#>genid dep (foo & bar > 2) | baz +nextjob + diff --git a/tools/installcheck.c b/tools/installcheck.c index 73fa61c..3ef67b0 100644 --- a/tools/installcheck.c +++ b/tools/installcheck.c @@ -29,6 +29,9 @@ #ifdef ENABLE_DEBIAN #include "repo_deb.h" #endif +#ifdef ENABLE_ARCHREPO +#include "repo_arch.h" +#endif #include "solver.h" #include "solv_xfopen.h" @@ -148,6 +151,12 @@ main(int argc, char **argv) r = repo_add_debpackages(repo, fp, 0); } #endif +#ifdef ENABLE_ARCHREPO + else if (l >= 10 && (!strcmp(argv[i] + l - 10, ".db.tar.gz") || !strcmp(argv[i] + l - 10, ".db.tar.xz"))) + { + r = repo_add_arch_repo(repo, fp, 0); + } +#endif else r = repo_add_solv(repo, fp, 0); if (r) diff --git a/tools/testsolv.c b/tools/testsolv.c index 279b43b..428688f 100644 --- a/tools/testsolv.c +++ b/tools/testsolv.c @@ -18,6 +18,9 @@ static struct resultflags2str { { TESTCASE_RESULT_ORPHANED, "orphaned" }, { TESTCASE_RESULT_RECOMMENDED, "recommended" }, { TESTCASE_RESULT_UNNEEDED, "unneeded" }, + { TESTCASE_RESULT_ALTERNATIVES, "alternatives" }, + { TESTCASE_RESULT_RULES, "rules" }, + { TESTCASE_RESULT_GENID, "genid" }, { 0, 0 } }; @@ -131,7 +134,7 @@ main(int argc, char **argv) if (!solv) { pool_free(pool); - exit(1); + exit(resultflags == 77 ? 77 : 1); } if (!multijob && !feof(fp)) |