Imported Upstream version 0.6.24 94/194194/1 upstream/0.6.24
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 30 Nov 2018 03:38:58 +0000 (12:38 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 30 Nov 2018 03:39:53 +0000 (12:39 +0900)
Change-Id: I68f4d40b704c1ccd2a86576a3c03687922f023aa
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
27 files changed:
CMakeLists.txt
NEWS
VERSION.cmake
bindings/CMakeLists.txt
bindings/python/CMakeLists.txt
bindings/python3/CMakeLists.txt [new file with mode: 0644]
bindings/solv.i
examples/solv/patchjobs.c
ext/CMakeLists.txt
ext/libsolvext.ver
ext/repo_rpmdb.c
ext/repo_susetags.c
ext/testcase.c
package/libsolv.changes
package/libsolv.spec.in
src/order.c
src/problems.c
src/rules.c
src/selection.c
src/solver.c
src/solver.h
src/solvversion.h.in
test/testcases/focus/best.t [new file with mode: 0644]
test/testcases/focus/installed.t [new file with mode: 0644]
test/testcases/focus/normal.t [new file with mode: 0644]
tools/CMakeLists.txt
tools/installcheck.c

index 0153a70..82034e0 100644 (file)
@@ -13,6 +13,7 @@ OPTION (ENABLE_TCL "Build the Tcl bindings?" OFF)
 OPTION (USE_VENDORDIRS "Install the bindings in vendor directories?" OFF)
 
 OPTION (ENABLE_RPMDB "Build with rpm database support?" OFF)
+OPTION (ENABLE_RPMPKG "Build with rpm package support?" OFF)
 OPTION (ENABLE_PUBKEY "Build with pubkey support?" OFF)
 OPTION (ENABLE_RPMDB_BYRPMHEADER "Build with rpmdb Header support?" OFF)
 OPTION (ENABLE_RPMMD "Build with rpmmd repository support?" OFF)
@@ -174,6 +175,10 @@ IF (MULTI_SEMANTICS)
 MESSAGE (STATUS "Enabling multi dist support")
 ENDIF (MULTI_SEMANTICS)
 
+IF (ENABLE_RPMDB)
+SET (ENABLE_RPMPKG ON)
+ENDIF (ENABLE_RPMDB)
+
 INCLUDE (CheckIncludeFile)
 IF (ENABLE_RPMDB)
   FIND_LIBRARY (RPMDB_LIBRARY NAMES rpmdb)
@@ -254,7 +259,8 @@ FOREACH (VAR
 ENDFOREACH (VAR)
 
 FOREACH (VAR
-  ENABLE_RPMDB ENABLE_PUBKEY ENABLE_RPMMD ENABLE_RPMDB_BYRPMHEADER ENABLE_SUSEREPO ENABLE_COMPS
+  ENABLE_RPMDB ENABLE_RPMPKG ENABLE_PUBKEY ENABLE_RPMMD ENABLE_RPMDB_BYRPMHEADER
+  ENABLE_SUSEREPO ENABLE_COMPS
   ENABLE_HELIXREPO ENABLE_MDKREPO ENABLE_ARCHREPO ENABLE_DEBIAN ENABLE_HAIKU
   ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION ENABLE_PGPVRFY ENABLE_APPDATA)
   IF(${VAR})
diff --git a/NEWS b/NEWS
index 1745af8..79e18dc 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@
 This file contains the major changes between
 libsolv versions:
 
+Version 0.6.24
+- new features:
+  * new SOLVER_FLAG_FOCUS_BEST flag
+
 Version 0.6.22, 0.6.23
 - bug fix releases, no new features
 
index 10ade66..ffa5bd0 100644 (file)
@@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "0")
 
 SET(LIBSOLV_MAJOR "0")
 SET(LIBSOLV_MINOR "6")
-SET(LIBSOLV_PATCH "23")
+SET(LIBSOLV_PATCH "24")
 
index 34b0784..737cee4 100644 (file)
@@ -8,6 +8,9 @@ SET (SWIG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/solv.i")
 IF (ENABLE_PYTHON)
     ADD_SUBDIRECTORY (python)
 ENDIF (ENABLE_PYTHON)
+IF (ENABLE_PYTHON3)
+    ADD_SUBDIRECTORY (python3)
+ENDIF (ENABLE_PYTHON3)
 IF (ENABLE_PERL)
     ADD_SUBDIRECTORY (perl)
 ENDIF (ENABLE_PERL)
index 73f2dca..dc6648d 100644 (file)
@@ -1,7 +1,13 @@
-#SET (PythonLibs_FIND_VERSION 3)
-
-FIND_PACKAGE (PythonLibs)
+IF (ENABLE_PYTHON3 AND NOT DEFINED PythonLibs_FIND_VERSION)
+    # if we build both for python2 and python3, make this the python2 build.
+    # see comment in the python3 CMakeLists.txt file
+    SET (PythonLibs_FIND_VERSION 2)
+    SET (PythonLibs_FIND_VERSION_MAJOR 2)
+ENDIF (ENABLE_PYTHON3 AND NOT DEFINED PythonLibs_FIND_VERSION)
+
+FIND_PACKAGE (PythonLibs REQUIRED)
 FIND_PACKAGE (PythonInterp ${PYTHONLIBS_VERSION_STRING} REQUIRED)
+
 EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_lib(True))" OUTPUT_VARIABLE PYTHON_INSTALL_DIR)
 
 IF (NOT DEFINED PYTHON_VERSION_MAJOR)
@@ -13,6 +19,7 @@ ENDIF (${PYTHON_VERSION_MAJOR} GREATER 2)
 
 MESSAGE (STATUS "Python executable: ${PYTHON_EXECUTABLE}")
 MESSAGE (STATUS "Python installation dir: ${PYTHON_INSTALL_DIR}")
+MESSAGE (STATUS "Python include path: ${PYTHON_INCLUDE_PATH}")
 
 ADD_CUSTOM_COMMAND (
     OUTPUT solv_python.c
diff --git a/bindings/python3/CMakeLists.txt b/bindings/python3/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7a2dca3
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# used for building both python2 and python3 bindings
+# do not use if you want to build just one flavor, use the
+# standard python bindings file in that case.
+#
+# we cannot use FIND_PACKAGE PythonLibs here, as this would
+# clash with the python variables.
+#
+IF (NOT DEFINED ${PYTHON3_EXECUTABLE})
+SET (PYTHON3_EXECUTABLE "/usr/bin/python3")
+ENDIF (NOT DEFINED ${PYTHON3_EXECUTABLE})
+
+EXECUTE_PROCESS(COMMAND ${PYTHON3_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_lib(True))" OUTPUT_VARIABLE PYTHON3_INSTALL_DIR)
+EXECUTE_PROCESS(COMMAND ${PYTHON3_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_inc())" OUTPUT_VARIABLE PYTHON3_INCLUDE_DIR)
+
+MESSAGE (STATUS "Python3 executable: ${PYTHON3_EXECUTABLE}")
+MESSAGE (STATUS "Python3 installation dir: ${PYTHON3_INSTALL_DIR}")
+MESSAGE (STATUS "Python3 include path: ${PYTHON3_INCLUDE_DIR}")
+
+ADD_CUSTOM_COMMAND (
+    OUTPUT solv_python.c
+    COMMAND ${SWIG_EXECUTABLE} ${SWIG_FLAGS} -python -DPYTHON3=1 -I${CMAKE_SOURCE_DIR}/src -o solv_python.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
+    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
+)
+
+ADD_DEFINITIONS(-Wno-unused)
+INCLUDE_DIRECTORIES (${PYTHON3_INCLUDE_DIR})
+
+ADD_LIBRARY (bindings_python3 SHARED solv_python.c)
+SET_TARGET_PROPERTIES (bindings_python3 PROPERTIES PREFIX "" OUTPUT_NAME "_solv")
+TARGET_LINK_LIBRARIES (bindings_python3 libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+INSTALL (TARGETS bindings_python3 LIBRARY DESTINATION ${PYTHON3_INSTALL_DIR})
+INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.py DESTINATION ${PYTHON3_INSTALL_DIR})
index b21fbbc..64f51d0 100644 (file)
@@ -634,7 +634,7 @@ typedef int bool;
 #include "selection.h"
 
 #include "repo_write.h"
-#ifdef ENABLE_RPMDB
+#if defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG)
 #include "repo_rpmdb.h"
 #endif
 #ifdef ENABLE_PUBKEY
@@ -1990,6 +1990,8 @@ rb_eval_string(
   bool add_rpmdb_reffp(FILE *reffp, int flags = 0) {
     return repo_add_rpmdb_reffp($self, reffp, flags) == 0;
   }
+#endif
+#ifdef ENABLE_RPMPKG
   %newobject add_rpm;
   XSolvable *add_rpm(const char *name, int flags = 0) {
     return new_XSolvable($self->pool, repo_add_rpm($self, name, flags));
@@ -3278,6 +3280,7 @@ rb_eval_string(
   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_FLAG_FOCUS_BEST = SOLVER_FLAG_FOCUS_BEST;
 
   static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED;
   static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE;
index 64ad607..929a203 100644 (file)
@@ -19,8 +19,10 @@ add_patchjobs(Pool *pool, Queue *job)
   map_init(&installedmap, pool->nsolvables);
   solver_calculate_multiversionmap(pool, job, &multiversionmap);
   if (pool->installed)
-    FOR_REPO_SOLVABLES(pool->installed, p, s)
-      MAPSET(&installedmap, p);
+    {
+      FOR_REPO_SOLVABLES(pool->installed, p, s)
+        MAPSET(&installedmap, p);
+    }
 
   /* install all patches */
   for (p = 1; p < pool->nsolvables; p++)
index ec5f20c..586eda8 100644 (file)
@@ -4,12 +4,12 @@ SET (libsolvext_SRCS
 SET (libsolvext_HEADERS
     tools_util.h solv_xfopen.h testcase.h)
 
-IF (ENABLE_RPMDB)
+IF (ENABLE_RPMDB OR ENABLE_RPMPKG)
     SET (libsolvext_SRCS ${libsolvext_SRCS}
         pool_fileconflicts.c repo_rpmdb.c)
     SET (libsolvext_HEADERS ${libsolvext_HEADERS}
         pool_fileconflicts.h repo_rpmdb.h)
-ENDIF (ENABLE_RPMDB)
+ENDIF (ENABLE_RPMDB OR ENABLE_RPMPKG)
 
 IF (ENABLE_PUBKEY)
     SET (libsolvext_SRCS ${libsolvext_SRCS}
@@ -45,12 +45,12 @@ ENDIF (ENABLE_SUSEREPO)
 
 # old cmake does not support parenthetical expressions...
 IF (ENABLE_COMPLEX_DEPS)
-IF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB)
+IF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB OR ENABLE_RPMPKG)
     SET (libsolvext_SRCS ${libsolvext_SRCS}
        pool_parserpmrichdep.c)
     SET (libsolvext_HEADERS ${libsolvext_HEADERS}
        pool_parserpmrichdep.h)
-ENDIF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB)
+ENDIF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB OR ENABLE_RPMPKG)
 ENDIF (ENABLE_COMPLEX_DEPS)
 
 IF (SUSE)
index 8774fd4..4896e85 100644 (file)
@@ -66,6 +66,7 @@ SOLV_1.0 {
                testcase_str2dep;
                testcase_str2job;
                testcase_str2repo;
+               testcase_str2solvid;
                testcase_read;
                testcase_resultdiff;
                testcase_solverresult;
index 95756c0..034198c 100644 (file)
@@ -24,6 +24,8 @@
 #include <stdint.h>
 #include <errno.h>
 
+#ifdef ENABLE_RPMDB
+
 #include <rpm/rpmio.h>
 #include <rpm/rpmpgp.h>
 #ifndef RPM5
@@ -39,6 +41,8 @@
 # endif
 #endif
 
+#endif
+
 #include "pool.h"
 #include "repo.h"
 #include "hash.h"
 # define RPM_INDEX_SIZE 8      /* rpmdbid + array index */
 #endif
 
+/* some limits to guard against corrupt rpms */
+#define MAX_SIG_CNT            0x100000
+#define MAX_SIG_DSIZE          0x100000
+
+#define MAX_HDR_CNT            0x100000
+#define MAX_HDR_DSIZE          0x2000000
 
 typedef struct rpmhead {
   int cnt;
-  int dcnt;
+  unsigned int dcnt;
   unsigned char *dp;
   int forcebinary;             /* sigh, see rh#478907 */
   unsigned char data[1];
@@ -204,7 +214,7 @@ headint32array(RpmHead *h, int tag, int *cnt)
     return 0;
   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (o + 4 * i > h->dcnt)
+  if (o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt)
     return 0;
   d = h->dp + o;
   r = solv_calloc(i ? i : 1, sizeof(unsigned int));
@@ -226,7 +236,7 @@ headint32(RpmHead *h, int tag)
     return 0;
   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (i == 0 || o + 4 * i > h->dcnt)
+  if (i == 0 || o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt)
     return 0;
   d = h->dp + o;
   return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
@@ -243,7 +253,7 @@ headint64array(RpmHead *h, int tag, int *cnt)
     return 0;
   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (o + 8 * i > h->dcnt)
+  if (o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
     return 0;
   d = h->dp + o;
   r = solv_calloc(i ? i : 1, sizeof(unsigned long long));
@@ -267,7 +277,7 @@ headint64(RpmHead *h, int tag)
     return 0;
   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (i == 0 || o + 8 * i > h->dcnt)
+  if (i == 0 || o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
     return 0;
   d = h->dp + o;
   i = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
@@ -284,7 +294,7 @@ headint16array(RpmHead *h, int tag, int *cnt)
     return 0;
   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (o + 4 * i > h->dcnt)
+  if (o > h->dcnt || i > h->dcnt || o + 2 * i > h->dcnt)
     return 0;
   d = h->dp + o;
   r = solv_calloc(i ? i : 1, sizeof(unsigned int));
@@ -320,6 +330,8 @@ headstringarray(RpmHead *h, int tag, int *cnt)
     return 0;
   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  if (o > h->dcnt || i > h->dcnt)
+    return 0;
   r = solv_calloc(i ? i : 1, sizeof(char *));
   if (cnt)
     *cnt = i;
@@ -347,7 +359,7 @@ headbinary(RpmHead *h, int tag, unsigned int *sizep)
     return 0;
   o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
   i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (o > h->dcnt || o + i < o || o + i > h->dcnt)
+  if (o > h->dcnt || i > h->dcnt || o + i > h->dcnt)
     return 0;
   if (sizep)
     *sizep = i;
@@ -827,7 +839,7 @@ addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags)
       Id did;
       char *b = bn[i];
 
-      if (di[i] == lastdii)
+      if (lastdid && di[i] == lastdii)
        did = lastdid;
       else
        {
@@ -943,7 +955,7 @@ set_description_author(Repodata *data, Id handle, char *str)
 }
 
 static int
-rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags)
+rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags)
 {
   char *name;
   char *evr;
@@ -1075,6 +1087,12 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead,
   return 1;
 }
 
+static inline unsigned int
+getu32(const unsigned char *dp)
+{
+  return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3];
+}
+
 
 /******************************************************************/
 /*  Rpm Database stuff
@@ -1087,13 +1105,17 @@ struct rpmdbstate {
   RpmHead *rpmhead;    /* header storage space */
   int rpmheadsize;
 
+#ifdef ENABLE_RPMDB
   int dbopened;
   DB_ENV *dbenv;       /* database environment */
   DB *db;              /* packages database */
   int byteswapped;     /* endianess of packages database */
   int is_ostree;       /* read-only db that lives in /usr/share/rpm */
+#endif
 };
 
+#ifdef ENABLE_RPMDB
+
 struct rpmdbentry {
   Id rpmdbid;
   Id nameoff;
@@ -1103,7 +1125,8 @@ struct rpmdbentry {
 #define NAMEDATA_BLOCK 1023
 
 
-static inline Id db2rpmdbid(unsigned char *db, int byteswapped)
+static inline Id
+db2rpmdbid(unsigned char *db, int byteswapped)
 {
 #ifdef RPM5
   return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
@@ -1119,7 +1142,8 @@ static inline Id db2rpmdbid(unsigned char *db, int byteswapped)
 #endif
 }
 
-static inline void rpmdbid2db(unsigned char *db, Id id, int byteswapped)
+static inline void
+rpmdbid2db(unsigned char *db, Id id, int byteswapped)
 {
 #ifdef RPM5
   db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
@@ -1235,6 +1259,46 @@ closedbenv(struct rpmdbstate *state)
   state->dbenv = 0;
 }
 
+#endif
+
+static void
+freestate(struct rpmdbstate *state)
+{
+  /* close down */
+  if (!state)
+    return;
+#ifdef ENABLE_RPMDB
+  if (state->db)
+    state->db->close(state->db, 0);
+  if (state->dbenv)
+    closedbenv(state);
+#endif
+  if (state->rootdir)
+    solv_free(state->rootdir);
+  solv_free(state->rpmhead);
+}
+
+void *
+rpm_state_create(Pool *pool, const char *rootdir)
+{
+  struct rpmdbstate *state;
+  state = solv_calloc(1, sizeof(*state));
+  state->pool = pool;
+  if (rootdir)
+    state->rootdir = solv_strdup(rootdir);
+  return state;
+}
+
+void *
+rpm_state_free(void *state)
+{
+  freestate(state);
+  return solv_free(state);
+}
+
+
+#ifdef ENABLE_RPMDB
+
 static int
 openpkgdb(struct rpmdbstate *state)
 {
@@ -1364,23 +1428,50 @@ getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *ma
   return entries;
 }
 
-/* retrive header by rpmdbid */
+/* common code, return dbid on success, -1 on error */
 static int
-getrpmdbid(struct rpmdbstate *state, Id rpmdbid)
+getrpm_dbdata(struct rpmdbstate *state, DBT *dbdata, int dbid)
 {
-  unsigned char buf[16];
-  DBT dbkey;
-  DBT dbdata;
+  unsigned int dsize, cnt, l;
   RpmHead *rpmhead;
 
-  if (!rpmdbid)
+  if (dbdata->size < 8)
+    return pool_error(state->pool, -1, "corrupt rpm database (size)");
+  cnt = getu32((const unsigned char *)dbdata->data);
+  dsize = getu32((const unsigned char *)dbdata->data + 4);
+  if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
+    return pool_error(state->pool, -1, "corrupt rpm database (cnt/dcnt)");
+  l = cnt * 16 + dsize;
+  if (8 + l > dbdata->size)
+    return pool_error(state->pool, -1, "corrupt rpm database (data size)");
+  if (l + 1 > state->rpmheadsize)
     {
-      pool_error(state->pool, 0, "illegal rpmdbid");
-      return -1;
+      state->rpmheadsize = l + 128;
+      state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize);
     }
+  rpmhead = state->rpmhead;
+  rpmhead->forcebinary = 1;
+  rpmhead->cnt = cnt;
+  rpmhead->dcnt = dsize;
+  memcpy(rpmhead->data, (unsigned char *)dbdata->data + 8, l);
+  rpmhead->data[l] = 0;
+  rpmhead->dp = rpmhead->data + cnt * 16;
+  return dbid;
+}
+
+/* retrive header by rpmdbid, returns 0 if not found, -1 on error */
+static int
+getrpm_dbid(struct rpmdbstate *state, Id dbid)
+{
+  unsigned char buf[4];
+  DBT dbkey;
+  DBT dbdata;
+
+  if (dbid <= 0)
+    return pool_error(state->pool, -1, "illegal rpmdbid %d", dbid);
   if (state->dbopened != 1 && !openpkgdb(state))
     return -1;
-  rpmdbid2db(buf, rpmdbid, state->byteswapped);
+  rpmdbid2db(buf, dbid, state->byteswapped);
   memset(&dbkey, 0, sizeof(dbkey));
   memset(&dbdata, 0, sizeof(dbdata));
   dbkey.data = buf;
@@ -1389,39 +1480,15 @@ getrpmdbid(struct rpmdbstate *state, Id rpmdbid)
   dbdata.size = 0;
   if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0))
     return 0;
-  if (dbdata.size < 8)
-    {
-      pool_error(state->pool, 0, "corrupt rpm database (size)");
-      return -1;
-    }
-  if (dbdata.size > state->rpmheadsize)
-    {
-      state->rpmheadsize = dbdata.size + 128;
-      state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize);
-    }
-  rpmhead = state->rpmhead;
-  memcpy(buf, dbdata.data, 8);
-  rpmhead->forcebinary = 1;
-  rpmhead->cnt = buf[0] << 24  | buf[1] << 16  | buf[2] << 8 | buf[3];
-  rpmhead->dcnt = buf[4] << 24  | buf[5] << 16  | buf[6] << 8 | buf[7];
-  if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size)
-    {
-      pool_error(state->pool, 0, "corrupt rpm database (data size)");
-      return -1;
-    }
-  memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
-  rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
-  return 1;
+  return getrpm_dbdata(state, &dbdata, dbid);
 }
 
-/* retrive header by berkeleydb cursor */
+/* retrive header by berkeleydb cursor, returns 0 on EOF, -1 on error */
 static Id
-getrpmcursor(struct rpmdbstate *state, DBC *dbc)
+getrpm_cursor(struct rpmdbstate *state, DBC *dbc)
 {
-  unsigned char buf[16];
   DBT dbkey;
   DBT dbdata;
-  RpmHead *rpmhead;
   Id dbid;
 
   memset(&dbkey, 0, sizeof(dbkey));
@@ -1431,62 +1498,12 @@ getrpmcursor(struct rpmdbstate *state, DBC *dbc)
       if (dbkey.size != 4)
        return pool_error(state->pool, -1, "corrupt Packages database (key size)");
       dbid = db2rpmdbid(dbkey.data, state->byteswapped);
-      if (dbid == 0)           /* the join key */
-       continue;
-      if (dbdata.size < 8)
-       return pool_error(state->pool, -1, "corrupt rpm database (size %u)\n", dbdata.size);
-      if (dbdata.size > state->rpmheadsize)
-       {
-         state->rpmheadsize = dbdata.size + 128;
-         state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
-       }
-      rpmhead = state->rpmhead;
-      memcpy(buf, dbdata.data, 8);
-      rpmhead->forcebinary = 1;
-      rpmhead->cnt = buf[0] << 24  | buf[1] << 16  | buf[2] << 8 | buf[3];
-      rpmhead->dcnt = buf[4] << 24  | buf[5] << 16  | buf[6] << 8 | buf[7];
-      if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size)
-       return pool_error(state->pool, -1, "corrupt rpm database (data size)\n");
-      memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
-      rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
-      return dbid;
+      if (dbid)                /* ignore join key */
+        return getrpm_dbdata(state, &dbdata, dbid);
     }
   return 0;
 }
 
-static void
-freestate(struct rpmdbstate *state)
-{
-  /* close down */
-  if (!state)
-    return;
-  if (state->db)
-    state->db->close(state->db, 0);
-  if (state->dbenv)
-    closedbenv(state);
-  if (state->rootdir)
-    solv_free(state->rootdir);
-  solv_free(state->rpmhead);
-}
-
-void *
-rpm_state_create(Pool *pool, const char *rootdir)
-{
-  struct rpmdbstate *state;
-  state = solv_calloc(1, sizeof(*state));
-  state->pool = pool;
-  if (rootdir)
-    state->rootdir = solv_strdup(rootdir);
-  return state;
-}
-
-void *
-rpm_state_free(void *state)
-{
-  freestate(state);
-  return solv_free(state);
-}
-
 static int
 count_headers(struct rpmdbstate *state)
 {
@@ -1851,7 +1868,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
        }
       i = 0;
       s = 0;
-      while ((dbid = getrpmcursor(&state, dbc)) != 0)
+      while ((dbid = getrpm_cursor(&state, dbc)) != 0)
        {
          if (dbid == -1)
            {
@@ -1869,7 +1886,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
          if (!repo->rpmdbid)
            repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
          repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid;
-         if (rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS))
+         if (rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS))
            {
              i++;
              s = 0;
@@ -2005,7 +2022,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
                    }
                }
            }
-         res = getrpmdbid(&state, dbid);
+         res = getrpm_dbid(&state, dbid);
          if (res <= 0)
            {
              if (!res)
@@ -2016,7 +2033,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
              solv_free(refhash);
              return -1;
            }
-         rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS);
+         rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS);
          if ((flags & RPMDB_REPORT_PROGRESS) != 0)
            {
              if (done < count)
@@ -2071,12 +2088,7 @@ repo_add_rpmdb_reffp(Repo *repo, FILE *fp, int flags)
   return res;
 }
 
-static inline unsigned int
-getu32(const unsigned char *dp)
-{
-  return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3];
-}
-
+#endif
 
 Id
 repo_add_rpm(Repo *repo, const char *rpm, int flags)
@@ -2148,7 +2160,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
     }
   sigcnt = getu32(lead + 96 + 8);
   sigdsize = getu32(lead + 96 + 12);
-  if (sigcnt >= 0x100000 || sigdsize >= 0x100000)
+  if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
     {
       pool_error(pool, -1, "%s: bad signature header", rpm);
       fclose(fp);
@@ -2161,7 +2173,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if ((flags & (RPM_ADD_WITH_PKGID | RPM_ADD_WITH_HDRID)) != 0)
     {
       /* extract pkgid or hdrid from the signature header */
-      if (sigdsize > rpmheadsize)
+      if (sigdsize + 1 > rpmheadsize)
        {
          rpmheadsize = sigdsize + 128;
          rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
@@ -2172,6 +2184,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
          fclose(fp);
          return 0;
        }
+      rpmhead->data[sigdsize] = 0;
       if (chksumh)
        solv_chksum_add(chksumh, rpmhead->data, sigdsize);
       if (leadsigchksumh)
@@ -2246,7 +2259,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
     }
   sigcnt = getu32(lead + 8);
   sigdsize = getu32(lead + 12);
-  if (sigcnt >= 0x100000 || sigdsize >= 0x2000000)
+  if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
     {
       pool_error(pool, -1, "%s: bad header", rpm);
       fclose(fp);
@@ -2254,7 +2267,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
     }
   l = sigdsize + sigcnt * 16;
   headerend = headerstart + 16 + l;
-  if (l > rpmheadsize)
+  if (l + 1 > rpmheadsize)
     {
       rpmheadsize = l + 128;
       rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
@@ -2265,6 +2278,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
       fclose(fp);
       return 0;
     }
+  rpmhead->data[l] = 0;
   if (chksumh)
     solv_chksum_add(chksumh, rpmhead->data, l);
   rpmhead->forcebinary = forcebinary;
@@ -2295,7 +2309,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
       solv_chksum_add(chksumh, lead, l);
   fclose(fp);
   s = pool_id2solvable(pool, repo_add_solvable(repo));
-  if (!rpm2solv(pool, repo, data, s, rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
+  if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
     {
       repo_free_solvable(repo, s - pool->solvables, 1);
       solv_chksum_free(chksumh, 0);
@@ -2347,7 +2361,7 @@ repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags)
       return 0;
     }
   s = pool_id2solvable(pool, repo_add_solvable(repo));
-  if (!rpm2solv(pool, repo, data, s, rpmhead, flags))
+  if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags))
     {
       repo_free_solvable(repo, s - pool->solvables, 1);
       return 0;
@@ -2599,6 +2613,8 @@ rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound)
   return notfound;
 }
 
+#ifdef ENABLE_RPMDB
+
 int
 rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq)
 {
@@ -2622,12 +2638,14 @@ rpm_byrpmdbid(void *rpmstate, Id rpmdbid)
   struct rpmdbstate *state = rpmstate;
   int r;
 
-  r = getrpmdbid(state, rpmdbid);
+  r = getrpm_dbid(state, rpmdbid);
   if (!r)
     pool_error(state->pool, 0, "header #%d not in database", rpmdbid);
   return r <= 0 ? 0 : state->rpmhead;
 }
 
+#endif
+
 void *
 rpm_byfp(void *rpmstate, FILE *fp, const char *name)
 {
@@ -2656,7 +2674,7 @@ rpm_byfp(void *rpmstate, FILE *fp, const char *name)
     }
   sigcnt = getu32(lead + 96 + 8);
   sigdsize = getu32(lead + 96 + 12);
-  if (sigcnt >= 0x100000 || sigdsize >= 0x100000)
+  if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
     {
       pool_error(state->pool, 0, "%s: bad signature header", name);
       return 0;
@@ -2686,14 +2704,14 @@ rpm_byfp(void *rpmstate, FILE *fp, const char *name)
     }
   sigcnt = getu32(lead + 8);
   sigdsize = getu32(lead + 12);
-  if (sigcnt >= 0x100000 || sigdsize >= 0x2000000)
+  if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
     {
       pool_error(state->pool, 0, "%s: bad header", name);
       return 0;
     }
   l = sigdsize + sigcnt * 16;
   /* headerend = headerstart + 16 + l; */
-  if (l > state->rpmheadsize)
+  if (l + 1 > state->rpmheadsize)
     {
       state->rpmheadsize = l + 128;
       state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
@@ -2704,6 +2722,7 @@ rpm_byfp(void *rpmstate, FILE *fp, const char *name)
       pool_error(state->pool, 0, "%s: unexpected EOF", name);
       return 0;
     }
+  rpmhead->data[l] = 0;
   rpmhead->forcebinary = forcebinary;
   rpmhead->cnt = sigcnt;
   rpmhead->dcnt = sigdsize;
@@ -2730,19 +2749,22 @@ rpm_byrpmh(void *rpmstate, Header h)
     return 0;
   sigcnt = getu32(uh);
   sigdsize = getu32(uh + 4);
+  if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
+    return 0;
   l = sigdsize + sigcnt * 16;
-  if (l > state->rpmheadsize)
+  if (l + 1 > state->rpmheadsize)
     {
       state->rpmheadsize = l + 128;
       state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
     }
   rpmhead = state->rpmhead;
-  memcpy(rpmhead->data, uh + 8, l - 8);
+  memcpy(rpmhead->data, uh + 8, l);
+  rpmhead->data[l] = 0;
   free((void *)uh);
   rpmhead->forcebinary = 0;
   rpmhead->cnt = sigcnt;
   rpmhead->dcnt = sigdsize;
-  rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
+  rpmhead->dp = rpmhead->data + sigcnt * 16;
   return rpmhead;
 }
 
index be73a7f..83967e0 100644 (file)
@@ -330,7 +330,7 @@ commit_diskusage(struct parsedata *pd, Id handle)
  *
  */
 
-static inline unsigned
+static inline unsigned int
 tag_from_string(char *cs)
 {
   unsigned char *s = (unsigned char *)cs;
@@ -478,6 +478,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
   Solvable *s;
   Offset freshens;
   int intag = 0;
+  int intag_linestart = 0;
   int cummulate = 0;
   int indesc = 0;
   int indelta = 0;
@@ -558,10 +559,9 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
 
   for (;;)
     {
-      unsigned tag;
-      char *olinep; /* old line pointer */
+      unsigned int tag;
       char line_lang[6];
-      int keylen = 3;
+      int keylen;
 
       if (pd.ret)
        break;
@@ -574,84 +574,86 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
        }
       if (!fgets(linep, aline - (linep - line), fp)) /* read line */
        break;
-      olinep = linep;
       linep += strlen(linep);
       if (linep == line || linep[-1] != '\n')
         continue;
       pd.lineno++;
       *--linep = 0;
-      if (linep == olinep)
-       continue;
 
       if (intag)
        {
-         /* check for multi-line value tags (+Key:/-Key:) */
-
-         int is_end = (linep[-intag - keylen + 1] == '-')
-                     && (linep[-1] == ':')
-                     && (linep == line + 1 + intag + 1 + 1 + 1 + intag + 1 || linep[-intag - keylen] == '\n');
-         if (is_end
-             && strncmp(linep - 1 - intag, line + 1, intag))
-           {
-             pool_debug(pool, SOLV_ERROR, "susetags: Nonmatching multi-line tags: %d: '%s' '%s' %d\n", pd.lineno, linep - 1 - intag, line + 1, intag);
-           }
-         if (cummulate && !is_end)
+         /* in multi-line value tags (+Key:/-Key:), check for end, cummulate */
+         int is_end = line[intag_linestart] == '-' && linep[-1] == ':' && linep - line == intag_linestart + intag + 2;
+         if (is_end && strncmp(linep - 1 - intag, line + 1, intag))
            {
-             *linep++ = '\n';
-             continue;
+             pool_debug(pool, SOLV_ERROR, "susetags: Nonmatching multi-line tags: %d: '%s' '%.*s'\n", pd.lineno, linep - 1 - intag, intag, line + 1);
            }
-         if (cummulate && is_end)
+         if (!is_end)
            {
-             linep[-intag - keylen + 1] = 0;
-             if (linep[-intag - keylen] == '\n')
-               linep[-intag - keylen] = 0;
-             linep = line;
-             intag = 0;
+             if (cummulate)
+               {
+                 *linep++ = '\n';
+                 intag_linestart = linep - line;
+                 continue;
+               }
+             intag_linestart = intag + 3;
+             linep = line + intag_linestart;
+             if (!*linep)
+               continue;               /* ignore empty lines, bnc#381828 */
            }
-         if (!cummulate && is_end)
+         else
            {
              intag = 0;
              linep = line;
-             continue;
+             if (!cummulate)
+               continue;
+             line[intag_linestart] = 0;
+             if (line[intag_linestart - 1] == '\n')
+               line[intag_linestart - 1] = 0;          /* strip trailing newline */
            }
-         if (!cummulate && !is_end)
-           linep = line + intag + keylen;
        }
       else
        linep = line;
 
-      if (!intag && line[0] == '+' && line[1] && line[1] != ':') /* start of +Key:/-Key: tag */
+      /* ignore comments and empty lines */
+      if (!*line || *line == '#')
+       continue;
+
+      /* ignore malformed lines */
+      if (!(line[0] && line[1] && line[2] && line[3] && (line[4] == ':' || line[4] == '.')))
+        continue;
+
+      if (!intag && line[0] == '+' && line[1] != ':') /* start of +Key:/-Key: tag */
        {
          char *tagend = strchr(line, ':');
-         if (!tagend)
+         if (!tagend || tagend - line > 100)
            {
              pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line);
              break;
            }
-         intag = tagend - (line + 1);
+         intag = tagend - (line + 1);          /* set to tagsize */
          cummulate = 0;
-         switch (tag_from_string(line))       /* check if accumulation is needed */
+         switch (tag_from_string(line))        /* check if accumulation is needed */
            {
              case CTAG('+', 'D', 'e', 's'):
              case CTAG('+', 'E', 'u', 'l'):
              case CTAG('+', 'I', 'n', 's'):
              case CTAG('+', 'D', 'e', 'l'):
              case CTAG('+', 'A', 'u', 't'):
-               if (line[4] == ':' || line[4] == '.')
-                 cummulate = 1;
+               cummulate = 1;
                break;
              default:
                break;
            }
-         line[0] = '=';                       /* handle lines between +Key:/-Key: as =Key: */
-         line[intag + keylen - 1] = ' ';
-         linep = line + intag + keylen;
+         line[0] = '=';                        /* handle lines between +Key:/-Key: as =Key: */
+         line[intag + 2] = ' ';
+         intag_linestart = intag + 3;
+         linep = line + intag_linestart;
          continue;
        }
-      if (*line == '#' || !*line)
-       continue;
-      if (! (line[0] && line[1] && line[2] && line[3] && (line[4] == ':' || line[4] == '.')))
-        continue;
+
+      /* support language suffix */
+      keylen = 3;
       line_lang[0] = 0;
       if (line[4] == '.')
         {
@@ -667,6 +669,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
               line_lang[langsize] = 0;
             }
         }
+
       tag = tag_from_string(line);
 
       if (indelta)
index 52c139f..a56c4db 100644 (file)
@@ -115,6 +115,7 @@ static struct solverflags2str {
   { SOLVER_FLAG_YUM_OBSOLETES,              "yumobsoletes", 0 },
   { SOLVER_FLAG_NEED_UPDATEPROVIDE,         "needupdateprovide", 0 },
   { SOLVER_FLAG_URPM_REORDER,               "urpmreorder", 0 },
+  { SOLVER_FLAG_FOCUS_BEST,                 "focusbest", 0 },
   { 0, 0, 0 }
 };
 
@@ -767,6 +768,7 @@ testcase_str2solvid(Pool *pool, const char *str)
          evrid = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0);
          if (!evrid)
            continue;
+         /* first check whatprovides */
          FOR_PROVIDES(p, pp, nid)
            {
              Solvable *s = pool->solvables + p;
@@ -778,6 +780,31 @@ testcase_str2solvid(Pool *pool, const char *str)
                continue;
              return p;
            }
+         /* maybe it's not installable and thus not in whatprovides. do a slow search */
+         if (repo)
+           {
+             Solvable *s;
+             FOR_REPO_SOLVABLES(repo, p, s)
+               {
+                 if (s->name != nid || s->evr != evrid)
+                   continue;
+                 if (arch && s->arch != arch)
+                   continue;
+                 return p;
+               }
+           }
+         else
+           {
+             FOR_POOL_SOLVABLES(p)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (s->name != nid || s->evr != evrid)
+                   continue;
+                 if (arch && s->arch != arch)
+                   continue;
+                 return p;
+               }
+           }
        }
     }
   return 0;
@@ -2328,7 +2355,7 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc
       Repo *repo = pool_id2repo(pool, repoid);
       char *buf = solv_malloc((repo->name ? strlen(repo->name) : 0) + 40);
       char *mp;
-      orignames[i] = repo->name;
+      orignames[repoid] = repo->name;
       if (!repo->name || !repo->name[0])
         sprintf(buf, "#%d", repoid);
       else
@@ -2353,7 +2380,7 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc
     {
       Repo *repo = pool_id2repo(pool, repoid);
       solv_free((void *)repo->name);
-      repo->name = orignames[i];
+      repo->name = orignames[repoid];
     }
   solv_free(orignames);
   return r;
@@ -2480,6 +2507,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
   int missing_features = 0;
   Id *genid = 0;
   int ngenid = 0;
+  Queue autoinstq;
 
   if (!fp && !(fp = fopen(testcase, "r")))
     {
@@ -2495,6 +2523,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
   buf = solv_malloc(bufl);
   bufp = buf;
   solv = 0;
+  queue_init(&autoinstq);
   for (;;)
     {
       if (bufp - buf + 16 > bufl)
@@ -2849,6 +2878,15 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
            }
          genid[ngenid++] = id;
        }
+      else if (!strcmp(pieces[0], "autoinst") && npieces > 2)
+       {
+         if (strcmp(pieces[1], "name"))
+           {
+             pool_debug(pool, SOLV_ERROR, "testcase_read: autoinst: illegal mode\n");
+             break;
+           }
+         queue_push(&autoinstq, pool_str2id(pool, pieces[2], 1));
+       }
       else
        {
          pool_debug(pool, SOLV_ERROR, "testcase_read: cannot parse command '%s'\n", pieces[0]);
@@ -2856,6 +2894,9 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
     }
   while (job && ngenid > 0)
     queue_push2(job, SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES, genid[--ngenid]);
+  if (autoinstq.count)
+    pool_add_userinstalled_jobs(pool, &autoinstq, job, GET_USERINSTALLED_NAMES | GET_USERINSTALLED_INVERTED);
+  queue_free(&autoinstq);
   genid = solv_free(genid);
   buf = solv_free(buf);
   pieces = solv_free(pieces);
index 7d12812..fd351c3 100644 (file)
@@ -1,4 +1,14 @@
 -------------------------------------------------------------------
+Thu Nov 10 15:09:25 CET 2016 - mls@suse.de
+
+- make testcase_str2solvid work with ignored packages
+- improve checks against corrupt rpm 
+- add SOLVER_FLAG_FOCUS_BEST solver flag
+- rework susetags multi-line handling [bnc#1007273]
+- build both for python2 and python3
+- bump version to 0.6.24
+
+-------------------------------------------------------------------
 Fri Jul 22 11:37:23 CEST 2016 - mls@suse.de
 
 - also scan /usr/share/metainfo for appdata files [bnc#989830]
index c2251ec..0009287 100644 (file)
@@ -26,6 +26,7 @@ BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 %bcond_without disable_shared
 %bcond_without perl_binding
 %bcond_without python_binding
+%bcond_without python3_binding
 %bcond_without ruby_binding
 %bcond_with zypp
 
@@ -70,10 +71,14 @@ BuildRequires:  ruby-devel
 BuildRequires:  swig
 %endif
 %if %{with python_binding}
-%global python_sitearch %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True);")
+%global python_sitearch %(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))")
 BuildRequires:  python-devel
 BuildRequires:  swig
 %endif
+%if %{with python3_binding}
+%global python3_sitearch %(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))")
+BuildRequires:  python3-devel
+%endif
 
 Summary:        A new approach to package dependency solving
 License:        BSD-3-Clause
@@ -146,6 +151,13 @@ Group:          Development/Languages/Python
 %description -n python-solv
 Python bindings for sat solver.
 
+%package -n python3-solv
+Summary:        Python3 bindings for the libsolv library
+Group:          Development/Languages/Python
+
+%description -n python3-solv
+Python3 bindings for sat solver.
+
 %package -n perl-solv
 Requires:       perl = %{perl_version}
 Summary:        Perl bindings for the libsolv library
@@ -169,7 +181,7 @@ CMAKE_FLAGS="-DFEDORA=1"
 CMAKE_FLAGS="-DSUSE=1 -DENABLE_APPDATA=1 -DENABLE_COMPS=1"
 %endif
 
-cmake   $CMAKE_FLAGS \
+cmake  $CMAKE_FLAGS \
        -DCMAKE_INSTALL_PREFIX=%{_prefix} \
        -DLIB=%{_lib} \
        -DCMAKE_VERBOSE_MAKEFILE=TRUE \
