summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--VERSION.cmake2
-rw-r--r--bindings/solv.i9
-rw-r--r--doc/libsolv-bindings.316
-rw-r--r--doc/libsolv-bindings.txt10
-rw-r--r--doc/libsolv-pool.38
-rw-r--r--doc/libsolv-pool.txt3
-rw-r--r--examples/solv/solv.c101
-rw-r--r--ext/CMakeLists.txt2
-rw-r--r--ext/libsolvext.ver1
-rw-r--r--ext/pool_fileconflicts.c12
-rw-r--r--ext/repo_deb.c6
-rw-r--r--ext/repo_rpmdb.c8
-rw-r--r--ext/repo_rpmmd.c4
-rw-r--r--ext/testcase.c77
-rw-r--r--ext/testcase.h1
-rw-r--r--package/libsolv.changes15
-rw-r--r--src/libsolv.ver2
-rw-r--r--src/policy.c202
-rw-r--r--src/policy.h2
-rw-r--r--src/pool.c47
-rw-r--r--src/pool.h1
-rw-r--r--src/poolarch.c25
-rw-r--r--src/selection.c93
-rw-r--r--src/selection.h2
-rw-r--r--src/solver.c130
-rw-r--r--src/solver.h7
-rw-r--r--test/testcases/favor/recommends.t50
-rw-r--r--test/testcases/favor/requires.t112
-rw-r--r--test/testcases/favor/supplements.t71
-rw-r--r--test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t20
-rw-r--r--tools/deb2solv.c30
32 files changed, 1001 insertions, 76 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fd1426b..f2a6e16 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,10 +57,10 @@ else (DEFINED INCLUDE)
ENDIF (DEFINED INCLUDE)
MESSAGE (STATUS "Header files will be installed in ${INCLUDE_INSTALL_DIR}")
SET (BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin")
-SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/man")
-IF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man" AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man")
- SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/man")
-ENDIF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man" AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man")
+SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/man")
+IF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man" AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man")
+ SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/man")
+ENDIF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man" AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man")
MESSAGE(STATUS "Man pages will be installed in ${MAN_INSTALL_DIR}")
####################################################################
diff --git a/VERSION.cmake b/VERSION.cmake
index 1b3fd7d..f0d0476 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 "20")
+SET(LIBSOLV_PATCH "21")
diff --git a/bindings/solv.i b/bindings/solv.i
index 4c098b3..b21fbbc 100644
--- a/bindings/solv.i
+++ b/bindings/solv.i
@@ -1172,6 +1172,8 @@ typedef struct {
static const Id SOLVER_DROP_ORPHANED = SOLVER_DROP_ORPHANED;
static const Id SOLVER_USERINSTALLED = SOLVER_USERINSTALLED;
static const Id SOLVER_ALLOWUNINSTALL = SOLVER_ALLOWUNINSTALL;
+ static const Id SOLVER_FAVOR = SOLVER_FAVOR;
+ static const Id SOLVER_DISFAVOR = SOLVER_DISFAVOR;
static const Id SOLVER_JOBMASK = SOLVER_JOBMASK;
static const Id SOLVER_WEAK = SOLVER_WEAK;
static const Id SOLVER_ESSENTIAL = SOLVER_ESSENTIAL;
@@ -1468,11 +1470,18 @@ typedef struct {
static const int POOL_FLAG_NOINSTALLEDOBSOLETES = POOL_FLAG_NOINSTALLEDOBSOLETES;
static const int POOL_FLAG_HAVEDISTEPOCH = POOL_FLAG_HAVEDISTEPOCH;
static const int POOL_FLAG_NOOBSOLETESMULTIVERSION = POOL_FLAG_NOOBSOLETESMULTIVERSION;
+ static const int DISTTYPE_RPM = DISTTYPE_RPM;
+ static const int DISTTYPE_DEB = DISTTYPE_DEB;
+ static const int DISTTYPE_ARCH = DISTTYPE_ARCH;
+ static const int DISTTYPE_HAIKU = DISTTYPE_HAIKU;
Pool() {
Pool *pool = pool_create();
return pool;
}
+ int setdisttype(int disttype) {
+ return pool_setdisttype($self, disttype);
+ }
void set_debuglevel(int level) {
pool_setdebuglevel($self, level);
}
diff --git a/doc/libsolv-bindings.3 b/doc/libsolv-bindings.3
index 14bf96c..6b57ebf 100644
--- a/doc/libsolv-bindings.3
+++ b/doc/libsolv-bindings.3
@@ -1,13 +1,13 @@
'\" t
.\" Title: Libsolv-Bindings
.\" Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\" Date: 12/14/2015
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\" Date: 05/03/2016
.\" Manual: LIBSOLV
.\" Source: libsolv
.\" Language: English
.\"
-.TH "LIBSOLV\-BINDINGS" "3" "12/14/2015" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-BINDINGS" "3" "05/03/2016" "libsolv" "LIBSOLV"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -3256,6 +3256,16 @@ The matching installed packages are considered to be installed by a user, thus n
Allow the solver to deinstall the matching installed packages if they get into the way of resolving a dependency\&. This is like the SOLVER_FLAG_ALLOW_UNINSTALL flag, but limited to a specific set of packages\&.
.RE
.PP
+\fBSOLVER_FAVOR\fR
+.RS 4
+Prefer the specified packages if the solver encounters an alternative\&. If a job contains multiple matching favor/disfavor elements, the last one takes precedence\&.
+.RE
+.PP
+\fBSOLVER_DISFAVOR\fR
+.RS 4
+Avoid the specified packages if the solver encounters an alternative\&. This can also be used to block recommended or supplemented packages from being installed\&.
+.RE
+.PP
\fBSOLVER_JOBMASK\fR
.RS 4
A mask containing all the above action bits\&.
diff --git a/doc/libsolv-bindings.txt b/doc/libsolv-bindings.txt
index 1ee699d..79f4c2c 100644
--- a/doc/libsolv-bindings.txt
+++ b/doc/libsolv-bindings.txt
@@ -1878,6 +1878,16 @@ Allow the solver to deinstall the matching installed packages if they get
into the way of resolving a dependency. This is like the
SOLVER_FLAG_ALLOW_UNINSTALL flag, but limited to a specific set of packages.
+*SOLVER_FAVOR*::
+Prefer the specified packages if the solver encounters an alternative. If
+a job contains multiple matching favor/disfavor elements, the last one takes
+precedence.
+
+*SOLVER_DISFAVOR*::
+Avoid the specified packages if the solver encounters an alternative. This
+can also be used to block recommended or supplemented packages from being
+installed.
+
*SOLVER_JOBMASK*::
A mask containing all the above action bits.
diff --git a/doc/libsolv-pool.3 b/doc/libsolv-pool.3
index 0929ba6..adc13e3 100644
--- a/doc/libsolv-pool.3
+++ b/doc/libsolv-pool.3
@@ -1,13 +1,13 @@
'\" t
.\" Title: Libsolv-Pool
.\" Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\" Date: 12/14/2015
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\" Date: 05/06/2016
.\" Manual: LIBSOLV
.\" Source: libsolv
.\" Language: English
.\"
-.TH "LIBSOLV\-POOL" "3" "12/14/2015" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-POOL" "3" "05/06/2016" "libsolv" "LIBSOLV"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -369,7 +369,7 @@ Make the addfileprovides method only add files from the standard locations (i\&.
.RE
.\}
.sp
-Set the package type of your system\&. The disttype is used for example to define package comparison semantics\&. Libsolv\(cqs default disttype should match the package manager of your system, so you only need to use this function if you want to use the library to solve packaging problems for different systems\&. The Function returns the old disttype on success, and \-1 if the new disttype is not supported\&.
+Set the package type of your system\&. The disttype is used for example to define package comparison semantics\&. Libsolv\(cqs default disttype should match the package manager of your system, so you only need to use this function if you want to use the library to solve packaging problems for different systems\&. The Function returns the old disttype on success, and \-1 if the new disttype is not supported\&. Note that any pool_setarch and pool_setarchpolicy calls need to come after the pool_setdisttype call, as they make use of the noarch/any/all architecture id\&.
.sp
.if n \{\
.RS 4
diff --git a/doc/libsolv-pool.txt b/doc/libsolv-pool.txt
index 8ee0c18..69291a4 100644
--- a/doc/libsolv-pool.txt
+++ b/doc/libsolv-pool.txt
@@ -270,6 +270,9 @@ should match the package manager of your system, so you only need to
use this function if you want to use the library to solve packaging
problems for different systems. The Function returns the old
disttype on success, and -1 if the new disttype is not supported.
+Note that any pool_setarch and pool_setarchpolicy calls need to
+come after the pool_setdisttype call, as they make use of the
+noarch/any/all architecture id.
int pool_set_flag(Pool *pool, int flag, int value);
diff --git a/examples/solv/solv.c b/examples/solv/solv.c
index 6840a6e..e12a686 100644
--- a/examples/solv/solv.c
+++ b/examples/solv/solv.c
@@ -67,7 +67,7 @@ setarch(Pool *pool)
int
-yesno(const char *str)
+yesno(const char *str, int other)
{
char inbuf[128], *ip;
@@ -88,8 +88,8 @@ yesno(const char *str)
printf("Abort.\n");
exit(1);
}
- if (*ip == 'y' || *ip == 'n')
- return *ip == 'y' ? 1 : 0;
+ if (*ip == 'y' || *ip == 'n' || *ip == other)
+ return *ip == 'n' ? 0 : *ip;
}
}
@@ -236,7 +236,9 @@ main(int argc, char **argv)
int forcebest = 0;
char *rootdir = 0;
char *keyname = 0;
+ int keyname_depstr = 0;
int debuglevel = 0;
+ int answer, acnt = 0;
argc--;
argv++;
@@ -323,7 +325,13 @@ main(int argc, char **argv)
argc--;
argv++;
}
- if (argc > 2 && !strcmp(argv[1], "--keyname"))
+ else if (argc > 1 && !strcmp(argv[1], "--depstr"))
+ {
+ keyname_depstr = 1;
+ argc--;
+ argv++;
+ }
+ else if (argc > 2 && !strcmp(argv[1], "--keyname"))
{
keyname = argv[2];
argc -= 2;
@@ -529,7 +537,11 @@ main(int argc, char **argv)
if (!keyname)
rflags = selection_make(pool, &job2, argv[i], flags);
else
- rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
+ {
+ if (keyname_depstr)
+ flags |= SELECTION_MATCH_DEPSTR;
+ rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
+ }
if (repofilter.count)
selection_filter(pool, &job2, &repofilter);
if (archfilter.count)
@@ -661,9 +673,7 @@ main(int argc, char **argv)
queue_push2(&job, SOLVER_ERASE|SOLVER_CLEANDEPS|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1));
#endif
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
rerunsolver:
-#endif
solv = solver_create(pool);
solver_set_flag(solv, SOLVER_FLAG_SPLITPROVIDES, 1);
#ifdef FEDORA
@@ -754,7 +764,80 @@ rerunsolver:
printf("install size change: %d K\n", transaction_calc_installsizechange(trans));
printf("\n");
- if (!yesno("OK to continue (y/n)? "))
+ acnt = solver_alternatives_count(solv);
+ if (acnt)
+ {
+ printf("Have %d alternatives\n\n", acnt);
+ answer = yesno("OK to continue (y/n/a)? ", 'a');
+ }
+ else
+ answer = yesno("OK to continue (y/n)? ", 0);
+ if (answer == 'a')
+ {
+ Queue choicesq;
+ Queue answerq;
+ Id id, from, chosen;
+ int j;
+
+ queue_init(&choicesq);
+ queue_init(&answerq);
+ for (i = 1; i <= acnt; i++)
+ {
+ int atype = solver_get_alternative(solv, i, &id, &from, &chosen, &choicesq, 0);
+ printf("\n%s\n", solver_alternative2str(solv, atype, id, from));
+ for (j = 0; j < choicesq.count; j++)
+ {
+ Id p = choicesq.elements[j];
+ if (p < 0)
+ p = -p;
+ queue_push(&answerq, p);
+ printf("%6d: %s\n", answerq.count, pool_solvid2str(pool, p));
+ }
+ }
+ queue_free(&choicesq);
+ printf("\n");
+ for (;;)
+ {
+ char inbuf[128], *ip;
+ int neg = 0;
+ printf("OK to continue (y/n), or number to change alternative: ");
+ fflush(stdout);
+ *inbuf = 0;
+ if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
+ {
+ printf("Abort.\n");
+ exit(1);
+ }
+ while (*ip == ' ' || *ip == '\t')
+ ip++;
+ if (*ip == '-' && ip[1] >= '0' && ip[1] <= '9')
+ {
+ neg = 1;
+ ip++;
+ }
+ if (*ip >= '0' && *ip <= '9')
+ {
+ int take = atoi(ip);
+ if (take > 0 && take <= answerq.count)
+ {
+ Id p = answerq.elements[take - 1];
+ queue_free(&answerq);
+ queue_push2(&job, (neg ? SOLVER_DISFAVOR : SOLVER_FAVOR) | SOLVER_SOLVABLE_NAME, pool->solvables[p].name);
+ solver_free(solv);
+ solv = 0;
+ goto rerunsolver;
+ break;
+ }
+ }
+ if (*ip == 'n' || *ip == 'y')
+ {
+ answer = *ip == 'n' ? 0 : *ip;
+ break;
+ }
+ }
+ queue_free(&answerq);
+ }
+ if (!answer)
{
printf("Abort.\n");
transaction_free(trans);
@@ -843,7 +926,7 @@ rerunsolver:
queue_init(&conflicts);
if (checkfileconflicts(pool, &checkq, newpkgs, newpkgsfps, &conflicts))
{
- if (yesno("Re-run solver (y/n/q)? "))
+ if (yesno("Re-run solver (y/n/q)? ", 0))
{
for (i = 0; i < newpkgs; i++)
if (newpkgsfps[i])
diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt
index ad52495..ec5f20c 100644
--- a/ext/CMakeLists.txt
+++ b/ext/CMakeLists.txt
@@ -48,6 +48,8 @@ IF (ENABLE_COMPLEX_DEPS)
IF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB)
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_COMPLEX_DEPS)
diff --git a/ext/libsolvext.ver b/ext/libsolvext.ver
index 654469b..8774fd4 100644
--- a/ext/libsolvext.ver
+++ b/ext/libsolvext.ver
@@ -2,6 +2,7 @@ SOLV_1.0 {
global:
pool_deb_get_autoinstalled;
pool_findfileconflicts;
+ pool_parserpmrichdep;
repo_add_appdata;
repo_add_appdata_dir;
repo_add_arch_local;
diff --git a/ext/pool_fileconflicts.c b/ext/pool_fileconflicts.c
index 4238d2d..6c9119f 100644
--- a/ext/pool_fileconflicts.c
+++ b/ext/pool_fileconflicts.c
@@ -640,7 +640,7 @@ findfileconflicts2_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
strncpy(md5padded, info->digest, 32);
md5padded[32] = 0;
md5padded[33] = info->color;
- /* printf("%d, hx %x -> %s %d %s\n", cbdata->idx, hx, fn, info->mode, info->digest); */
+ /* printf("%d, hx %x -> %s %d %s %d\n", cbdata->idx, hx, fn, info->mode, info->digest, info->color); */
off = addfilesspace(cbdata, strlen(fn) + (34 + 1));
memcpy(cbdata->filesspace + off, (unsigned char *)md5padded, 34);
strcpy((char *)cbdata->filesspace + off + 34, fn);
@@ -805,7 +805,7 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
void *handle;
Repo *installed = pool->installed;
Id p;
- int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS);
+ int usefilecolors;
int hdrfetches;
queue_empty(conflicts);
@@ -813,8 +813,10 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
return 0;
now = start = solv_timems(0);
+ /* Hmm, should we have a different flag for this? */
+ usefilecolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS);
POOL_DEBUG(SOLV_DEBUG_STATS, "searching for file conflicts\n");
- POOL_DEBUG(SOLV_DEBUG_STATS, "packages: %d, cutoff %d\n", pkgs->count, cutoff);
+ POOL_DEBUG(SOLV_DEBUG_STATS, "packages: %d, cutoff %d, usefilecolors %d\n", pkgs->count, cutoff, usefilecolors);
memset(&cbdata, 0, sizeof(cbdata));
cbdata.aliases = flags & FINDFILECONFLICTS_CHECK_DIRALIASING;
@@ -1026,7 +1028,7 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
{
Id idx = cbdata.lookat.elements[i + 1];
int iterflags = RPM_ITERATE_FILELIST_WITHMD5 | RPM_ITERATE_FILELIST_NOGHOSTS;
- if (obsoleteusescolors)
+ if (usefilecolors)
iterflags |= RPM_ITERATE_FILELIST_WITHCOL;
p = pkgs->elements[idx];
handle = (*handle_cb)(pool, p, handle_cbdata);
@@ -1098,7 +1100,7 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
}
if (!strcmp(fsi, fsj))
continue; /* file digests match, no conflict */
- if (obsoleteusescolors && fsi[33] && fsj[33] && (fsi[33] & fsj[33]) == 0)
+ if (usefilecolors && fsi[33] && fsj[33] && (fsi[33] & fsj[33]) == 0)
continue; /* colors do not conflict */
queue_push(conflicts, pool_str2id(pool, fsi + 34, 1));
queue_push(conflicts, pkgs->elements[pidx]);
diff --git a/ext/repo_deb.c b/ext/repo_deb.c
index 35dcc84..812f3d9 100644
--- a/ext/repo_deb.c
+++ b/ext/repo_deb.c
@@ -388,12 +388,10 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags)
if (!(p = strchr(p, '\n')))
{
int l3;
- if (l + 1024 >= bufl)
+ while (l + 1024 >= bufl)
{
buf = solv_realloc(buf, bufl + 4096);
bufl += 4096;
- p = buf + l;
- continue;
}
p = buf + l;
ll = fread(p, 1, bufl - l - 1, fp);
@@ -403,6 +401,8 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags)
while ((l3 = strlen(p)) < ll)
p[l3] = '\n';
l += ll;
+ if (p != buf)
+ p--;
continue;
}
p++;
diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c
index 308cfe5..92aef31 100644
--- a/ext/repo_rpmdb.c
+++ b/ext/repo_rpmdb.c
@@ -54,7 +54,8 @@
/* 3: added triggers */
/* 4: fixed triggers */
/* 5: fixed checksum copying */
-#define RPMDB_COOKIE_VERSION 5
+/* 6: add SOLVABLE_PREREQ_IGNOREINST support */
+#define RPMDB_COOKIE_VERSION 6
#define TAG_NAME 1000
#define TAG_VERSION 1001
@@ -2434,7 +2435,7 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *
if ((flags & RPM_ITERATE_FILELIST_WITHCOL) != 0)
{
co = headint32array(rpmhead, TAG_FILECOLORS, &cnt2);
- if (!co || cnt != cnt2)
+ if (co && cnt != cnt2)
{
solv_free(co);
solv_free(md);
@@ -2512,8 +2513,7 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *
info.digest = md5;
}
}
- if (co)
- info.color = co[i];
+ info.color = co ? co[i] : 0;
(*cb)(cbdata, space, &info);
}
solv_free(space);
diff --git a/ext/repo_rpmmd.c b/ext/repo_rpmmd.c
index 78264cc..729f4f7 100644
--- a/ext/repo_rpmmd.c
+++ b/ext/repo_rpmmd.c
@@ -651,13 +651,13 @@ put_in_cshash(struct parsedata *pd, const unsigned char *key, int keyl, Id id)
while (ht[h])
{
unsigned char *d = pd->csdata + ht[h];
- if (d[-1] == keyl && !memcmp(key, d, keyl))
+ if (d[-1] == keyl - 1 && !memcmp(key, d, keyl))
return; /* XXX: first id wins... */
h = HASHCHAIN_NEXT(h, hh, hm);
}
}
/* a new entry. put in csdata */
- pd->csdata = solv_extend(pd->csdata, pd->ncsdata, 1, 1 + keyl + sizeof(Id), 4095);
+ pd->csdata = solv_extend(pd->csdata, pd->ncsdata, 1 + keyl + sizeof(Id), 1, 4095);
d = pd->csdata + pd->ncsdata;
d[0] = keyl - 1;
memcpy(d + 1, key, keyl);
diff --git a/ext/testcase.c b/ext/testcase.c
index 536875c..6e2b574 100644
--- a/ext/testcase.c
+++ b/ext/testcase.c
@@ -46,6 +46,8 @@ static struct job2str {
{ SOLVER_DROP_ORPHANED, "droporphaned" },
{ SOLVER_USERINSTALLED, "userinstalled" },
{ SOLVER_ALLOWUNINSTALL, "allowuninstall" },
+ { SOLVER_FAVOR, "favor" },
+ { SOLVER_DISFAVOR, "disfavor" },
{ 0, 0 }
};
@@ -81,6 +83,7 @@ static struct resultflags2str {
{ TESTCASE_RESULT_ALTERNATIVES, "alternatives" },
{ TESTCASE_RESULT_RULES, "rules" },
{ TESTCASE_RESULT_GENID, "genid" },
+ { TESTCASE_RESULT_REASON, "reason" },
{ 0, 0 }
};
@@ -111,6 +114,7 @@ static struct solverflags2str {
{ SOLVER_FLAG_FOCUS_INSTALLED, "focusinstalled", 0 },
{ SOLVER_FLAG_YUM_OBSOLETES, "yumobsoletes", 0 },
{ SOLVER_FLAG_NEED_UPDATEPROVIDE, "needupdateprovide", 0 },
+ { SOLVER_FLAG_URPM_REORDER, "urpmreorder", 0 },
{ 0, 0, 0 }
};
@@ -1553,7 +1557,11 @@ testcase_setsolverflags(Solver *solv, const char *str)
pool_debug(solv->pool, SOLV_ERROR, "setsolverflags: unknown flag '%.*s'\n", (int)(p - s), s);
return 0;
}
- solver_set_flag(solv, solverflags2str[i].flag, v);
+ if (solver_set_flag(solv, solverflags2str[i].flag, v) == -1)
+ {
+ pool_debug(solv->pool, SOLV_ERROR, "setsolverflags: unsupported flag '%s'\n", solverflags2str[i].str);
+ return 0;
+ }
}
return 1;
}
@@ -1700,6 +1708,35 @@ static struct class2str {
{ 0, 0 }
};
+static struct reason2str {
+ Id reason;
+ const char *str;
+} reason2str[] = {
+ { SOLVER_REASON_UNRELATED, "unrelated" },
+ { SOLVER_REASON_UNIT_RULE, "unit" },
+ { SOLVER_REASON_KEEP_INSTALLED, "keep" },
+ { SOLVER_REASON_RESOLVE_JOB, "job" },
+ { SOLVER_REASON_UPDATE_INSTALLED, "update" },
+ { SOLVER_REASON_CLEANDEPS_ERASE, "cleandeps" },
+ { SOLVER_REASON_RESOLVE, "resolve" },
+ { SOLVER_REASON_WEAKDEP, "weakdep" },
+ { SOLVER_REASON_RESOLVE_ORPHAN, "orphan" },
+
+ { SOLVER_REASON_RECOMMENDED, "recommended" },
+ { SOLVER_REASON_SUPPLEMENTED, "supplemented" },
+ { 0, 0 }
+};
+
+static const char *
+testcase_reason2str(Id reason)
+{
+ int i;
+ for (i = 0; reason2str[i].str; i++)
+ if (reason == reason2str[i].reason)
+ return reason2str[i].str;
+ return "?";
+}
+
static int
dump_genid(Pool *pool, Strqueue *sq, Id id, int cnt)
{
@@ -2017,6 +2054,44 @@ testcase_solverresult(Solver *solv, int resultflags)
dump_genid(pool, &sq, id, 1);
}
}
+ if ((resultflags & TESTCASE_RESULT_REASON) != 0)
+ {
+ Queue whyq;
+ queue_init(&whyq);
+ FOR_POOL_SOLVABLES(p)
+ {
+ Id info, p2, id;
+ int reason = solver_describe_decision(solv, p, &info);
+ if (reason == SOLVER_REASON_UNRELATED)
+ continue;
+ if (reason == SOLVER_REASON_WEAKDEP)
+ {
+ solver_describe_weakdep_decision(solv, p, &whyq);
+ if (whyq.count)
+ {
+ for (i = 0; i < whyq.count; i += 3)
+ {
+ reason = whyq.elements[i];
+ p2 = whyq.elements[i + 1];
+ id = whyq.elements[i + 2];
+ s = pool_tmpjoin(pool, "reason ", testcase_solvid2str(pool, p), 0);
+ s = pool_tmpappend(pool, s, " ", testcase_reason2str(reason));
+ s = pool_tmpappend(pool, s, " ", testcase_dep2str(pool, id));
+ if (p2)
+ s = pool_tmpappend(pool, s, " ", testcase_solvid2str(pool, p2));
+ strqueue_push(&sq, s);
+ }
+ continue;
+ }
+ }
+ s = pool_tmpjoin(pool, "reason ", testcase_solvid2str(pool, p), 0);
+ s = pool_tmpappend(pool, s, " ", testcase_reason2str(reason));
+ if (info)
+ s = pool_tmpappend(pool, s, " ", testcase_ruleid(solv, info));
+ strqueue_push(&sq, s);
+ }
+ queue_free(&whyq);
+ }
strqueue_sort(&sq);
result = strqueue_join(&sq);
strqueue_free(&sq);
diff --git a/ext/testcase.h b/ext/testcase.h
index 4903e6c..d3ad505 100644
--- a/ext/testcase.h
+++ b/ext/testcase.h
@@ -17,6 +17,7 @@
#define TESTCASE_RESULT_ALTERNATIVES (1 << 5)
#define TESTCASE_RESULT_RULES (1 << 6)
#define TESTCASE_RESULT_GENID (1 << 7)
+#define TESTCASE_RESULT_REASON (1 << 8)
extern Id testcase_str2dep(Pool *pool, const char *s);
extern const char *testcase_dep2str(Pool *pool, Id id);
diff --git a/package/libsolv.changes b/package/libsolv.changes
index 9575327..b6c04a7 100644
--- a/package/libsolv.changes
+++ b/package/libsolv.changes
@@ -1,4 +1,19 @@
-------------------------------------------------------------------
+Wed May 18 15:09:56 CEST 2016 - mls@suse.de
+
+- add pool->setdisttype to the bindings
+- fix error in repo_deb that could lead to missing packages
+- add reason testing to testcase code
+- add pool_whatcontainsdep, selection_make_matchdepid, and
+ SELECTION_MATCH_DEPSTR
+- add SOLVER_FAVOR and SOLVER_DISFAVOR job types
+- allow unknown archs in pool_setarch
+- add the SOLVER_FLAG_URPM_REORDER solver flag
+- fix segfault in cshash dedup code
+- fix supplements handling when implicitobsoleteusescolors is set
+- bump version to 0.6.21
+
+-------------------------------------------------------------------
Fri Apr 8 15:36:21 CEST 2016 - mls@suse.de
- Better support of complex deps in pool_match_dep and
diff --git a/src/libsolv.ver b/src/libsolv.ver
index cc79704..a5efd6a 100644
--- a/src/libsolv.ver
+++ b/src/libsolv.ver
@@ -120,6 +120,7 @@ SOLV_1.0 {
pool_trivial_installable_multiversionmap;
pool_vendor2mask;
pool_whatmatchesdep;
+ pool_whatcontainsdep;
queue_alloc_one;
queue_alloc_one_head;
queue_delete;
@@ -245,6 +246,7 @@ SOLV_1.0 {
selection_add;
selection_filter;
selection_make;
+ selection_make_matchdepid;
selection_make_matchdeps;
selection_solvables;
solv_bin2hex;
diff --git a/src/policy.c b/src/policy.c
index 12ad771..3a0a737 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -453,6 +453,89 @@ prefer_suggested(Solver *solv, Queue *plist)
}
}
+static int
+sort_by_favorq_cmp(const void *ap, const void *bp, void *dp)
+{
+ const Id *a = ap, *b = bp, *d = dp;
+ return d[b[0]] - d[a[0]];
+}
+
+static void
+sort_by_favorq(Queue *favorq, Id *el, int cnt)
+{
+ int i;
+ /* map to offsets into favorq */
+ for (i = 0; i < cnt; i++)
+ {
+ Id p = el[i];
+ /* lookup p in sorted favorq */
+ int med = 0, low = 0;
+ int high = favorq->count / 2;
+ while (low != high)
+ {
+ med = (low + high) / 2;
+ Id pp = favorq->elements[2 * med];
+ if (pp < p)
+ low = med;
+ else if (pp > p)
+ high = med;
+ else
+ break;
+ }
+ while(med && favorq->elements[2 * med - 2] == p)
+ med--;
+ if (favorq->elements[2 * med] == p)
+ el[i] = 2 * med + 1;
+ else
+ el[i] = 0; /* hmm */
+ }
+ /* sort by position */
+ solv_sort(el, cnt, sizeof(Id), sort_by_favorq_cmp, favorq->elements);
+ /* map back */
+ for (i = 0; i < cnt; i++)
+ if (el[i])
+ el[i] = favorq->elements[el[i] - 1];
+}
+
+/* bring favored packages to front and disfavored packages to back */
+void
+policy_prefer_favored(Solver *solv, Queue *plist)
+{
+ int i, fav, disfav, count;
+ if (!solv->favormap.size)
+ return;
+ for (i = fav = disfav = 0, count = plist->count; i < count; i++)
+ {
+ Id p = plist->elements[i];
+ if (!MAPTST(&solv->favormap, p))
+ continue;
+ if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p))
+ {
+ /* disfavored package. bring to back */
+ if (i < plist->count - 1)
+ {
+ memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id));
+ plist->elements[plist->count - 1] = p;
+ }
+ i--;
+ count--;
+ disfav++;
+ }
+ else
+ {
+ /* favored package. bring to front */
+ if (i > fav)
+ memmove(plist->elements + fav + 1, plist->elements + fav, (i - fav) * sizeof(Id));
+ plist->elements[fav++] = p;
+ }
+ }
+ /* if we have multiple favored/disfavored packages, sort by favorq index */
+ if (fav > 1)
+ sort_by_favorq(solv->favorq, plist->elements, fav);
+ if (disfav > 1)
+ sort_by_favorq(solv->favorq, plist->elements + plist->count - disfav, disfav);
+}
+
/*
* prune to recommended/suggested packages.
* does not prune installed packages (they are also somewhat recommended).
@@ -1112,6 +1195,111 @@ dislike_old_versions(Pool *pool, Queue *plist)
}
}
+
+/* special lang package handling for urpm */
+/* see https://bugs.mageia.org/show_bug.cgi?id=18315 */
+
+static int
+urpm_reorder_cmp(const void *ap, const void *bp, void *dp)
+{
+ return ((Id *)bp)[1] - ((Id *)ap)[1];
+}
+
+static void
+urpm_reorder(Solver *solv, Queue *plist)
+{
+ Pool *pool = solv->pool;
+ int i, count = plist->count;
+ /* add locale score to packages */
+ queue_insertn(plist, count, count, 0);
+ for (i = count - 1; i >= 0; i--)
+ {
+ Solvable *s = pool->solvables + plist->elements[i];
+ int score = 1;
+ const char *sn = pool_id2str(pool, s->name);
+
+ if (!strncmp(sn, "kernel-", 7))
+ {
+ const char *devel = strstr(sn, "-devel-");
+ if (devel && strlen(sn) < 256)
+ {
+ char kn[256];
+ Id p, pp, knid;
+ memcpy(kn, sn, devel - sn);
+ strcpy(kn + (devel - sn), devel + 6);
+ knid = pool_str2id(pool, kn, 0);
+ if (knid)
+ {
+ FOR_PROVIDES(p, pp, knid)
+ if (solv->decisionmap[p] > 0 || (pool->installed && pool->solvables[p].repo == pool->installed))
+ score = 3;
+ }
+ }
+ }
+ else if ((sn = strstr(sn, "-kernel-")) != 0)
+ {
+ sn += 8;
+ if (strlen(sn) < 256 - 8 && *sn >= '0' && *sn <= '9' && sn[1] == '.')
+ {
+ const char *flavor = strchr(sn, '-');
+ if (flavor)
+ {
+ const char *release = strchr(flavor + 1, '-');
+ if (release)
+ {
+ char kn[256];
+ Id p, pp, knid;
+ memcpy(kn, "kernel", 8);
+ memcpy(kn + 6, flavor, release - flavor + 1);
+ memcpy(kn + 6 + (release - flavor) + 1, sn, flavor - sn);
+ strcpy(kn + 6 + (release + 1 - sn), release);
+ knid = pool_str2id(pool, kn, 0);
+ if (knid)
+ {
+ FOR_PROVIDES(p, pp, knid)
+ if (solv->decisionmap[p] > 0 || (pool->installed && pool->solvables[p].repo == pool->installed))
+ score = 3;
+ }
+ }
+ }
+ }
+ }
+ if (score == 1 && s->requires)
+ {
+ Id id, *idp, p, pp;
+ const char *deps;
+ for (idp = s->repo->idarraydata + s->requires; (id = *idp) != 0; idp++)
+ {
+ while (ISRELDEP(id))
+ {
+ Reldep *rd = GETRELDEP(pool, id);
+ id = rd->name;
+ }
+ deps = strstr(pool_id2str(pool, id), "locales-");
+ if (!deps)
+ continue;
+ if (!strncmp(deps + 8, "en", 2))
+ score = 2;
+ else
+ {
+ score = 0;
+ FOR_PROVIDES(p, pp, id)
+ if (solv->decisionmap[p] > 0 || (pool->installed && pool->solvables[p].repo == pool->installed))
+ score = 3;
+ break;
+ }
+ }
+ }
+ plist->elements[i * 2] = plist->elements[i];
+ plist->elements[i * 2 + 1] = score;
+ }
+ solv_sort(plist->elements, count, sizeof(Id) * 2, urpm_reorder_cmp, pool);
+ for (i = 0; i < count; i++)
+ plist->elements[i] = plist->elements[2 * i];
+ queue_truncate(plist, count);
+}
+
+
/*
* POLICY_MODE_CHOOSE: default, do all pruning steps
* POLICY_MODE_RECOMMEND: leave out prune_to_recommended
@@ -1121,6 +1309,17 @@ void
policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
{
Pool *pool = solv->pool;
+ if (mode == POLICY_MODE_SUPPLEMENT)
+ {
+ /* reorder only */
+ dislike_old_versions(pool, plist);
+ sort_by_common_dep(pool, plist);
+ if (solv->urpmreorder)
+ urpm_reorder(solv, plist);
+ prefer_suggested(solv, plist);
+ policy_prefer_favored(solv, plist);
+ return;
+ }
if (plist->count > 1)
{
if (mode != POLICY_MODE_SUGGEST)
@@ -1143,7 +1342,10 @@ policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
#endif
dislike_old_versions(pool, plist);
sort_by_common_dep(pool, plist);
+ if (solv->urpmreorder)
+ urpm_reorder(solv, plist);
prefer_suggested(solv, plist);
+ policy_prefer_favored(solv, plist);
}
}
}
diff --git a/src/policy.h b/src/policy.h
index 73410ee..0c3c7cb 100644
--- a/src/policy.h
+++ b/src/policy.h
@@ -20,6 +20,7 @@ extern "C" {
#define POLICY_MODE_RECOMMEND 1
#define POLICY_MODE_SUGGEST 2
#define POLICY_MODE_CHOOSE_NOREORDER 3 /* internal, do not use */
+#define POLICY_MODE_SUPPLEMENT 4 /* internal, do not use */
#define POLICY_ILLEGAL_DOWNGRADE 1
@@ -39,6 +40,7 @@ extern void policy_create_obsolete_index(Solver *solv);
/* internal, do not use */
extern void prune_to_best_version(Pool *pool, Queue *plist);
+extern void policy_prefer_favored(Solver *solv, Queue *plist);
#ifdef __cplusplus
diff --git a/src/pool.c b/src/pool.c
index ecc3686..c51c62e 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -1331,8 +1331,11 @@ void
pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
{
Id p;
+ Queue qq;
+ int i;
queue_empty(q);
+ queue_init(&qq);
FOR_POOL_SOLVABLES(p)
{
Solvable *s = pool->solvables + p;
@@ -1340,9 +1343,49 @@ pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
continue;
if (s->repo != pool->installed && !pool_installable(pool, s))
continue;
- if (solvable_matchesdep(s, keyname, dep, marker))
- queue_push(q, p);
+ if (qq.count)
+ queue_empty(&qq);
+ solvable_lookup_deparray(s, keyname, &qq, marker);
+ for (i = 0; i < qq.count; i++)
+ if (pool_match_dep(pool, qq.elements[i], dep))
+ {
+ queue_push(q, p);
+ break;
+ }
+ }
+ queue_free(&qq);
+}
+
+/* check if keyname contains dep, return list of matching packages */
+void
+pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
+{
+ Id p;
+ Queue qq;
+ int i;
+
+ queue_empty(q);
+ if (!dep)
+ return;
+ queue_init(&qq);
+ FOR_POOL_SOLVABLES(p)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo->disabled)
+ continue;
+ if (s->repo != pool->installed && !pool_installable(pool, s))
+ continue;
+ if (qq.count)
+ queue_empty(&qq);
+ solvable_lookup_deparray(s, keyname, &qq, marker);
+ for (i = 0; i < qq.count; i++)
+ if (qq.elements[i] == dep)
+ {
+ queue_push(q, p);
+ break;
+ }
}
+ queue_free(&qq);
}
/*************************************************************************/
diff --git a/src/pool.h b/src/pool.h
index b9e2ed6..069594b 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -347,6 +347,7 @@ static inline Id *pool_whatprovides_ptr(Pool *pool, Id d)
}
void pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
+void pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
/* search the pool. the following filters are available:
* p - search just this solvable
diff --git a/src/poolarch.c b/src/poolarch.c
index 788646b..83cbd62 100644
--- a/src/poolarch.c
+++ b/src/poolarch.c
@@ -29,16 +29,10 @@ static const char *archpolicies[] = {
"i686", "i686:i586:i486:i386",
"i586", "i586:i486:i386",
"i486", "i486:i386",
- "i386", "i386",
"s390x", "s390x:s390",
- "s390", "s390",
- "ppc64le", "ppc64le",
"ppc64", "ppc64:ppc",
- "ppc", "ppc",
"ppc64p7", "ppc64p7:ppc64:ppc",
"ia64", "ia64:i686:i586:i486:i386",
- "aarch64", "aarch64",
- "armv6hl", "armv6hl",
"armv7hnl", "armv7hnl:armv7hl:armv6hl",
"armv7hl", "armv7hl:armv6hl",
"armv7l", "armv7l:armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
@@ -49,21 +43,12 @@ static const char *archpolicies[] = {
"armv5l", "armv5l:armv4tl:armv4l:armv3l",
"armv4tl", "armv4tl:armv4l:armv3l",
"armv4l", "armv4l:armv3l",
- "armv3l", "armv3l",
- "sh3", "sh3",
- "sh4", "sh4",
"sh4a", "sh4a:sh4",
"sparc64v", "sparc64v:sparc64:sparcv9v:sparcv9:sparcv8:sparc",
"sparc64", "sparc64:sparcv9:sparcv8:sparc",
"sparcv9v", "sparcv9v:sparcv9:sparcv8:sparc",
"sparcv9", "sparcv9:sparcv8:sparc",
"sparcv8", "sparcv8:sparc",
- "sparc", "sparc",
- "mips", "mips",
- "mipsel", "mipsel",
- "mips64", "mips64",
- "mips64el", "mips64el",
- "m68k", "m68k",
#if defined(FEDORA) || defined(MAGEIA)
"ia32e", "ia32e:x86_64:athlon:i686:i586:i486:i386",
"athlon", "athlon:i686:i586:i486:i386",
@@ -81,15 +66,13 @@ pool_setarch(Pool *pool, const char *arch)
if (arch)
{
int i;
-
/* convert arch to known policy */
for (i = 0; archpolicies[i]; i += 2)
if (!strcmp(archpolicies[i], arch))
- break;
- if (archpolicies[i])
- arch = archpolicies[i + 1];
- else
- arch = "";
+ {
+ arch = archpolicies[i + 1];
+ break;
+ }
}
pool_setarchpolicy(pool, arch);
}
diff --git a/src/selection.c b/src/selection.c
index 7d9a918..6b89ab0 100644
--- a/src/selection.c
+++ b/src/selection.c
@@ -867,6 +867,19 @@ selection_make(Pool *pool, Queue *selection, const char *name, int flags)
return ret;
}
+static inline int
+matchdep_str(const char *pattern, const char *string, int flags)
+{
+ if (flags & SELECTION_GLOB)
+ {
+ int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0;
+ return fnmatch(pattern, string, globflags) == 0 ? 1 : 0;
+ }
+ if (flags & SELECTION_NOCASE)
+ return strcasecmp(pattern, string) == 0 ? 1 : 0;
+ return strcmp(pattern, string) == 0 ? 1 : 0;
+}
+
static int
matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags)
{
@@ -899,14 +912,7 @@ matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags)
}
return 1;
}
- if (flags & SELECTION_GLOB)
- {
- int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0;
- return fnmatch(rname, pool_id2str(pool, id), globflags) == 0 ? 1 : 0;
- }
- if (flags & SELECTION_NOCASE)
- return strcasecmp(rname, pool_id2str(pool, id)) == 0 ? 1 : 0;
- return strcmp(rname, pool_id2str(pool, id)) == 0 ? 1 : 0;
+ return matchdep_str(rname, pool_id2str(pool, id), flags);
}
/*
@@ -917,22 +923,25 @@ matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags)
int
selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
{
- char *rname, *r;
+ char *rname, *r = 0;
int rflags = 0;
Id p;
Queue q;
queue_empty(selection);
rname = solv_strdup(name);
- if ((r = strpbrk(rname, "<=>")) != 0)
+ if (!(flags & SELECTION_MATCH_DEPSTR))
{
- if ((r = splitrel(rname, r, &rflags)) == 0)
+ if ((r = strpbrk(rname, "<=>")) != 0)
{
- solv_free(rname);
- return 0;
+ if ((r = splitrel(rname, r, &rflags)) == 0)
+ {
+ solv_free(rname);
+ return 0;
+ }
}
}
- if ((flags & SELECTION_GLOB) != 0 && !strpbrk(name, "[*?") != 0)
+ if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0)
flags &= ~SELECTION_GLOB;
queue_init(&q);
@@ -957,6 +966,12 @@ selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int fla
for (i = 0; i < q.count; i++)
{
Id id = q.elements[i];
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+ {
+ if (matchdep_str(rname, pool_dep2str(pool, id), flags))
+ break;
+ continue;
+ }
if (matchdep(pool, id, rname, rflags, r, flags))
break;
}
@@ -972,6 +987,56 @@ selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int fla
return SELECTION_PROVIDES;
}
+int
+selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
+{
+ Id p;
+ Queue q;
+
+ queue_empty(selection);
+ if (!dep)
+ return 0;
+ queue_init(&q);
+ FOR_POOL_SOLVABLES(p)
+ {
+ Solvable *s = pool->solvables + p;
+ int i;
+
+ if (s->repo != pool->installed && !pool_installable(pool, s))
+ {
+ if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
+ continue;
+ if (pool_disabled_solvable(pool, s))
+ continue;
+ }
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
+ continue;
+ queue_empty(&q);
+ repo_lookup_deparray(s->repo, p, keyname, &q, marker);
+ for (i = 0; i < q.count; i++)
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */
+ {
+ if (q.elements[i] == dep)
+ break;
+ continue;
+ }
+ if (pool_match_dep(pool, q.elements[i], dep))
+ break;
+ }
+ if (i < q.count)
+ queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
+ }
+ queue_free(&q);
+ if (!selection->count)
+ return 0;
+ if ((flags & SELECTION_FLAT) != 0)
+ selection_flatten(pool, selection);
+ return SELECTION_PROVIDES;
+}
+
static inline int
pool_is_kind(Pool *pool, Id name, Id kind)
{
diff --git a/src/selection.h b/src/selection.h
index fc2b15d..0dd6150 100644
--- a/src/selection.h
+++ b/src/selection.h
@@ -33,9 +33,11 @@ extern "C" {
#define SELECTION_SOURCE_ONLY (1 << 12)
#define SELECTION_WITH_SOURCE (1 << 13)
#define SELECTION_SKIP_KIND (1 << 14)
+#define SELECTION_MATCH_DEPSTR (1 << 15)
extern int selection_make(Pool *pool, Queue *selection, const char *name, int flags);
extern int selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker);
+extern int selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker);
extern void selection_filter(Pool *pool, Queue *sel1, Queue *sel2);
extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2);
diff --git a/src/solver.c b/src/solver.c
index d5989cc..4f849ec 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -1432,6 +1432,8 @@ reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq)
solv->recommends_index = -1;
queue_truncate(&solv->decisionq, decisionqcount);
}
+ /* but obey favored maps */
+ policy_prefer_favored(solv, dq);
}
/*-------------------------------------------------------------------
@@ -1701,6 +1703,7 @@ solver_free(Solver *solv)
queuep_free(&solv->recommendscplxq);
queuep_free(&solv->suggestscplxq);
queuep_free(&solv->brokenorphanrules);
+ queuep_free(&solv->favorq);
map_free(&solv->recommendsmap);
map_free(&solv->suggestsmap);
@@ -1716,6 +1719,8 @@ solver_free(Solver *solv)
map_free(&solv->droporphanedmap);
map_free(&solv->cleandepsmap);
map_free(&solv->allowuninstallmap);
+ map_free(&solv->favormap);
+ map_free(&solv->isdisfavormap);
solv_free(solv->decisionmap);
solv_free(solv->rules);
@@ -1779,6 +1784,8 @@ solver_get_flag(Solver *solv, int flag)
return solv->do_yum_obsoletes;
case SOLVER_FLAG_NEED_UPDATEPROVIDE:
return solv->needupdateprovide;
+ case SOLVER_FLAG_URPM_REORDER:
+ return solv->urpmreorder;
default:
break;
}
@@ -1857,6 +1864,9 @@ solver_set_flag(Solver *solv, int flag, int value)
case SOLVER_FLAG_NEED_UPDATEPROVIDE:
solv->needupdateprovide = value;
break;
+ case SOLVER_FLAG_URPM_REORDER:
+ solv->urpmreorder = value;
+ break;
default:
break;
}
@@ -2063,6 +2073,22 @@ do_complex_recommendations(Solver *solv, Id rec, Map *m, int noselected)
#endif
+static void
+prune_disfavored(Solver *solv, Queue *plist)
+{
+ int i, j;
+ if (!solv->isdisfavormap.size)
+ return;
+ for (i = j = 0; i < plist->count; i++)
+ {
+ Id p = plist->elements[i];
+ if (!MAPTST(&solv->isdisfavormap, p))
+ plist->elements[j++] = p;
+ }
+ if (i != j)
+ queue_truncate(plist, j);
+}
+
/*-------------------------------------------------------------------
*
* solver_run_sat
@@ -2522,10 +2548,16 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
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)
@@ -2604,6 +2636,26 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
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)
{
@@ -2636,11 +2688,22 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
for (i = 0; i < dq.count; i++)
MAPSET(&dqmap, dq.elements[i]);
- /* install all supplemented packages */
+ /* 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] || !MAPTST(&dqmap, p))
+ if (solv->decisionmap[p])
continue;
POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
olevel = level;
@@ -3327,6 +3390,42 @@ add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak)
}
#endif
+/* sort by package id, last entry wins */
+static int
+setup_favormaps_cmp(const void *ap, const void *bp, void *dp)
+{
+ const Id *a = ap, *b = bp;
+ if ((*a - *b) != 0)
+ return *a - *b;
+ return (b[1] < 0 ? -b[1] : b[1]) - (a[1] < 0 ? -a[1] : a[1]);
+}
+
+static void
+setup_favormaps(Solver *solv)
+{
+ Queue *q = solv->favorq;
+ Pool *pool = solv->pool;
+ int i;
+ Id oldp = 0;
+ if (q->count > 2)
+ solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), setup_favormaps_cmp, solv);
+ map_grow(&solv->favormap, pool->nsolvables);
+ for (i = 0; i < q->count; i += 2)
+ {
+ Id p = q->elements[i];
+ if (p == oldp)
+ continue;
+ oldp = p;
+ MAPSET(&solv->favormap, p);
+ if (q->elements[i + 1] < 0)
+ {
+ if (!solv->isdisfavormap.size)
+ map_grow(&solv->isdisfavormap, pool->nsolvables);
+ MAPSET(&solv->isdisfavormap, p);
+ }
+ }
+}
+
/*
*
* solve job queue
@@ -3400,6 +3499,8 @@ solver_solve(Solver *solv, Queue *job)
map_zerosize(&solv->allowuninstallmap);
map_zerosize(&solv->cleandepsmap);
map_zerosize(&solv->weakrulemap);
+ map_zerosize(&solv->favormap);
+ map_zerosize(&solv->isdisfavormap);
queue_empty(&solv->weakruleq);
solv->watches = solv_free(solv->watches);
queue_empty(&solv->ruletojob);
@@ -3935,6 +4036,21 @@ solver_solve(Solver *solv, Queue *job)
case SOLVER_ALLOWUNINSTALL:
POOL_DEBUG(SOLV_DEBUG_JOB, "job: allowuninstall %s\n", solver_select2str(pool, select, what));
break;
+ case SOLVER_FAVOR:
+ case SOLVER_DISFAVOR:
+ POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s %s\n", (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? "favor" : "disfavor", solver_select2str(pool, select, what));
+ FOR_JOB_SELECT(p, pp, select, what)
+ {
+ int j;
+ if (!solv->favorq)
+ {
+ solv->favorq = solv_calloc(1, sizeof(Queue));
+ queue_init(solv->favorq);
+ }
+ j = solv->favorq->count + 1;
+ queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? j : -j);
+ }
+ break;
default:
POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
break;
@@ -3955,6 +4071,10 @@ solver_solve(Solver *solv, Queue *job)
assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
solv->jobrules_end = solv->nrules;
+ /* transform favorq into two maps */
+ if (solv->favorq)
+ setup_favormaps(solv);
+
/* now create infarch and dup rules */
if (!solv->noinfarchcheck)
{
@@ -5157,6 +5277,12 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
case SOLVER_ALLOWUNINSTALL:
strstart = "allow deinstallation of ";
break;
+ case SOLVER_FAVOR:
+ strstart = "favor ";
+ break;
+ case SOLVER_DISFAVOR:
+ strstart = "disfavor ";
+ break;
default:
strstart = "unknown job ";
break;
diff --git a/src/solver.h b/src/solver.h
index 2ae9c8d..3495fd8 100644
--- a/src/solver.h
+++ b/src/solver.h
@@ -167,6 +167,7 @@ struct _Solver {
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 do_yum_obsoletes; /* true: add special yumobs rules */
+ int urpmreorder; /* true: do special urpm package reordering */
Map dupmap; /* dup these packages*/
int dupmap_all; /* dup all packages */
@@ -199,6 +200,9 @@ struct _Solver {
Map allowuninstallmap; /* ok to uninstall those */
int allowuninstall_all;
+ Queue *favorq;
+ Map favormap; /* favored / disfavored packages */
+ Map isdisfavormap;
#endif /* LIBSOLV_INTERNAL */
};
@@ -229,6 +233,8 @@ typedef struct _Solver Solver;
#define SOLVER_DROP_ORPHANED 0x0900
#define SOLVER_USERINSTALLED 0x0a00
#define SOLVER_ALLOWUNINSTALL 0x0b00
+#define SOLVER_FAVOR 0x0c00
+#define SOLVER_DISFAVOR 0x0d00
#define SOLVER_JOBMASK 0xff00
@@ -302,6 +308,7 @@ typedef struct _Solver Solver;
#define SOLVER_FLAG_FOCUS_INSTALLED 20
#define SOLVER_FLAG_YUM_OBSOLETES 21
#define SOLVER_FLAG_NEED_UPDATEPROVIDE 22
+#define SOLVER_FLAG_URPM_REORDER 23
#define GET_USERINSTALLED_NAMES (1 << 0) /* package names instead of ids */
#define GET_USERINSTALLED_INVERTED (1 << 1) /* autoinstalled */
diff --git a/test/testcases/favor/recommends.t b/test/testcases/favor/recommends.t
new file mode 100644
index 0000000..c802d4a
--- /dev/null
+++ b/test/testcases/favor/recommends.t
@@ -0,0 +1,50 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: A 1 1 noarch
+#>=Rec: X
+#>=Pkg: B 1 1 noarch
+#>=Prv: X
+#>=Pkg: C 1 1 noarch
+#>=Prv: X
+system unset * system
+
+# first favor B
+job install name A
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+# then favor C
+nextjob
+job install name A
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# check disfavor
+nextjob
+job install name A
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+# check disfavor both, this is different from
+# the requires case
+
+nextjob
+job install name A
+job disfavor name B
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
diff --git a/test/testcases/favor/requires.t b/test/testcases/favor/requires.t
new file mode 100644
index 0000000..e96a905
--- /dev/null
+++ b/test/testcases/favor/requires.t
@@ -0,0 +1,112 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: A 1 1 noarch
+#>=Req: X
+#>=Pkg: B 1 1 noarch
+#>=Prv: X
+#>=Pkg: C 1 1 noarch
+#>=Prv: X
+system unset * system
+
+# first favor B
+job install name A
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+# then favor C
+nextjob
+job install name A
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+
+# if both are favored, the last one wins
+nextjob
+job install name A
+job favor name C
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job favor name B
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# now test disfavor
+
+# first disfavor B
+nextjob
+job install name A
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# then disfavor C
+nextjob
+job install name A
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+# then both
+nextjob
+job install name A
+job disfavor name B
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name C
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# then test combination
+nextjob
+job install name A
+job favor name B
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name B
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job favor name C
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name C
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
diff --git a/test/testcases/favor/supplements.t b/test/testcases/favor/supplements.t
new file mode 100644
index 0000000..7f415b0
--- /dev/null
+++ b/test/testcases/favor/supplements.t
@@ -0,0 +1,71 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: A 1 1 noarch
+#>=Pkg: B 1 1 noarch
+#>=Sup: A
+#>=Pkg: C 1 1 noarch
+#>=Sup: A
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Sup: A2
+#>=Pkg: C2 1 1 noarch
+#>=Sup: A2
+#>=Con: B2
+system unset * system
+
+# first favor B
+job install name A
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# then favor C
+nextjob
+job install name A
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# same with A2 where B2 and C2 conflict
+
+nextjob
+job install name A2
+job favor name B2
+result transaction,problems <inline>
+#>install A2-1-1.noarch@test
+#>install B2-1-1.noarch@test
+
+nextjob
+job install name A2
+job favor name C2
+result transaction,problems <inline>
+#>install A2-1-1.noarch@test
+#>install C2-1-1.noarch@test
+
+
+# check disfavor
+nextjob
+job install name A
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name B
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
diff --git a/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t b/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t
new file mode 100644
index 0000000..6de4544
--- /dev/null
+++ b/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t
@@ -0,0 +1,20 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: A 1 1 noarch
+#>=Pkg: B 1 1 x86_64
+#>=Sup: A
+#>=Pkg: B 1 1 i686
+#>=Sup: A
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: B2 1 1 x86_64
+#>=Sup: A2
+#>=Req: XX
+#>=Pkg: B2 1 1 i686
+#>=Sup: A2
+system x86_64 * system
+poolflags implicitobsoleteusescolors
+job install name A
+
+nextjob
+job install name A2
diff --git a/tools/deb2solv.c b/tools/deb2solv.c
index 0d22f24..63b6839 100644
--- a/tools/deb2solv.c
+++ b/tools/deb2solv.c
@@ -58,8 +58,9 @@ main(int argc, char **argv)
FILE *fp;
char buf[4096], *p;
const char *basefile = 0;
+ int is_repo = 0;
- while ((c = getopt(argc, argv, "0b:m:")) >= 0)
+ while ((c = getopt(argc, argv, "0b:m:r")) >= 0)
{
switch(c)
{
@@ -69,6 +70,9 @@ main(int argc, char **argv)
case 'm':
manifest = optarg;
break;
+ case 'r':
+ is_repo = 1;
+ break;
case '0':
manifest0 = 1;
break;
@@ -113,8 +117,32 @@ main(int argc, char **argv)
repo = repo_create(pool, "deb2solv");
repo_add_repodata(repo, 0);
res = 0;
+ if (!ndebs && !manifest && is_repo)
+ {
+ if (repo_add_debpackages(repo, stdin, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE))
+ {
+ fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool));
+ res = 1;
+ }
+ }
for (i = 0; i < ndebs; i++)
{
+ if (is_repo)
+ {
+ if ((fp = fopen(debs[i], "r")) == 0)
+ {
+ perror(debs[i]);
+ res = 1;
+ continue;
+ }
+ if (repo_add_debpackages(repo, fp, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE))
+ {
+ fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool));
+ res = 1;
+ }
+ fclose(fp);
+ continue;
+ }
if (repo_add_deb(repo, debs[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE) == 0)
{
fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool));