Imported Upstream version 0.6.11 10/94110/1 upstream/0.6.11
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 27 Oct 2016 05:54:23 +0000 (14:54 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 27 Oct 2016 05:54:24 +0000 (14:54 +0900)
Change-Id: Ia7fcc570c551205421c68cc6feb2ecfd3c97e149
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
42 files changed:
CMakeLists.txt
VERSION.cmake
bindings/solv.i
cmake/modules/FindRuby.cmake
doc/libsolv-constantids.3
doc/libsolv-constantids.txt
ext/CMakeLists.txt
ext/repo_deb.c
ext/testcase.c
ext/testcase.h
package/libsolv.changes
package/libsolv.spec.in
src/CMakeLists.txt
src/cplxdeps.c
src/cplxdeps.h
src/libsolv.ver
src/policy.c
src/policy.h
src/pool.c
src/pool.h
src/problems.c
src/repopack.h
src/rules.c
src/rules.h
src/solver.c
src/solver.h
src/solver_private.h
src/solverdebug.c
test/runtestcases
test/testcases/cleandeps/mistake.t
test/testcases/distupgrade/dup_allowuninstall [new file with mode: 0644]
test/testcases/distupgrade/dup_noarchchange [new file with mode: 0644]
test/testcases/evrcmp/conflicts.repo
test/testcases/sat/assert.t
test/testcases/sat/mm-packages.repo.gz [deleted file]
test/testcases/sat/mm-system.repo.gz [deleted file]
test/testcases/sat/mm-test.t
test/testcases/targeted/targeted_dup.t
test/testcases/targeted/targeted_up.t
test/testcases/testcase/str2dep.t [new file with mode: 0644]
tools/installcheck.c
tools/testsolv.c

index ab3fec9..45422af 100644 (file)
@@ -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)
index 92a1b90..fe0632b 100644 (file)
@@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "0")
 
 SET(LIBSOLV_MAJOR "0")
 SET(LIBSOLV_MINOR "6")
-SET(LIBSOLV_PATCH "10")
+SET(LIBSOLV_PATCH "11")
 
index 50f0b50..4030796 100644 (file)
@@ -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;
index 17ad7ef..827a7a6 100644 (file)
@@ -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)
index 8511667..a079793 100644 (file)
@@ -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\&.
index 7426b8f..7a83b46 100644 (file)
@@ -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.
index bdf949d..360c7dc 100644 (file)
@@ -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})
index 05d731b..26c73b0 100644 (file)
@@ -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
                {
index f0057e6..251cd2f 100644 (file)
@@ -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;
 }
 
index 14a2cca..78f78b0 100644 (file)
@@ -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);
index ad435b9..5a0a59b 100644 (file)
@@ -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
index 934ae2e..f5581b6 100644 (file)
@@ -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
index b78a82a..f60853e 100644 (file)
@@ -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})
index 9e42194..1be6868 100644 (file)
@@ -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;
 }
index 101d7ad..b553305 100644 (file)
@@ -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
 
index c795b7a..b8d9764 100644 (file)
@@ -74,6 +74,7 @@ SOLV_1.0 {
                pool_id2langid;
                pool_id2rel;
                pool_id2str;
+               pool_ids2whatprovides;
                pool_intersect_evrs;
                pool_isemptyupdatejob;
                pool_job2solvables;
index 93d7440..fadfcda 100644 (file)
@@ -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])
     {
index a4dd4c4..73410ee 100644 (file)
@@ -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
index 8de4cc5..f78f71a 100644 (file)
@@ -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);
 }
 
index f6e5d29..6b98efc 100644 (file)
@@ -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);
index 528aa2e..b57d980 100644 (file)
@@ -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)
        {
index f7828ab..3079239 100644 (file)
@@ -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)
index c9bbf81..67de769 100644 (file)
@@ -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));
index 8f55af3..606819b 100644 (file)
@@ -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);
index 46d0ca3..f551731 100644 (file)
@@ -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]);
+       }
     }
 }
 
index 1cb9f15..1a47ae0 100644 (file)
@@ -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
index f30b03a..f8df8c7 100644 (file)
@@ -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)
     {
index 3e84046..39f5d78 100644 (file)
@@ -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 ");
index 2edf743..3d73663 100755 (executable)
@@ -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
index b51ff69..48099a8 100644 (file)
@@ -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 (file)
index 0000000..86a8af9
--- /dev/null
@@ -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 (file)
index 0000000..f500d9b
--- /dev/null
@@ -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
index 90dd239..c979cb0 100644 (file)
@@ -1,4 +1,4 @@
-Ver: 2.0
+=Ver: 2.0
 #
 =Pkg: CEQ2 1 1 noarch
 =Con: B = 2
index 5d1ca1d..b3a2482 100644 (file)
@@ -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
deleted file mode 100644 (file)
index fd4aa08..0000000
Binary files a/test/testcases/sat/mm-packages.repo.gz and /dev/null differ
diff --git a/test/testcases/sat/mm-system.repo.gz b/test/testcases/sat/mm-system.repo.gz
deleted file mode 100644 (file)
index ef1ac5f..0000000
Binary files a/test/testcases/sat/mm-system.repo.gz and /dev/null differ
index 573dbb0..6665cad 100644 (file)
@@ -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>
index d85f477..bce3fef 100644 (file)
@@ -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
index 2b21c6b..1ab09e4 100644 (file)
@@ -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 (file)
index 0000000..d08c110
--- /dev/null
@@ -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
+
index 73fa61c..3ef67b0 100644 (file)
@@ -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)
index 279b43b..428688f 100644 (file)
@@ -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))