@@ -178,6 +190,7 @@ cmake   $CMAKE_FLAGS \
        %{?with_disable_shared:-DDISABLE_SHARED=1} \
        %{?with_perl_binding:-DENABLE_PERL=1} \
        %{?with_python_binding:-DENABLE_PYTHON=1} \
+       %{?with_python3_binding:-DENABLE_PYTHON3=1} \
        %{?with_ruby_binding:-DENABLE_RUBY=1} \
        %{?with_zypp:-DENABLE_SUSEREPO=1 -DENABLE_HELIXREPO=1} \
        -DUSE_VENDORDIRS=1 \
@@ -186,13 +199,16 @@ make %{?jobs:-j %jobs}
 
 %install
 make DESTDIR=$RPM_BUILD_ROOT install
-%if %{with python_binding}
 %if 0%{?suse_version}
+%if %{with python_binding}
 pushd $RPM_BUILD_ROOT/%{python_sitearch}
 python %py_libdir/py_compile.py *.py
 python -O %py_libdir/py_compile.py *.py
 popd
 %endif
+%if %{with python3_binding}
+%py3_compile $RPM_BUILD_ROOT/%{python3_sitearch}
+%endif
 %endif
 %if %{with disable_shared}
 # we want to leave the .a file untouched
@@ -265,4 +281,13 @@ rm -rf "$RPM_BUILD_ROOT"
 %{python_sitearch}/*
 %endif
 
+%if %{with python3_binding}
+%files -n python3-solv
+%defattr(-,root,root)
+%{python3_sitearch}/*solv*
+%if 0%{?suse_version}
+%{python3_sitearch}/*/*solv*
+%endif
+%endif
+
 %changelog
index d560865..4fe3e08 100644 (file)
@@ -1262,8 +1262,10 @@ transaction_check_order(Transaction *trans)
   map_init(&ins, pool->nsolvables);
   map_init(&seen, pool->nsolvables);
   if (pool->installed)
-    FOR_REPO_SOLVABLES(pool->installed, p, s)
-      MAPSET(&ins, p);
+    {
+      FOR_REPO_SOLVABLES(pool->installed, p, s)
+        MAPSET(&ins, p);
+    }
   lastins = 0;
   for (i = 0; i < trans->steps.count; i++)
     {
index b57d980..063d47b 100644 (file)
@@ -588,17 +588,12 @@ create_solutions(Solver *solv, int probnr, int solidx)
 {
   Pool *pool = solv->pool;
   Queue redoq;
-  Queue problem, solution, problems_save, branches_save;
+  Queue problem, solution, problems_save, branches_save, decisionq_reason_save;
   int i, j, nsol;
   int essentialok;
   unsigned int now;
   int oldmistakes = solv->cleandeps_mistakes ? solv->cleandeps_mistakes->count : 0;
   Id extraflags = -1;
-  int decisioncnt_update;
-  int decisioncnt_keep;
-  int decisioncnt_resolve;
-  int decisioncnt_weak;
-  int decisioncnt_orphan;
 
   now = solv_timems(0);
   queue_init(&redoq);
@@ -610,11 +605,6 @@ create_solutions(Solver *solv, int probnr, int solidx)
       queue_push(&redoq, solv->decisionq_why.elements[i]);
       queue_push(&redoq, solv->decisionmap[p > 0 ? p : -p]);
     }
-  decisioncnt_update = solv->decisioncnt_update;
-  decisioncnt_keep = solv->decisioncnt_keep;
-  decisioncnt_resolve = solv->decisioncnt_resolve;
-  decisioncnt_weak = solv->decisioncnt_weak;
-  decisioncnt_orphan = solv->decisioncnt_orphan;
 
   /* save problems queue */
   problems_save = solv->problems;
@@ -624,6 +614,10 @@ create_solutions(Solver *solv, int probnr, int solidx)
   branches_save = solv->problems;
   memset(&solv->branches, 0, sizeof(solv->branches));
 
+  /* save decisionq_reason */
+  decisionq_reason_save = solv->decisionq_reason;
+  memset(&solv->decisionq_reason, 0, sizeof(solv->decisionq_reason));
+
   /* extract problem from queue */
   queue_init(&problem);
   for (i = solidx + 1; i < solv->solutions.count; i++)
@@ -711,11 +705,10 @@ create_solutions(Solver *solv, int probnr, int solidx)
       solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2];
     }
   queue_free(&redoq);
-  solv->decisioncnt_update = decisioncnt_update;
-  solv->decisioncnt_keep = decisioncnt_keep;
-  solv->decisioncnt_resolve = decisioncnt_resolve;
-  solv->decisioncnt_weak = decisioncnt_weak;
-  solv->decisioncnt_orphan = decisioncnt_orphan;
+
+  /* restore decision reasons */
+  queue_free(&solv->decisionq_reason);
+  solv->decisionq_reason = decisionq_reason_save;
 
   /* restore problems */
   queue_free(&solv->problems);
@@ -962,8 +955,11 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
                {
                  if (*reqrp > 0 && r->p < -1)
                    {
+                     Pool *pool = solv->pool;
                      Id op = -solv->rules[*reqrp].p;
-                     if (op > 1 && solv->pool->solvables[op].arch != solv->pool->solvables[-r->p].arch)
+                     if (op > 1 && pool->solvables[op].arch != pool->solvables[-r->p].arch &&
+                         pool->solvables[op].arch != pool->noarchid &&
+                         pool->solvables[-r->p].arch != pool->noarchid)
                        continue;       /* different arch, skip */
                    }
                  /* prefer assertions */
index aa90b5f..67f10d8 100644 (file)
@@ -2361,8 +2361,10 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
       if (!installed)
        break;
       if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
-       FOR_REPO_SOLVABLES(installed, p, s)
-         queue_push2(q, DISABLE_UPDATE, p);
+       {
+         FOR_REPO_SOLVABLES(installed, p, s)
+           queue_push2(q, DISABLE_UPDATE, p);
+       }
       FOR_JOB_SELECT(p, pp, select, what)
        if (pool->solvables[p].repo == installed)
          {
@@ -3956,8 +3958,10 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
          what = job->elements[i + 1];
          select = how & SOLVER_SELECTMASK;
          if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
-           FOR_REPO_SOLVABLES(installed, p, s)
-             MAPSET(&userinstalled, p - installed->start);
+           {
+             FOR_REPO_SOLVABLES(installed, p, s)
+               MAPSET(&userinstalled, p - installed->start);
+           }
          FOR_JOB_SELECT(p, pp, select, what)
            if (pool->solvables[p].repo == installed)
              MAPSET(&userinstalled, p - installed->start);
index 6b89ab0..37c6184 100644 (file)
@@ -53,8 +53,10 @@ selection_prune(Pool *pool, Queue *selection)
          Solvable *s;
          Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
          if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             break;
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               break;
+           }
        }
       else
        {
@@ -96,8 +98,10 @@ selection_solvables(Pool *pool, Queue *selection, Queue *pkgs)
          Solvable *s;
          Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
          if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             queue_push(pkgs, p);
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               queue_push(pkgs, p);
+           }
        }
       else
        {
@@ -1100,8 +1104,10 @@ selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
          Solvable *s;
          Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
          if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             map_set(&m2, p);
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               map_set(&m2, p);
+           }
        }
       else
        {
@@ -1163,13 +1169,15 @@ selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
          Solvable *s;
          Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
          if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             {
-               if (map_tst(&m2, p))
-                 queue_push(&q1, p);
-               else
-                 miss = 1;
-             }
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               {
+                 if (map_tst(&m2, p))
+                   queue_push(&q1, p);
+                 else
+                   miss = 1;
+               }
+           }
        }
       else
        {
index 5fca20d..efe3342 100644 (file)
@@ -341,6 +341,7 @@ makeruledecisions(Solver *solv)
   assert(solv->decisionq.count == 0);
   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
   queue_push(&solv->decisionq_why, 0);
+  queue_push2(&solv->decisionq_reason, 0, 0);
   solv->decisionmap[SYSTEMSOLVABLE] = 1;       /* installed at level '1' */
 
   decisionstart = solv->decisionq.count;
@@ -907,18 +908,7 @@ revert(Solver *solv, int 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;
+  solv->decisionq_reason.count = level + 1;
 }
 
 /*-------------------------------------------------------------------
@@ -1111,9 +1101,9 @@ solver_reset(Solver *solv)
     }
   queue_empty(&solv->decisionq_why);
   queue_empty(&solv->decisionq);
+  queue_empty(&solv->decisionq_reason);
   solv->recommends_index = -1;
   solv->propagate_index = 0;
-  solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
   queue_empty(&solv->branches);
 
   /* adapt learnt rule status to new set of enabled/disabled rules */
@@ -1334,7 +1324,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
  */
 
 static int
-setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid)
+setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid, Id reason)
 {
   Pool *pool = solv->pool;
   Rule *r, *lr;
@@ -1348,6 +1338,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul
         solv->decisionmap[-decision] = -level;
       queue_push(&solv->decisionq, decision);
       queue_push(&solv->decisionq_why, -ruleid);       /* <= 0 -> free decision */
+      queue_push(&solv->decisionq_reason, reason);
     }
   assert(ruleid >= 0 && level > 0);
   for (;;)
@@ -1376,7 +1367,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul
 }
 
 static void
-reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq)
+reorder_dq_for_future_installed(Solver *solv, int level, Queue *dq)
 {
   Pool *pool = solv->pool;
   int i, j, haveone = 0, dqcount = dq->count;
@@ -1464,7 +1455,7 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
 {
   Pool *pool = solv->pool;
   int level;
-  Id p, why;
+  Id p, why, reason;
 #if 0
   {
     int i;
@@ -1484,7 +1475,8 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
   /* hack: revert simply sets the count, so we can still access the reverted elements */
   why = -solv->decisionq_why.elements[solv->decisionq_why.count];
   assert(why >= 0);
-  return setpropagatelearn(solv, level, p, disablerules, why);
+  reason = solv->decisionq_reason.elements[level + 1];
+  return setpropagatelearn(solv, level, p, disablerules, why, reason);
 }
 
 /*-------------------------------------------------------------------
@@ -1499,23 +1491,23 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
  */
 
 static int
-selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid)
+selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid, Id reason)
 {
   Pool *pool = solv->pool;
   Id p;
 
   if (dq->count > 1)
     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
-  /* if we're resolving job rules and didn't resolve the installed packages yet,
+  /* if we're resolving rules and didn't resolve the installed packages yet,
    * do some special supplements ordering */
-  if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed && !solv->focus_installed)
-    reorder_dq_for_jobrules(solv, level, dq);
+  if (dq->count > 1 && solv->do_extra_reordering)
+    reorder_dq_for_future_installed(solv, level, dq);
   /* if we have multiple candidates we open a branch */
   if (dq->count > 1)
     createbranch(solv, level, dq, 0, ruleid);
   p = dq->elements[0];
   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p));
-  return setpropagatelearn(solv, level, p, disablerules, ruleid);
+  return setpropagatelearn(solv, level, p, disablerules, ruleid, reason);
 }
 
 
@@ -1556,6 +1548,7 @@ solver_create(Pool *pool)
   queue_init(&solv->ruletojob);
   queue_init(&solv->decisionq);
   queue_init(&solv->decisionq_why);
+  queue_init(&solv->decisionq_reason);
   queue_init(&solv->problems);
   queue_init(&solv->orphaned);
   queue_init(&solv->learnt_why);
@@ -1581,80 +1574,6 @@ solver_create(Pool *pool)
 }
 
 
-static int
-resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
-{
-  Pool *pool = solv->pool;
-  int oldlevel = level;
-  int i, olevel;
-  Rule *r;
-
-  POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
-  if (!solv->decisioncnt_jobs)
-    solv->decisioncnt_jobs = solv->decisionq.count;
-  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
-    {
-      Id l, pp;
-      if (r->d < 0)            /* ignore disabled rules */
-       continue;
-      queue_empty(dq);
-      FOR_RULELITERALS(l, pp, r)
-       {
-         if (l < 0)
-           {
-             if (solv->decisionmap[-l] <= 0)
-               break;
-           }
-         else
-           {
-             if (solv->decisionmap[l] > 0)
-               break;
-             if (solv->decisionmap[l] == 0)
-               queue_push(dq, l);
-           }
-       }
-      if (l || !dq->count)
-       continue;
-      /* prune to installed if not updating */
-      if (dq->count > 1 && solv->installed && !solv->updatemap_all &&
-         !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
-       {
-         int j, k;
-         for (j = k = 0; j < dq->count; j++)
-           {
-             Solvable *s = pool->solvables + dq->elements[j];
-             if (s->repo == solv->installed)
-               {
-                 dq->elements[k++] = dq->elements[j];
-                 if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start))
-                   {
-                     k = 0;    /* package wants to be updated, do not prune */
-                     break;
-                   }
-               }
-           }
-         if (k)
-           dq->count = k;
-       }
-      olevel = level;
-      level = selectandinstall(solv, level, dq, disablerules, i);
-      if (level <= olevel)
-       {
-         if (level == olevel)
-           {
-             i--;
-             r--;
-             continue; /* try something else */
-           }
-         if (level < oldlevel)
-           return level;
-         /* redo from start of jobrules */
-         i = solv->jobrules - 1;
-         r = solv->rules + i;
-       }
-    }
-  return level;
-}
 
 /*-------------------------------------------------------------------
  *
@@ -1687,6 +1606,7 @@ solver_free(Solver *solv)
   queue_free(&solv->ruletojob);
   queue_free(&solv->decisionq);
   queue_free(&solv->decisionq_why);
+  queue_free(&solv->decisionq_reason);
   queue_free(&solv->learnt_why);
   queue_free(&solv->learnt_pool);
   queue_free(&solv->problems);
@@ -1780,6 +1700,8 @@ solver_get_flag(Solver *solv, int flag)
     return solv->break_orphans;
   case SOLVER_FLAG_FOCUS_INSTALLED:
     return solv->focus_installed;
+  case SOLVER_FLAG_FOCUS_BEST:
+    return solv->focus_best;
   case SOLVER_FLAG_YUM_OBSOLETES:
     return solv->do_yum_obsoletes;
   case SOLVER_FLAG_NEED_UPDATEPROVIDE:
@@ -1858,6 +1780,9 @@ solver_set_flag(Solver *solv, int flag, int value)
   case SOLVER_FLAG_FOCUS_INSTALLED:
     solv->focus_installed = value;
     break;
+  case SOLVER_FLAG_FOCUS_BEST:
+    solv->focus_best = value;
+    break;
   case SOLVER_FLAG_YUM_OBSOLETES:
     solv->do_yum_obsoletes = value;
     break;
@@ -1874,6 +1799,79 @@ solver_set_flag(Solver *solv, int flag, int value)
 }
 
 static int
+resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  int oldlevel = level;
+  int i, olevel;
+  Rule *r;
+
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
+  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
+    {
+      Id l, pp;
+      if (r->d < 0)            /* ignore disabled rules */
+       continue;
+      queue_empty(dq);
+      FOR_RULELITERALS(l, pp, r)
+       {
+         if (l < 0)
+           {
+             if (solv->decisionmap[-l] <= 0)
+               break;
+           }
+         else
+           {
+             if (solv->decisionmap[l] > 0)
+               break;
+             if (solv->decisionmap[l] == 0)
+               queue_push(dq, l);
+           }
+       }
+      if (l || !dq->count)
+       continue;
+      /* prune to installed if not updating */
+      if (dq->count > 1 && solv->installed && !solv->updatemap_all &&
+         !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
+       {
+         int j, k;
+         for (j = k = 0; j < dq->count; j++)
+           {
+             Solvable *s = pool->solvables + dq->elements[j];
+             if (s->repo == solv->installed)
+               {
+                 dq->elements[k++] = dq->elements[j];
+                 if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start))
+                   {
+                     k = 0;    /* package wants to be updated, do not prune */
+                     break;
+                   }
+               }
+           }
+         if (k)
+           dq->count = k;
+       }
+      olevel = level;
+      level = selectandinstall(solv, level, dq, disablerules, i, SOLVER_REASON_RESOLVE_JOB);
+      if (level <= olevel)
+       {
+         if (level == olevel)
+           {
+             i--;
+             r--;
+             continue; /* try something else */
+           }
+         if (level < oldlevel)
+           return level;
+         /* redo from start of jobrules */
+         i = solv->jobrules - 1;
+         r = solv->rules + i;
+       }
+    }
+  return level;
+}
+
+static int
 cleandeps_check_mistakes(Solver *solv)
 {
   Pool *pool = solv->pool;
@@ -1941,6 +1939,291 @@ prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
   queue_truncate(q, j);
 }
 
