From: DongHun Kwak Date: Fri, 30 Nov 2018 03:38:58 +0000 (+0900) Subject: Imported Upstream version 0.6.24 X-Git-Tag: upstream/0.6.24 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Ftags%2Fupstream%2F0.6.24;p=platform%2Fupstream%2Flibsolv.git Imported Upstream version 0.6.24 Change-Id: I68f4d40b704c1ccd2a86576a3c03687922f023aa Signed-off-by: DongHun Kwak --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 0153a70..82034e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 --- 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 diff --git a/VERSION.cmake b/VERSION.cmake index 10ade66..ffa5bd0 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "0") SET(LIBSOLV_MAJOR "0") SET(LIBSOLV_MINOR "6") -SET(LIBSOLV_PATCH "23") +SET(LIBSOLV_PATCH "24") diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index 34b0784..737cee4 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -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) diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt index 73f2dca..dc6648d 100644 --- a/bindings/python/CMakeLists.txt +++ b/bindings/python/CMakeLists.txt @@ -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 index 0000000..7a2dca3 --- /dev/null +++ b/bindings/python3/CMakeLists.txt @@ -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}) diff --git a/bindings/solv.i b/bindings/solv.i index b21fbbc..64f51d0 100644 --- a/bindings/solv.i +++ b/bindings/solv.i @@ -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; diff --git a/examples/solv/patchjobs.c b/examples/solv/patchjobs.c index 64ad607..929a203 100644 --- a/examples/solv/patchjobs.c +++ b/examples/solv/patchjobs.c @@ -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++) diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index ec5f20c..586eda8 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -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) diff --git a/ext/libsolvext.ver b/ext/libsolvext.ver index 8774fd4..4896e85 100644 --- a/ext/libsolvext.ver +++ b/ext/libsolvext.ver @@ -66,6 +66,7 @@ SOLV_1.0 { testcase_str2dep; testcase_str2job; testcase_str2repo; + testcase_str2solvid; testcase_read; testcase_resultdiff; testcase_solverresult; diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c index 95756c0..034198c 100644 --- a/ext/repo_rpmdb.c +++ b/ext/repo_rpmdb.c @@ -24,6 +24,8 @@ #include #include +#ifdef ENABLE_RPMDB + #include #include #ifndef RPM5 @@ -39,6 +41,8 @@ # endif #endif +#endif + #include "pool.h" #include "repo.h" #include "hash.h" @@ -162,10 +166,16 @@ # 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; } diff --git a/ext/repo_susetags.c b/ext/repo_susetags.c index be73a7f..83967e0 100644 --- a/ext/repo_susetags.c +++ b/ext/repo_susetags.c @@ -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) diff --git a/ext/testcase.c b/ext/testcase.c index 52c139f..a56c4db 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -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); diff --git a/package/libsolv.changes b/package/libsolv.changes index 7d12812..fd351c3 100644 --- a/package/libsolv.changes +++ b/package/libsolv.changes @@ -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] diff --git a/package/libsolv.spec.in b/package/libsolv.spec.in index c2251ec..0009287 100644 --- a/package/libsolv.spec.in +++ b/package/libsolv.spec.in @@ -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 diff --git a/src/order.c b/src/order.c index d560865..4fe3e08 100644 --- a/src/order.c +++ b/src/order.c @@ -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++) { diff --git a/src/problems.c b/src/problems.c index b57d980..063d47b 100644 --- a/src/problems.c +++ b/src/problems.c @@ -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 */ diff --git a/src/rules.c b/src/rules.c index aa90b5f..67f10d8 100644 --- a/src/rules.c +++ b/src/rules.c @@ -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); diff --git a/src/selection.c b/src/selection.c index 6b89ab0..37c6184 100644 --- a/src/selection.c +++ b/src/selection.c @@ -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 { diff --git a/src/solver.c b/src/solver.c index 5fca20d..efe3342 100644 --- a/src/solver.c +++ b/src/solver.c @@ -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); diff --git a/src/solver.h b/src/solver.h index 758f1eb..be240c9 100644 --- a/src/solver.h +++ b/src/solver.h @@ -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 */ diff --git a/src/solvversion.h.in b/src/solvversion.h.in index 75dc63f..9f59d75 100644 --- a/src/solvversion.h.in +++ b/src/solvversion.h.in @@ -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 index 0000000..a7a46b9 --- /dev/null +++ b/test/testcases/focus/best.t @@ -0,0 +1,23 @@ +repo system 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A2 1 1 noarch +repo available 0 testtags +#>=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 index 0000000..4f49d35 --- /dev/null +++ b/test/testcases/focus/installed.t @@ -0,0 +1,23 @@ +repo system 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A2 1 1 noarch +repo available 0 testtags +#>=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 index 0000000..6e562a3 --- /dev/null +++ b/test/testcases/focus/normal.t @@ -0,0 +1,22 @@ +repo system 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A2 1 1 noarch +repo available 0 testtags +#>=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 diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 16fa097..6b592f7 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -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}) diff --git a/tools/installcheck.c b/tools/installcheck.c index e8be171..b0fdb33 100644 --- a/tools/installcheck.c +++ b/tools/installcheck.c @@ -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)