+static int
+resolve_installed(Solver *solv, int level, int disablerules, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  int i, n, pass;
+  int installedpos = solv->installedpos;
+  Solvable *s;
+  Id p, pp;
+  int olevel, origlevel = level;
+
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n");
+  if (!installedpos)
+    installedpos = installed->start;
+  /* we use two passes if we need to update packages
+   * to create a better user experience */
+  for (pass = solv->updatemap.size ? 0 : 1; pass < 2; )
+    {
+      int passlevel = level;
+      Id *specialupdaters = solv->specialupdaters;
+      /* start with installedpos, the position that gave us problems the last time */
+      for (i = installedpos, n = installed->start; n < installed->end; i++, n++)
+       {
+         Rule *r, *rr;
+         Id d;
+
+         if (i == installed->end)
+           i = installed->start;
+         s = pool->solvables + i;
+         if (s->repo != installed)
+           continue;
+
+         if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start]))
+           continue;           /* already decided */
+         if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
+           continue;           /* updates first */
+         r = solv->rules + solv->updaterules + (i - installed->start);
+         rr = r;
+         if (!rr->p || rr->d < 0)      /* disabled -> look at feature rule */
+           rr -= solv->installed->end - solv->installed->start;
+         if (!rr->p)           /* identical to update rule? */
+           rr = r;
+         if (!rr->p)
+           continue;           /* orpaned package or pseudo package */
+
+         /* check if we should update this package to the latest version
+          * noupdate is set for erase jobs, in that case we want to deinstall
+          * the installed package and not replace it with a newer version
+          * rr->p != i is for dup jobs where the installed package cannot be kept */
+         if (dq->count)
+           queue_empty(dq);
+         if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i)))
+           {
+             if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
+               {
+                 /* special multiversion handling, make sure best version is chosen */
+                 if (rr->p == i && solv->decisionmap[i] >= 0)
+                   queue_push(dq, i);
+                 while ((p = pool->whatprovidesdata[d++]) != 0)
+                   if (solv->decisionmap[p] >= 0)
+                     queue_push(dq, p);
+                 if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start])
+                   prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq);
+                 if (dq->count)
+                   {
+                     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
+                     p = dq->elements[0];
+                     if (p != i && solv->decisionmap[p] == 0)
+                       {
+                         rr = solv->rules + solv->featurerules + (i - solv->installed->start);
+                         if (!rr->p)           /* update rule == feature rule? */
+                           rr = rr - solv->featurerules + solv->updaterules;
+                         dq->count = 1;
+                       }
+                     else
+                       dq->count = 0;
+                   }
+               }
+             else
+               {
+                 /* update to best package of the update rule */
+                 FOR_RULELITERALS(p, pp, rr)
+                   {
+                     if (solv->decisionmap[p] > 0)
+                       {
+                         dq->count = 0;                /* already fulfilled */
+                         break;
+                       }
+                     if (!solv->decisionmap[p])
+                       queue_push(dq, p);
+                   }
+               }
+           }
+         if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start])
+           prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq);
+         /* install best version */
+         if (dq->count)
+           {
+             olevel = level;
+             level = selectandinstall(solv, level, dq, disablerules, rr - solv->rules, SOLVER_REASON_UPDATE_INSTALLED);
+             if (level <= olevel)
+               {
+                 if (level < passlevel)
+                   break;      /* trouble */
+                 if (level < olevel)
+                   n = installed->start;       /* redo all */
+                 i--;
+                 n--;
+                 continue;
+               }
+           }
+         /* if still undecided keep package */
+         if (solv->decisionmap[i] == 0)
+           {
+             olevel = level;
+             if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
+               {
+#if 0
+                 POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i));
+                 level = setpropagatelearn(solv, level, -i, disablerules, 0, SOLVER_REASON_CLEANDEPS_ERASE);
+#else
+                 continue;
+#endif
+               }
+             else
+               {
+                 POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
+                 level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules, SOLVER_REASON_KEEP_INSTALLED);
+               }
+             if (level <= olevel)
+               {
+                 if (level < passlevel)
+                   break;      /* trouble */
+                 if (level < olevel)
+                   n = installed->start;       /* redo all */
+                 i--;
+                 n--;
+                 continue;     /* retry with learnt rule */
+               }
+           }
+       }
+      if (n < installed->end)
+       {
+         installedpos = i;     /* retry problem solvable next time */
+         if (level < origlevel)
+           break;              /* ran into trouble */
+         /* re-run all passes */
+          pass = solv->updatemap.size ? 0 : 1;
+         continue;
+       }
+      /* reset installedpos, advance to next pass */
+      installedpos = installed->start;
+      pass++;
+    }
+  solv->installedpos = installedpos;
+  return level;
+}
+
+static int
+resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  int i, j, n;
+  int postponed;
+  Rule *r;
+  int origlevel = level;
+  Id p, *dp;
+
+  /*
+   * decide
+   */
+  POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\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;
+      if (r->d < 0)            /* ignore disabled rules */
+       continue;
+      if (r->p < 0)            /* most common cases first */
+       {
+         if (r->d == 0 || solv->decisionmap[-r->p] <= 0)
+           continue;
+       }
+      if (dq->count)
+       queue_empty(dq);
+      if (r->d == 0)
+       {
+         /* binary or unary rule */
+         /* need two positive undecided literals, r->p already checked above */
+         if (r->w2 <= 0)
+           continue;
+         if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
+           continue;
+         queue_push(dq, r->p);
+         queue_push(dq, r->w2);
+       }
+      else
+       {
+         /* make sure that
+          * all negative literals are installed
+          * no positive literal is installed
+          * i.e. the rule is not fulfilled and we
+          * just need to decide on the positive literals
+          * (decisionmap[-r->p] for the r->p < 0 case is already checked above)
+          */
+         if (r->p >= 0)
+           {
+             if (solv->decisionmap[r->p] > 0)
+               continue;
+             if (solv->decisionmap[r->p] == 0)
+               queue_push(dq, r->p);
+           }
+         dp = pool->whatprovidesdata + r->d;
+         while ((p = *dp++) != 0)
+           {
+             if (p < 0)
+               {
+                 if (solv->decisionmap[-p] <= 0)
+                   break;
+               }
+             else
+               {
+                 if (solv->decisionmap[p] > 0)
+                   break;
+                 if (solv->decisionmap[p] == 0)
+                   queue_push(dq, p);
+               }
+           }
+         if (p)
+           continue;
+       }
+      IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+       {
+         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled ");
+         solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r);
+       }
+      /* dq->count < 2 cannot happen as this means that
+       * the rule is unit */
+      assert(dq->count > 1);
+
+      /* prune to cleandeps packages */
+      if (solv->cleandepsmap.size && solv->installed)
+       {
+         Repo *installed = solv->installed;
+         for (j = 0; j < dq->count; j++)
+           if (pool->solvables[dq->elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq->elements[j] - installed->start))
+             break;
+         if (j < dq->count)
+           {
+             dq->elements[0] = dq->elements[j];
+             queue_truncate(dq, 1);
+           }
+       }
+
+      if (dq->count > 1 && postponed >= 0)
+       {
+         policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE_NOREORDER);
+         if (dq->count > 1)
+           {
+             if (!postponed)
+               postponed = i;
+             continue;
+           }
+       }
+
+      level = selectandinstall(solv, level, dq, disablerules, r - solv->rules, SOLVER_REASON_RESOLVE);
+      if (level < origlevel)
+       break;          /* trouble */
+      /* something changed, so look at all rules again */
+      n = 0;
+    }
+  return level;
+}
+
+
 #ifdef ENABLE_COMPLEX_DEPS
 
 static void
@@ -2089,6 +2372,365 @@ prune_disfavored(Solver *solv, Queue *plist)
     queue_truncate(plist, j);
 }
 
+static int
+resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, int *rerunp)
+{
+  Pool *pool = solv->pool;
+  int i, j, qcount;
+  int olevel;
+  Solvable *s;
+  Map dqmap;
+  int decisioncount;
+  Id p;
+
+  POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n");
+  if (dq->count)
+    queue_empty(dq);   /* recommended packages */
+  if (dqs->count)
+    queue_empty(dqs);  /* supplemented packages */
+  for (i = 1; i < pool->nsolvables; i++)
+    {
+      if (solv->decisionmap[i] < 0)
+       continue;
+      s = pool->solvables + i;
+      if (solv->decisionmap[i] > 0)
+       {
+         /* installed, check for recommends */
+         Id *recp, rec, pp, p;
+         if (!solv->addalreadyrecommended && s->repo == solv->installed)
+           continue;
+         /* XXX need to special case AND ? */
+         if (s->recommends)
+           {
+             recp = s->repo->idarraydata + s->recommends;
+             while ((rec = *recp++) != 0)
+               {
+#ifdef ENABLE_COMPLEX_DEPS
+                 if (pool_is_complex_dep(pool, rec))
+                   {
+                     add_complex_recommends(solv, rec, dq, 0);
+                     continue;
+                   }
+#endif
+                 qcount = dq->count;
+                 FOR_PROVIDES(p, pp, rec)
+                   {
+                     if (solv->decisionmap[p] > 0)
+                       {
+                         dq->count = qcount;
+                         break;
+                       }
+                     else if (solv->decisionmap[p] == 0)
+                       {
+                         if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
+                           continue;
+                         queue_pushunique(dq, p);
+                       }
+                   }
+               }
+           }
+       }
+      else
+       {
+         /* not yet installed, check if supplemented */
+         if (!s->supplements)
+           continue;
+         if (!pool_installable(pool, s))
+           continue;
+         if (!solver_is_supplementing(solv, s))
+           continue;
+         if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
+           continue;
+         if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, i))
+           continue;   /* disfavored supplements, do not install */
+         queue_push(dqs, i);
+       }
+    }
+
+  /* filter out disfavored recommended packages */
+  if (dq->count && solv->isdisfavormap.size)
+    prune_disfavored(solv, dq);
+
+  /* filter out all packages obsoleted by installed packages */
+  /* this is no longer needed if we have (and trust) reverse obsoletes */
+  if ((dqs->count || dq->count) && solv->installed)
+    {
+      Map obsmap;
+      Id obs, *obsp, po, ppo;
+
+      map_init(&obsmap, pool->nsolvables);
+      for (p = solv->installed->start; p < solv->installed->end; p++)
+       {
+         s = pool->solvables + p;
+         if (s->repo != solv->installed || !s->obsoletes)
+           continue;
+         if (solv->decisionmap[p] <= 0)
+           continue;
+         if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p))
+           continue;
+         obsp = s->repo->idarraydata + s->obsoletes;
+         /* foreach obsoletes */
+         while ((obs = *obsp++) != 0)
+           FOR_PROVIDES(po, ppo, obs)
+             {
+               Solvable *pos = pool->solvables + po;
+               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs))
+                 continue;
+               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos))
+                 continue;
+               MAPSET(&obsmap, po);
+             }
+       }
+      for (i = j = 0; i < dqs->count; i++)
+       if (!MAPTST(&obsmap, dqs->elements[i]))
+         dqs->elements[j++] = dqs->elements[i];
+      dqs->count = j;
+      for (i = j = 0; i < dq->count; i++)
+       if (!MAPTST(&obsmap, dq->elements[i]))
+         dq->elements[j++] = dq->elements[i];
+      dq->count = j;
+      map_free(&obsmap);
+    }
+
+  /* filter out all already supplemented packages if requested */
+  if (!solv->addalreadyrecommended && dqs->count)
+    {
+      /* filter out old supplements */
+      for (i = j = 0; i < dqs->count; i++)
+       {
+         p = dqs->elements[i];
+         s = pool->solvables + p;
+         if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s))
+           dqs->elements[j++] = p;
+       }
+      dqs->count = j;
+    }
+
+  /* multiversion doesn't mix well with supplements.
+   * filter supplemented packages where we already decided
+   * to install a different version (see bnc#501088) */
+  if (dqs->count && solv->multiversion.size)
+    {
+      for (i = j = 0; i < dqs->count; i++)
+       {
+         p = dqs->elements[i];
+         if (MAPTST(&solv->multiversion, p))
+           {
+             Id p2, pp2;
+             s = pool->solvables + p;
+             FOR_PROVIDES(p2, pp2, s->name)
+               if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name)
+                 break;
+             if (p2)
+               continue;       /* ignore this package */
+           }
+         dqs->elements[j++] = p;
+       }
+      dqs->count = j;
+    }
+
+  /* implicitobsoleteusescolors doesn't mix well with supplements.
+   * filter supplemented packages where we already decided
+   * to install a different architecture */
+  if (dqs->count && pool->implicitobsoleteusescolors)
+    {
+      for (i = j = 0; i < dqs->count; i++)
+       {
+         Id p2, pp2;
+         p = dqs->elements[i];
+         s = pool->solvables + p;
+         FOR_PROVIDES(p2, pp2, s->name)
+           if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name && pool->solvables[p2].arch != s->arch)
+             break;
+         if (p2)
+           continue;   /* ignore this package */
+         dqs->elements[j++] = p;
+       }
+      dqs->count = j;
+    }
+
+  /* make dq contain both recommended and supplemented pkgs */
+  if (dqs->count)
+    {
+      for (i = 0; i < dqs->count; i++)
+       queue_pushunique(dq, dqs->elements[i]);
+    }
+
+  if (!dq->count)
+    return level;
+  *rerunp = 1;
+
+  if (dq->count == 1)
+    {
+      /* simple case, just one package. no need to choose to best version */
+      p = dq->elements[0];
+      if (dqs->count)
+       POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
+      else
+       POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
+      return setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP);
+    }
+
+  /* filter packages, this gives us the best versions */
+  policy_filter_unwanted(solv, dq, POLICY_MODE_RECOMMEND);
+
+  /* create map of result */
+  map_init(&dqmap, pool->nsolvables);
+  for (i = 0; i < dq->count; i++)
+    MAPSET(&dqmap, dq->elements[i]);
+
+  /* prune dqs so that it only contains the best versions */
+  for (i = j = 0; i < dqs->count; i++)
+    {
+      p = dqs->elements[i];
+      if (MAPTST(&dqmap, p))
+       dqs->elements[j++] = p;
+    }
+  dqs->count = j;
+
+  /* install all supplemented packages, but order first */
+  if (dqs->count > 1)
+    policy_filter_unwanted(solv, dqs, POLICY_MODE_SUPPLEMENT);
+  decisioncount = solv->decisionq.count;
+  for (i = 0; i < dqs->count; i++)
+    {
+      p = dqs->elements[i];
+      if (solv->decisionmap[p])
+       continue;
+      POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
+      olevel = level;
+      level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP);
+      if (level <= olevel)
+       break;
+    }
+  if (i < dqs->count || solv->decisionq.count < decisioncount)
+    {
+      map_free(&dqmap);
+      return level;
+    }
+
+  /* install all recommended packages */
+  /* more work as we want to created branches if multiple
+   * choices are valid */
+  for (i = 0; i < decisioncount; i++)
+    {
+      Id rec, *recp, pp;
+      p = solv->decisionq.elements[i];
+      if (p < 0)
+       continue;
+      s = pool->solvables + p;
+      if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed))
+       continue;
+      if (!s->recommends)
+       continue;
+      recp = s->repo->idarraydata + s->recommends;
+      while ((rec = *recp++) != 0)
+       {
+         queue_empty(dq);
+#ifdef ENABLE_COMPLEX_DEPS
+         if (pool_is_complex_dep(pool, rec))
+             add_complex_recommends(solv, rec, dq, &dqmap);
+         else
+#endif
+         FOR_PROVIDES(p, pp, rec)
+           {
+             if (solv->decisionmap[p] > 0)
+               {
+                 dq->count = 0;
+                 break;
+               }
+             else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
+               queue_push(dq, p);
+           }
+         if (!dq->count)
+           continue;
+         if (dq->count > 1)
+           policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
+         /* if we have multiple candidates we open a branch */
+         if (dq->count > 1)
+             createbranch(solv, level, dq, s - pool->solvables, rec);
+         p = dq->elements[0];
+         POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
+         olevel = level;
+         level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP);
+         if (level <= olevel || solv->decisionq.count < decisioncount)
+           break;      /* we had to revert some decisions */
+       }
+      if (rec)
+       break;  /* had a problem above, quit loop */
+    }
+  map_free(&dqmap);
+  return level;
+}
+
+
+static int
+resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *rerunp)
+{
+  Pool *pool = solv->pool;
+  int i;
+  Id p;
+  int installedone = 0;
+  int olevel;
+
+  /* let's see if we can install some unsupported package */
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n");
+  for (i = 0; i < solv->orphaned.count; i++)
+    {
+      p = solv->orphaned.elements[i];
+      if (solv->decisionmap[p])
+       continue;       /* already decided */
+      if (solv->droporphanedmap_all)
+       continue;
+      if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
+       continue;
+      POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p));
+      olevel = level;
+      level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN);
+      installedone = 1;
+      if (level < olevel)
+       break;
+    }
+  if (installedone || i < solv->orphaned.count)
+    {
+      *rerunp = 1;
+      return level;
+    }
+  for (i = 0; i < solv->orphaned.count; i++)
+    {
+      p = solv->orphaned.elements[i];
+      if (solv->decisionmap[p])
+       continue;       /* already decided */
+      POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p));
+      olevel = level;
+      level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN);
+      if (level < olevel)
+       {
+         *rerunp = 1;
+         return level;
+       }
+    }
+  if (solv->brokenorphanrules)
+    {
+      solver_check_brokenorphanrules(solv, dq);
+      if (dq->count)
+       {
+         policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
+         for (i = 0; i < dq->count; i++)
+           {
+             p = dq->elements[i];
+             POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p));
+             olevel = level;
+             level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN);
+             if (level < olevel)
+               break;
+           }
+         *rerunp = 1;
+       }
+    }
+  return level;
+}
+
 /*-------------------------------------------------------------------
  *
  * solver_run_sat
@@ -2105,12 +2747,11 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
   int systemlevel;
   int level, olevel;
   Rule *r;
-  int i, j, n;
+  int i;
   Solvable *s;
   Pool *pool = solv->pool;
-  Id p, pp, *dp, postponed;
+  Id p;
   int minimizationsteps;
-  int installedpos = solv->installed ? solv->installed->start : 0;
 
   IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
     {
@@ -2126,6 +2767,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
 
   queue_init(&dq);
   queue_init(&dqs);
+  solv->installedpos = 0;
+  solv->do_extra_reordering = 0;
 
   /*
    * here's the main loop:
@@ -2154,683 +2797,114 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
          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)
-           {
-             level = analyze_unsolvable(solv, r, disablerules);
-             continue;
-           }
-         systemlevel = level + 1;
-       }
-
-      /*
-       * resolve jobs first (unless focus_installed is set)
-       */
-     if (level < systemlevel && !solv->focus_installed)
-       {
-         olevel = level;
-         level = resolve_jobrules(solv, level, disablerules, &dq);
-         if (level < olevel)
-           continue;
-         systemlevel = level + 1;
-       }
-
-
-      /*
-       * installed packages
-       */
-      if (!solv->decisioncnt_update)
-       solv->decisioncnt_update = solv->decisionq.count;
-      if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
-       {
-         Repo *installed = solv->installed;
-         int pass;
-
-         POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n");
-         /* we use two passes if we need to update packages
-           * to create a better user experience */
-         for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++)
-           {
-             int passlevel = level;
-             Id *specialupdaters = solv->specialupdaters;
-             if (pass == 1 && !solv->decisioncnt_keep)
-               solv->decisioncnt_keep = solv->decisionq.count;
-             /* start with installedpos, the position that gave us problems the last time */
-             for (i = installedpos, n = installed->start; n < installed->end; i++, n++)
-               {
-                 Rule *rr;
-                 Id d;
-
-                 if (i == installed->end)
-                   i = installed->start;
-                 s = pool->solvables + i;
-                 if (s->repo != installed)
-                   continue;
-
-                 if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start]))
-                   continue;           /* already decided */
-                 if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
-                   continue;           /* updates first */
-                 r = solv->rules + solv->updaterules + (i - installed->start);
-                 rr = r;
-                 if (!rr->p || rr->d < 0)      /* disabled -> look at feature rule */
-                   rr -= solv->installed->end - solv->installed->start;
-                 if (!rr->p)           /* identical to update rule? */
-                   rr = r;
-                 if (!rr->p)
-                   continue;           /* orpaned package or pseudo package */
-
-                 /* check if we should update this package to the latest version
-                  * noupdate is set for erase jobs, in that case we want to deinstall
-                  * the installed package and not replace it with a newer version
-                  * rr->p != i is for dup jobs where the installed package cannot be kept */
-                 queue_empty(&dq);
-                 if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i)))
-                   {
-                     if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
-                       {
-                         /* special multiversion handling, make sure best version is chosen */
-                         if (rr->p == i && solv->decisionmap[i] >= 0)
-                           queue_push(&dq, i);
-                         while ((p = pool->whatprovidesdata[d++]) != 0)
-                           if (solv->decisionmap[p] >= 0)
-                             queue_push(&dq, p);
-                         if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
-                           prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
-                         if (dq.count)
-                           {
-                             policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
-                             p = dq.elements[0];
-                             if (p != i && solv->decisionmap[p] == 0)
-                               {
-                                 rr = solv->rules + solv->featurerules + (i - solv->installed->start);
-                                 if (!rr->p)           /* update rule == feature rule? */
-                                   rr = rr - solv->featurerules + solv->updaterules;
-                                 dq.count = 1;
-                               }
-                             else
-                               dq.count = 0;
-                           }
-                       }
-                     else
-                       {
-                         /* update to best package of the update rule */
-                         FOR_RULELITERALS(p, pp, rr)
-                           {
-                             if (solv->decisionmap[p] > 0)
-                               {
-                                 dq.count = 0;         /* already fulfilled */
-                                 break;
-                               }
-                             if (!solv->decisionmap[p])
-                               queue_push(&dq, p);
-                           }
-                       }
-                   }
-                 if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
-                   prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
-                 /* install best version */
-                 if (dq.count)
-                   {
-                     olevel = level;
-                     level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
-                     if (level <= olevel)
-                       {
-                         if (level < passlevel)
-                           break;      /* trouble */
-                         if (level < olevel)
-                           n = installed->start;       /* redo all */
-                         i--;
-                         n--;
-                         continue;
-                       }
-                   }
-                 /* if still undecided keep package */
-                 if (solv->decisionmap[i] == 0)
-                   {
-                     olevel = level;
-                     if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
-                       {
-#if 0
-                         POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i));
-                         level = setpropagatelearn(solv, level, -i, disablerules, 0);
-#else
-                         continue;
-#endif
-                       }
-                     else
-                       {
-                         POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
-                         level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
-                       }
-                     if (level <= olevel)
-                       {
-                         if (level < passlevel)
-                           break;      /* trouble */
-                         if (level < olevel)
-                           n = installed->start;       /* redo all */
-                         i--;
-                         n--;
-                         continue;     /* retry with learnt rule */
-                       }
-                   }
-               }
-             if (n < installed->end)
-               {
-                 installedpos = i;     /* retry problem solvable next time */
-                 break;                /* ran into trouble */
-               }
-             installedpos = installed->start;  /* reset installedpos */
+             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)
+           {
+             level = analyze_unsolvable(solv, r, disablerules);
+             continue;
            }
          systemlevel = level + 1;
-         if (pass < 2)
-           continue;           /* had trouble, retry */
        }
-      if (!solv->decisioncnt_keep)
-       solv->decisioncnt_keep = solv->decisionq.count;
 
-     if (level < systemlevel && solv->focus_installed)
+      /*
+       * resolve jobs first (unless focus_installed is set)
+       */
+     if (level < systemlevel && !solv->focus_installed)
        {
+         if (solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
+           solv->do_extra_reordering = 1;
          olevel = level;
          level = resolve_jobrules(solv, level, disablerules, &dq);
+         solv->do_extra_reordering = 0;
          if (level < olevel)
            continue;
          systemlevel = level + 1;
        }
 
-      if (level < systemlevel)
-        systemlevel = level;
+      /* resolve job dependencies in the focus_best case */
+      if (level < systemlevel && solv->focus_best && !solv->focus_installed && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
+       {
+         solv->do_extra_reordering = 1;
+         olevel = level;
+         level = resolve_dependencies(solv, level, disablerules, &dq);
+         solv->do_extra_reordering = 0;
+         if (level < olevel)
+           continue;           /* start over */
+         systemlevel = level + 1;
+       }
 
       /*
-       * decide
+       * installed packages
        */
-      if (!solv->decisioncnt_resolve)
-        solv->decisioncnt_resolve = solv->decisionq.count;
-      POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n");
-      postponed = 0;
-      for (i = 1, n = 1; ; i++, n++)
+      if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
        {
-         if (n >= solv->nrules)
-           {
-             if (postponed <= 0)
-               break;
-             i = postponed;
-             postponed = -1;
-             n = 1;
-           }
-         if (i == solv->nrules)
-           i = 1;
-         r = solv->rules + i;
-         if (r->d < 0)         /* ignore disabled rules */
+         olevel = level;
+         level = resolve_installed(solv, level, disablerules, &dq);
+         if (level < olevel)
            continue;
-         if (r->p < 0)         /* most common cases first */
-           {
-             if (r->d == 0 || solv->decisionmap[-r->p] <= 0)
-               continue;
-           }
-         if (dq.count)
-           queue_empty(&dq);
-         if (r->d == 0)
-           {
-             /* binary or unary rule */
-             /* need two positive undecided literals, r->p already checked above */
-             if (r->w2 <= 0)
-               continue;
-             if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
-               continue;
-             queue_push(&dq, r->p);
-             queue_push(&dq, r->w2);
-           }
-         else
-           {
-             /* make sure that
-               * all negative literals are installed
-               * no positive literal is installed
-              * i.e. the rule is not fulfilled and we
-               * just need to decide on the positive literals
-              * (decisionmap[-r->p] for the r->p < 0 case is already checked above)
-               */
-             if (r->p >= 0)
-               {
-                 if (solv->decisionmap[r->p] > 0)
-                   continue;
-                 if (solv->decisionmap[r->p] == 0)
-                   queue_push(&dq, r->p);
-               }
-             dp = pool->whatprovidesdata + r->d;
-             while ((p = *dp++) != 0)
-               {
-                 if (p < 0)
-                   {
-                     if (solv->decisionmap[-p] <= 0)
-                       break;
-                   }
-                 else
-                   {
-                     if (solv->decisionmap[p] > 0)
-                       break;
-                     if (solv->decisionmap[p] == 0)
-                       queue_push(&dq, p);
-                   }
-               }
-             if (p)
-               continue;
-           }
-         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
-           {
-             POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled ");
-             solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r);
-           }
-         /* dq.count < 2 cannot happen as this means that
-          * the rule is unit */
-         assert(dq.count > 1);
-
-         /* prune to cleandeps packages */
-         if (solv->cleandepsmap.size && solv->installed)
-           {
-             Repo *installed = solv->installed;
-             for (j = 0; j < dq.count; j++)
-               if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start))
-                 break;
-             if (j < dq.count)
-               {
-                 dq.elements[0] = dq.elements[j];
-                 queue_truncate(&dq, 1);
-               }
-           }
-
-         if (dq.count > 1 && postponed >= 0)
-           {
-             policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE_NOREORDER);
-             if (dq.count > 1)
-               {
-                 if (!postponed)
-                   postponed = i;
-                 continue;
-               }
-           }
+         systemlevel = level + 1;
+       }
 
+     /* resolve jobs in focus_installed case */
+     if (level < systemlevel && solv->focus_installed)
+       {
          olevel = level;
-         level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules);
-         if (level < systemlevel)
-           break;              /* trouble */
-         /* something changed, so look at all rules again */
-         n = 0;
+         level = resolve_jobrules(solv, level, disablerules, &dq);
+         if (level < olevel)
+           continue;
+         systemlevel = level + 1;
        }
 
-      if (n < solv->nrules)    /* ran into trouble? */
+      if (level < systemlevel)
+        systemlevel = level;
+
+      /* resolve all dependencies */
+      olevel = level;
+      level = resolve_dependencies(solv, level, disablerules, &dq);
+      if (level < olevel)
         continue;              /* start over */
 
       /* decide leftover cleandeps packages */
       if (solv->cleandepsmap.size && solv->installed)
-       {
-         for (p = solv->installed->start; p < solv->installed->end; p++)
-           {
-             s = pool->solvables + p;
-             if (s->repo != solv->installed)
-               continue;
-             if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
-               {
-                 POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
-                 olevel = level;
-                 level = setpropagatelearn(solv, level, -p, 0, 0);
-                 if (level < olevel)
-                   break;
-               }
-           }
-         if (p < solv->installed->end)
-           continue;
-       }
+       {
+         for (p = solv->installed->start; p < solv->installed->end; p++)
+           {
+             s = pool->solvables + p;
+             if (s->repo != solv->installed)
+               continue;
+             if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
+               {
+                 POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
+                 olevel = level;
+                 level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE);
+                 if (level < olevel)
+                   break;
+               }
+           }
+         if (p < solv->installed->end)
+           continue;
+       }
 
       /* at this point we have a consistent system. now do the extras... */
 
-      if (!solv->decisioncnt_weak)
-        solv->decisioncnt_weak = solv->decisionq.count;
       if (doweak)
        {
-         int qcount;
-
-         POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n");
-         queue_empty(&dq);     /* recommended packages */
-         queue_empty(&dqs);    /* supplemented packages */
-         for (i = 1; i < pool->nsolvables; i++)
-           {
-             if (solv->decisionmap[i] < 0)
-               continue;
-             if (solv->decisionmap[i] > 0)
-               {
-                 /* installed, check for recommends */
-                 Id *recp, rec, pp, p;
-                 s = pool->solvables + i;
-                 if (!solv->addalreadyrecommended && s->repo == solv->installed)
-                   continue;
-                 /* XXX need to special case AND ? */
-                 if (s->recommends)
-                   {
-                     recp = s->repo->idarraydata + s->recommends;
-                     while ((rec = *recp++) != 0)
-                       {
-#ifdef ENABLE_COMPLEX_DEPS
-                         if (pool_is_complex_dep(pool, rec))
-                           {
-                             add_complex_recommends(solv, rec, &dq, 0);
-                             continue;
-                           }
-#endif
-                         qcount = dq.count;
-                         FOR_PROVIDES(p, pp, rec)
-                           {
-                             if (solv->decisionmap[p] > 0)
-                               {
-                                 dq.count = qcount;
-                                 break;
-                               }
-                             else if (solv->decisionmap[p] == 0)
-                               {
-                                 if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
-                                   continue;
-                                 queue_pushunique(&dq, p);
-                               }
-                           }
-                       }
-                   }
-               }
-             else
-               {
-                 s = pool->solvables + i;
-                 if (!s->supplements)
-                   continue;
-                 if (!pool_installable(pool, s))
-                   continue;
-                 if (!solver_is_supplementing(solv, s))
-                   continue;
-                 if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
-                   continue;
-                 if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, i))
-                   continue;   /* disfavored supplements, do not install */
-                 queue_push(&dqs, i);
-               }
-           }
-
-         /* filter out disfavored recommended packages */
-         if (dq.count && solv->isdisfavormap.size)
-           prune_disfavored(solv, &dq);
-
-         /* filter out all packages obsoleted by installed packages */
-         /* this is no longer needed if we have reverse obsoletes */
-          if ((dqs.count || dq.count) && solv->installed)
-           {
-             Map obsmap;
-             Id obs, *obsp, po, ppo;
-
-             map_init(&obsmap, pool->nsolvables);
-             for (p = solv->installed->start; p < solv->installed->end; p++)
-               {
-                 s = pool->solvables + p;
-                 if (s->repo != solv->installed || !s->obsoletes)
-                   continue;
-                 if (solv->decisionmap[p] <= 0)
-                   continue;
-                 if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p))
-                   continue;
-                 obsp = s->repo->idarraydata + s->obsoletes;
-                 /* foreach obsoletes */
-                 while ((obs = *obsp++) != 0)
-                   FOR_PROVIDES(po, ppo, obs)
-                     {
-                       Solvable *pos = pool->solvables + po;
-                       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs))
-                         continue;
-                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos))
-                         continue;
-                       MAPSET(&obsmap, po);
-                     }
-               }
-             for (i = j = 0; i < dqs.count; i++)
-               if (!MAPTST(&obsmap, dqs.elements[i]))
-                 dqs.elements[j++] = dqs.elements[i];
-             dqs.count = j;
-             for (i = j = 0; i < dq.count; i++)
-               if (!MAPTST(&obsmap, dq.elements[i]))
-                 dq.elements[j++] = dq.elements[i];
-             dq.count = j;
-             map_free(&obsmap);
-           }
-
-          /* filter out all already supplemented packages if requested */
-          if (!solv->addalreadyrecommended && dqs.count)
-           {
-             /* filter out old supplements */
-             for (i = j = 0; i < dqs.count; i++)
-               {
-                 p = dqs.elements[i];
-                 s = pool->solvables + p;
-                 if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s))
-                   dqs.elements[j++] = p;
-               }
-             dqs.count = j;
-           }
-
-         /* multiversion doesn't mix well with supplements.
-          * filter supplemented packages where we already decided
-          * to install a different version (see bnc#501088) */
-          if (dqs.count && solv->multiversion.size)
-           {
-             for (i = j = 0; i < dqs.count; i++)
-               {
-                 p = dqs.elements[i];
-                 if (MAPTST(&solv->multiversion, p))
-                   {
-                     Id p2, pp2;
-                     s = pool->solvables + p;
-                     FOR_PROVIDES(p2, pp2, s->name)
-                       if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name)
-                         break;
-                     if (p2)
-                       continue;       /* ignore this package */
-                   }
-                 dqs.elements[j++] = p;
-               }
-             dqs.count = j;
-           }
-
-         /* implicitobsoleteusescolors doesn't mix well with supplements.
-          * filter supplemented packages where we already decided
-          * to install a different architecture */
-          if (dqs.count && pool->implicitobsoleteusescolors)
-           {
-             for (i = j = 0; i < dqs.count; i++)
-               {
-                 Id p2, pp2;
-                 p = dqs.elements[i];
-                 s = pool->solvables + p;
-                 FOR_PROVIDES(p2, pp2, s->name)
-                   if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name && pool->solvables[p2].arch != s->arch)
-                     break;
-                 if (p2)
-                   continue;   /* ignore this package */
-                 dqs.elements[j++] = p;
-               }
-             dqs.count = j;
-           }
-
-          /* make dq contain both recommended and supplemented pkgs */
-         if (dqs.count)
-           {
-             for (i = 0; i < dqs.count; i++)
-               queue_pushunique(&dq, dqs.elements[i]);
-           }
-
-         if (dq.count)
-           {
-             Map dqmap;
-             int decisioncount = solv->decisionq.count;
-
-             if (dq.count == 1)
-               {
-                 /* simple case, just one package. no need to choose to best version */
-                 p = dq.elements[0];
-                 if (dqs.count)
-                   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
-                 else
-                   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
-                 level = setpropagatelearn(solv, level, p, 0, 0);
-                 continue;     /* back to main loop */
-               }
-
-             /* filter packages, this gives us the best versions */
-             policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
-
-             /* create map of result */
-             map_init(&dqmap, pool->nsolvables);
-             for (i = 0; i < dq.count; i++)
-               MAPSET(&dqmap, dq.elements[i]);
-
-             /* prune dqs so that it only contains the best versions */
-             for (i = j = 0; i < dqs.count; i++)
-               {
-                 p = dqs.elements[i];
-                 if (MAPTST(&dqmap, p))
-                   dqs.elements[j++] = p;
-               }
-             dqs.count = j;
-
-             /* install all supplemented packages, but order first */
-             if (dqs.count > 1)
-               policy_filter_unwanted(solv, &dqs, POLICY_MODE_SUPPLEMENT);
-             for (i = 0; i < dqs.count; i++)
-               {
-                 p = dqs.elements[i];
-                 if (solv->decisionmap[p])
-                   continue;
-                 POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
-                 olevel = level;
-                 level = setpropagatelearn(solv, level, p, 0, 0);
-                 if (level <= olevel)
-                   break;
-               }
-             if (i < dqs.count || solv->decisionq.count < decisioncount)
-               {
-                 map_free(&dqmap);
-                 continue;
-               }
-
-             /* install all recommended packages */
-             /* more work as we want to created branches if multiple
-               * choices are valid */
-             for (i = 0; i < decisioncount; i++)
-               {
-                 Id rec, *recp, pp;
-                 p = solv->decisionq.elements[i];
-                 if (p < 0)
-                   continue;
-                 s = pool->solvables + p;
-                 if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed))
-                   continue;
-                 if (!s->recommends)
-                   continue;
-                 recp = s->repo->idarraydata + s->recommends;
-                 while ((rec = *recp++) != 0)
-                   {
-                     queue_empty(&dq);
-#ifdef ENABLE_COMPLEX_DEPS
-                     if (pool_is_complex_dep(pool, rec))
-                         add_complex_recommends(solv, rec, &dq, &dqmap);
-                     else
-#endif
-                     FOR_PROVIDES(p, pp, rec)
-                       {
-                         if (solv->decisionmap[p] > 0)
-                           {
-                             dq.count = 0;
-                             break;
-                           }
-                         else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
-                           queue_push(&dq, p);
-                       }
-                     if (!dq.count)
-                       continue;
-                     if (dq.count > 1)
-                       policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
-                     /* if we have multiple candidates we open a branch */
-                     if (dq.count > 1)
-                         createbranch(solv, level, &dq, s - pool->solvables, rec);
-                     p = dq.elements[0];
-                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
-                     olevel = level;
-                     level = setpropagatelearn(solv, level, p, 0, 0);
-                     if (level <= olevel || solv->decisionq.count < decisioncount)
-                       break;  /* we had to revert some decisions */
-                   }
-                 if (rec)
-                   break;      /* had a problem above, quit loop */
-               }
-             map_free(&dqmap);
-             continue;         /* back to main loop so that all deps are checked */
-           }
+         int rerun = 0;
+         level = resolve_weak(solv, level, disablerules, &dq, &dqs, &rerun);
+         if (rerun)
+           continue;
        }
 
-      if (!solv->decisioncnt_orphan)
-        solv->decisioncnt_orphan = solv->decisionq.count;
       if (solv->installed && (solv->orphaned.count || solv->brokenorphanrules))
        {
-         int installedone = 0;
-
-         /* let's see if we can install some unsupported package */
-         POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n");
-         for (i = 0; i < solv->orphaned.count; i++)
-           {
-             p = solv->orphaned.elements[i];
-             if (solv->decisionmap[p])
-               continue;       /* already decided */
-             if (solv->droporphanedmap_all)
-               continue;
-             if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
-               continue;
-             POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p));
-             olevel = level;
-             level = setpropagatelearn(solv, level, p, 0, 0);
-             installedone = 1;
-             if (level < olevel)
-               break;
-           }
-         if (installedone || i < solv->orphaned.count)
-           continue;           /* back to main loop */
-         for (i = 0; i < solv->orphaned.count; i++)
-           {
-             p = solv->orphaned.elements[i];
-             if (solv->decisionmap[p])
-               continue;       /* already decided */
-             POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p));
-             olevel = level;
-             level = setpropagatelearn(solv, level, -p, 0, 0);
-             if (level < olevel)
-               break;
-           }
-         if (i < solv->orphaned.count)
-           continue;           /* back to main loop */
-          if (solv->brokenorphanrules)
-           {
-             solver_check_brokenorphanrules(solv, &dq);
-             if (dq.count)
-               {
-                 policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
-                 for (i = 0; i < dq.count; i++)
-                   {
-                     p = dq.elements[i];
-                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p));
-                     olevel = level;
-                     level = setpropagatelearn(solv, level, p, 0, 0);
-                     if (level < olevel)
-                       break;
-                   }
-                 continue;
-               }
-           }
+         int rerun = 0;
+         level = resolve_orphaned(solv, level, disablerules, &dq, &rerun);
+         if (rerun)
+           continue;
        }
-
+         
      /* one final pass to make sure we decided all installed packages */
       if (solv->installed)
        {
@@ -2843,7 +2917,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                continue;
              POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing unwanted %s\n", pool_solvid2str(pool, p));
              olevel = level;
-             level = setpropagatelearn(solv, level, -p, 0, 0);
+             level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE);
              if (level < olevel)
                break;
            }
@@ -2950,22 +3024,13 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
       /* no minimization found, we're finally finished! */
       break;
     }
+  assert(level == -1 || level + 1 == solv->decisionq_reason.count);
 
   POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
 
   POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n");
   queue_free(&dq);
   queue_free(&dqs);
-  if (level < 0)
-    {
-      /* unsolvable */
-      solv->decisioncnt_jobs = solv->decisionq.count;
-      solv->decisioncnt_update = solv->decisionq.count;
-      solv->decisioncnt_keep = solv->decisionq.count;
-      solv->decisioncnt_resolve = solv->decisionq.count;
-      solv->decisioncnt_weak = solv->decisionq.count;
-      solv->decisioncnt_orphan = solv->decisionq.count;
-    }
 #if 0
   solver_printdecisionq(solv, SOLV_DEBUG_RESULT);
 #endif
@@ -3141,8 +3206,10 @@ solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap)
          Solvable *s;
          Repo *repo = pool_id2repo(pool, what);
          if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             MAPSET(multiversionmap, p);
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               MAPSET(multiversionmap, p);
+           }
        }
       FOR_JOB_SELECT(p, pp, select, what)
         MAPSET(multiversionmap, p);
@@ -3513,7 +3580,7 @@ solver_solve(Solver *solv, Queue *job)
     memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
   queue_empty(&solv->decisionq);
   queue_empty(&solv->decisionq_why);
-  solv->decisioncnt_jobs = solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
+  queue_empty(&solv->decisionq_reason);
   queue_empty(&solv->learnt_why);
   queue_empty(&solv->learnt_pool);
   queue_empty(&solv->branches);
@@ -3947,8 +4014,10 @@ solver_solve(Solver *solv, Queue *job)
            {
              Repo *repo = pool_id2repo(pool, what);
              if (repo)
-               FOR_REPO_SOLVABLES(repo, p, s)
-                 solver_addjobrule(solv, -p, 0, 0, i, weak);
+               {
+                 FOR_REPO_SOLVABLES(repo, p, s)
+                   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))
@@ -4023,8 +4092,10 @@ solver_solve(Solver *solv, Queue *job)
            {
              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, 0, i, weak);
+               {
+                 FOR_REPO_SOLVABLES(repo, p, s)
+                   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, 0, i, weak);
@@ -4284,20 +4355,12 @@ void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *su
       MAPZERO(&solv->recommendsmap);
 
       /* put all packages the solver already chose in the map */
-      if (solv->decisioncnt_weak)
-       {
-         for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++)
-           {
-             Id why;
-             why = solv->decisionq_why.elements[i];
-             if (why)
-               continue;       /* forced by unit rule or dep resolving */
-             p = solv->decisionq.elements[i];
-             if (p < 0)
-               continue;
+      for (i = 1; i < solv->decisionq.count; i++)
+        if ((p = solv->decisionq.elements[i]) > 0 && solv->decisionq_why.elements[i] == 0)
+         {
+           if (solv->decisionq_reason.elements[solv->decisionmap[p]] == SOLVER_REASON_WEAKDEP)
              MAPSET(&solv->recommendsmap, p);
-           }
-       }
+         }
 
       for (i = 0; i < solv->decisionq.count; i++)
        {
@@ -4565,36 +4628,8 @@ solver_describe_decision(Solver *solv, Id p, Id *infop)
     *infop = why > 0 ? why : -why;
   if (why > 0)
     return SOLVER_REASON_UNIT_RULE;
-  why = -why;
-  if (i == 0)
-    return SOLVER_REASON_KEEP_INSTALLED;       /* the systemsolvable */
-  if (i < solv->decisioncnt_update)
-    return SOLVER_REASON_RESOLVE_JOB;
-  if (i < solv->decisioncnt_keep)
-    {
-      if (why == 0 && pp < 0)
-       return SOLVER_REASON_CLEANDEPS_ERASE;
-      return SOLVER_REASON_UPDATE_INSTALLED;
-    }
-  if (i < solv->decisioncnt_resolve)
-    {
-      if (solv->focus_installed && i >= solv->decisioncnt_jobs)
-       return SOLVER_REASON_RESOLVE_JOB;
-      if (why == 0 && pp < 0)
-       return SOLVER_REASON_CLEANDEPS_ERASE;
-      return SOLVER_REASON_KEEP_INSTALLED;
-    }
-  if (i < solv->decisioncnt_weak)
-    {
-      if (why == 0 && pp < 0)
-       return SOLVER_REASON_CLEANDEPS_ERASE;
-    }
-  if (why > 0)
-    return SOLVER_REASON_RESOLVE;
-  /* weak or orphaned */
-  if (i < solv->decisioncnt_orphan)
-    return SOLVER_REASON_WEAKDEP;
-  return SOLVER_REASON_RESOLVE_ORPHAN;
+  i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
+  return solv->decisionq_reason.elements[i];
 }
 
 
@@ -4615,7 +4650,8 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
       break;
   if (decisionno == solv->decisionq.count)
     return;    /* huh? */
-  if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan)
+  i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
+  if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP)
     return;    /* huh? */
 
   /* 1) list all packages that recommend us */
@@ -4716,8 +4752,10 @@ pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
       Repo *repo = pool_id2repo(pool, what);
       Solvable *s;
       if (repo)
-       FOR_REPO_SOLVABLES(repo, p, s)
-         queue_push(pkgs, p);
+       {
+         FOR_REPO_SOLVABLES(repo, p, s)
+           queue_push(pkgs, p);
+       }
     }
   else
     {
@@ -4873,8 +4911,10 @@ solver_get_userinstalled(Solver *solv, Queue *q, int flags)
          what = solv->job.elements[i + 1];
          select = how & SOLVER_SELECTMASK;
          if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
-           FOR_REPO_SOLVABLES(installed, p, s)
-             MAPSET(&userinstalled, p - installed->start);
+           {
+             FOR_REPO_SOLVABLES(installed, p, s)
+               MAPSET(&userinstalled, p - installed->start);
+           }
          FOR_JOB_SELECT(p, pp, select, what)
            if (pool->solvables[p].repo == installed)
              MAPSET(&userinstalled, p - installed->start);
index 758f1eb..be240c9 100644 (file)
@@ -107,19 +107,13 @@ struct _Solver {
   /* our decisions: */
   Queue decisionq;                      /* >0:install, <0:remove/conflict */
   Queue decisionq_why;                 /* index of rule, Offset into rules */
+  Queue decisionq_reason;              /* reason for decision, indexed by level */
 
   Id *decisionmap;                     /* map for all available solvables,
                                         * = 0: undecided
                                         * > 0: level of decision when installed,
                                         * < 0: level of decision when conflict */
 
-  int decisioncnt_jobs;
-  int decisioncnt_update;
-  int decisioncnt_keep;
-  int decisioncnt_resolve;
-  int decisioncnt_weak;
-  int decisioncnt_orphan;
-
   /* learnt rule history */
   Queue learnt_why;
   Queue learnt_pool;
@@ -166,6 +160,7 @@ struct _Solver {
   int bestobeypolicy;                  /* true: stay in policy with the best rules */
   int noautotarget;                    /* true: do not assume targeted for up/dup jobs that contain no installed solvable */
   int focus_installed;                 /* true: resolve update rules first */
+  int focus_best;                      /* true: resolve job dependencies first */
   int do_yum_obsoletes;                        /* true: add special yumobs rules */
   int urpmreorder;                     /* true: do special urpm package reordering */
 
@@ -203,6 +198,9 @@ struct _Solver {
   Queue *favorq;
   Map favormap;                                /* favored / disfavored packages */
   Map isdisfavormap;
+
+  int installedpos;                    /* for resolve_installed */
+  int do_extra_reordering;             /* reorder for future installed packages */
 #endif /* LIBSOLV_INTERNAL */
 };
 
@@ -309,6 +307,7 @@ typedef struct _Solver Solver;
 #define SOLVER_FLAG_YUM_OBSOLETES              21
 #define SOLVER_FLAG_NEED_UPDATEPROVIDE         22
 #define SOLVER_FLAG_URPM_REORDER               23
+#define SOLVER_FLAG_FOCUS_BEST                 24
 
 #define GET_USERINSTALLED_NAMES                        (1 << 0)        /* package names instead of ids */
 #define GET_USERINSTALLED_INVERTED             (1 << 1)        /* autoinstalled */
index 75dc63f..9f59d75 100644 (file)
@@ -28,6 +28,7 @@ extern int solv_version_patch;
 #cmakedefine LIBSOLV_FEATURE_COMPLEX_DEPS
 #cmakedefine LIBSOLV_FEATURE_MULTI_SEMANTICS
 
+#cmakedefine LIBSOLVEXT_FEATURE_RPMPKG
 #cmakedefine LIBSOLVEXT_FEATURE_RPMDB
 #cmakedefine LIBSOLVEXT_FEATURE_RPMDB_BYRPMHEADER
 #cmakedefine LIBSOLVEXT_FEATURE_PUBKEY
diff --git a/test/testcases/focus/best.t b/test/testcases/focus/best.t
new file mode 100644 (file)
index 0000000..a7a46b9
--- /dev/null
@@ -0,0 +1,23 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A2 1 1 noarch
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A 2 1 noarch
+#>=Pkg: B 1 1 noarch
+#>=Req: A = 1
+#>=Pkg: B 2 1 noarch
+#>=Req: A = 2
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: A2 2 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Req: A2 = 1
+#>=Pkg: B2 2 1 noarch
+#>=Req: A2 = 2
+#>=Pkg: C 1 1 noarch
+#>=Req: B2
+system i686 rpm system
+solverflags focusbest
+
+job install name B
+job install name C
diff --git a/test/testcases/focus/installed.t b/test/testcases/focus/installed.t
new file mode 100644 (file)
index 0000000..4f49d35
--- /dev/null
@@ -0,0 +1,23 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A2 1 1 noarch
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A 2 1 noarch
+#>=Pkg: B 1 1 noarch
+#>=Req: A = 1
+#>=Pkg: B 2 1 noarch
+#>=Req: A = 2
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: A2 2 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Req: A2 = 1
+#>=Pkg: B2 2 1 noarch
+#>=Req: A2 = 2
+#>=Pkg: C 1 1 noarch
+#>=Req: B2
+system i686 rpm system
+solverflags focusinstalled
+
+job install name B
+job install name C
diff --git a/test/testcases/focus/normal.t b/test/testcases/focus/normal.t
new file mode 100644 (file)
index 0000000..6e562a3
--- /dev/null
@@ -0,0 +1,22 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A2 1 1 noarch
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A 2 1 noarch
+#>=Pkg: B 1 1 noarch
+#>=Req: A = 1
+#>=Pkg: B 2 1 noarch
+#>=Req: A = 2
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: A2 2 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Req: A2 = 1
+#>=Pkg: B2 2 1 noarch
+#>=Req: A2 = 2
+#>=Pkg: C 1 1 noarch
+#>=Req: B2
+system i686 rpm system
+
+job install name B
+job install name C
index 16fa097..6b592f7 100644 (file)
@@ -10,15 +10,18 @@ IF (ENABLE_RPMDB)
 ADD_EXECUTABLE (rpmdb2solv rpmdb2solv.c)
 TARGET_LINK_LIBRARIES (rpmdb2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
 
-ADD_EXECUTABLE (rpms2solv rpms2solv.c)
-TARGET_LINK_LIBRARIES (rpms2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
 ADD_EXECUTABLE (findfileconflicts findfileconflicts.c)
 TARGET_LINK_LIBRARIES (findfileconflicts libsolvext libsolv ${SYSTEM_LIBRARIES})
 
-SET (tools_list ${tools_list} rpmdb2solv rpms2solv)
+SET (tools_list ${tools_list} rpmdb2solv)
 ENDIF (ENABLE_RPMDB)
 
+IF (ENABLE_RPMPKG)
+ADD_EXECUTABLE (rpms2solv rpms2solv.c)
+TARGET_LINK_LIBRARIES (rpms2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+SET (tools_list ${tools_list} rpms2solv)
+ENDIF (ENABLE_RPMPKG)
+
 IF (ENABLE_RPMMD)
 ADD_EXECUTABLE (repomdxml2solv repomdxml2solv.c)
 TARGET_LINK_LIBRARIES (repomdxml2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
index e8be171..b0fdb33 100644 (file)
@@ -49,6 +49,7 @@ usage(char** argv)
   exit(1);
 }
 
+#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO)
 static int
 strlen_comp(const char *str)
 {
@@ -63,6 +64,7 @@ strlen_comp(const char *str)
     return l - 5;
   return l;
 }
+#endif
 
 int
 main(int argc, char **argv)
@@ -97,7 +99,10 @@ main(int argc, char **argv)
   for (i = 2; i < argc; i++)
     {
       FILE *fp;
-      int r, l;
+      int r;
+#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO)
+      int l;
+#endif
 
       if (!strcmp(argv[i], "--withsrc"))
        {
@@ -126,7 +131,9 @@ main(int argc, char **argv)
           ++i;
           continue;
         }
+#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO)
       l = strlen_comp(argv[i]);
+#endif
       if (!strcmp(argv[i], "-"))
        fp = stdin;
       else if ((fp = solv_xfopen(argv[i], 0)) == 0)