This file contains the major changes between
libsolv versions:
+Version 0.7.3
+- selected bug fixes:
+ * fixed a couple of null pointer derefs and potential memory
+ leaks
+ * made disfavoring recommended packages work if strong recommends
+ is enabled
+ * no longer disable infarch rules when they don't conflict with
+ the job
+- new features:
+ * do favor evaluation before pruning allowing to (dis)favor
+ specific package versions
+
Version 0.7.2
- bug fixes:
* do not autouninstall packages because of forcebest updates
SET(LIBSOLV_MAJOR "0")
SET(LIBSOLV_MINOR "7")
-SET(LIBSOLV_PATCH "2")
+SET(LIBSOLV_PATCH "3")
static const int SOLVER_FLAG_FOCUS_BEST = SOLVER_FLAG_FOCUS_BEST;
static const int SOLVER_FLAG_STRONG_RECOMMENDS = SOLVER_FLAG_STRONG_RECOMMENDS;
static const int SOLVER_FLAG_INSTALL_ALSO_UPDATES = SOLVER_FLAG_INSTALL_ALSO_UPDATES;
+ static const int SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED = SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED;
static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED;
static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE;
socks[i] = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (socks[i] >= 0)
{
- fcntl(socks[i], F_SETFL, O_NONBLOCK);
+ if (fcntl(socks[i], F_SETFL, O_NONBLOCK) == -1)
+ {
+ close(socks[i]);
+ socks[i] = -1;
+ }
if (connect(socks[i], result->ai_addr, result->ai_addrlen) == -1)
{
if (errno != EINPROGRESS)
if (!info->dirlen)
return;
- dp = fn + info->dirlen;
if (info->diridx != cbdata->lastdiridx)
{
cbdata->lastdiridx = info->diridx;
{
struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
- Solvable *s = pd->solvable;
+ Solvable *s;
const char *type;
/* ignore all language tags */
if (repo == pool->installed)
flags |= ADD_NO_AUTOPRODUCTS; /* no auto products for installed repos */
- pattern_id = pool_str2id(pool, "pattern()", 9);
- product_id = pool_str2id(pool, "product()", 9);
+ pattern_id = pool_str2id(pool, "pattern()", 1);
+ product_id = pool_str2id(pool, "product()", 1);
queue_init(&categorykeys);
FOR_REPO_SOLVABLES(repo, p, s)
{
struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
- Solvable *s = pd->solvable;
+ Solvable *s;
switch(state)
{
while (value)
{
char *p = strchr(value, ',');
- if (*p)
+ if (p)
*p++ = 0;
if (*value)
repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_UPDATES, value);
if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
{
pool_error(pool, -1, "%s: not a rpm", rpm);
+ solv_chksum_free(leadsigchksumh, 0);
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
if (lead[78] != 0 || lead[79] != 5)
{
pool_error(pool, -1, "%s: not a rpm v5 header", rpm);
+ solv_chksum_free(leadsigchksumh, 0);
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
if (getu32(lead + 96) != 0x8eade801)
{
pool_error(pool, -1, "%s: bad signature header", rpm);
+ solv_chksum_free(leadsigchksumh, 0);
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
{
pool_error(pool, -1, "%s: bad signature header", rpm);
+ solv_chksum_free(leadsigchksumh, 0);
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
{
if (!headfromfp(&state, rpm, fp, lead + 96, sigcnt, sigdsize, sigpad, chksumh, leadsigchksumh))
{
+ solv_chksum_free(leadsigchksumh, 0);
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
if (fread(lead, l, 1, fp) != 1)
{
pool_error(pool, -1, "%s: unexpected EOF", rpm);
+ solv_chksum_free(leadsigchksumh, 0);
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
if (fread(lead, 16, 1, fp) != 1)
{
pool_error(pool, -1, "%s: unexpected EOF", rpm);
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
if (getu32(lead) != 0x8eade801)
{
pool_error(pool, -1, "%s: bad header", rpm);
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
{
pool_error(pool, -1, "%s: bad header", rpm);
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
if (!headfromfp(&state, rpm, fp, lead, sigcnt, sigdsize, 0, chksumh, 0))
{
+ solv_chksum_free(chksumh, 0);
fclose(fp);
return 0;
}
#endif
if ((p = getuint(p, zck->hdr_end, &zck->flags)) == 0)
return open_error(zck);
- if ((zck->flags & ~(1)) != 0)
+ if ((zck->flags & ~(3)) != 0)
return open_error(zck);
if ((p = getuint(p, zck->hdr_end, &zck->comp)) == 0 || (zck->comp != 0 && zck->comp != 2))
return open_error(zck); /* only uncompressed + zstd supported */
+ /* skip all optional elements if present */
+ if ((zck->flags & 2) != 0)
+ {
+ unsigned int nopt, lopt;
+ if ((p = getuint(p, zck->hdr_end, &nopt)) == 0)
+ return open_error(zck);
+ for (; nopt != 0; nopt--)
+ {
+ if ((p = getuint(p, zck->hdr_end, &lopt)) == 0)
+ return open_error(zck);
+ if ((p = getuint(p, zck->hdr_end, &lopt)) == 0)
+ return open_error(zck);
+ if (p + lopt > zck->hdr_end)
+ return open_error(zck);
+ p += lopt;
+ }
+ }
+
preface_size = p - (zck->hdr + lead_size);
/* parse index: index size, index chksum type, num chunks, chunk data */
Id flags, id, id2, namespaceid = 0;
struct oplist *op;
+ if (!s)
+ return 0;
while (*s == ' ' || *s == '\t')
s++;
if (!strncmp(s, "namespace:", 10))
return jobflags;
}
+static Id
+testcase_str2jobsel(Pool *pool, const char *caller, char **pieces, int npieces, Id *whatp)
+{
+ Id job, what;
+ if (!strcmp(pieces[0], "pkg") && npieces == 2)
+ {
+ job = SOLVER_SOLVABLE;
+ what = testcase_str2solvid(pool, pieces[1]);
+ if (!what)
+ return pool_error(pool, -1, "%s: unknown package '%s'", caller, pieces[1]);
+ }
+ else if (!strcmp(pieces[0], "name") || !strcmp(pieces[0], "provides"))
+ {
+ /* join em again for dep2str... */
+ char *sp;
+ for (sp = pieces[1]; sp < pieces[npieces - 1]; sp++)
+ if (*sp == 0)
+ *sp = ' ';
+ what = 0;
+ if (pieces[0][0] == 'p' && strncmp(pieces[1], "namespace:", 10) == 0)
+ {
+ char *spe = strchr(pieces[1], '(');
+ int l = strlen(pieces[1]);
+ if (spe && pieces[1][l - 1] == ')')
+ {
+ /* special namespace provides */
+ if (strcmp(spe, "(<NULL>)") != 0)
+ {
+ pieces[1][l - 1] = 0;
+ what = testcase_str2dep(pool, spe + 1);
+ pieces[1][l - 1] = ')';
+ }
+ what = pool_rel2id(pool, pool_strn2id(pool, pieces[1], spe - pieces[1], 1), what, REL_NAMESPACE, 1);
+ }
+ }
+ if (!what)
+ what = testcase_str2dep(pool, pieces[1]);
+ if (pieces[0][0] == 'n')
+ job = SOLVER_SOLVABLE_NAME;
+ else
+ job = SOLVER_SOLVABLE_PROVIDES;
+ }
+ else if (!strcmp(pieces[0], "oneof"))
+ {
+ Queue q;
+ job = SOLVER_SOLVABLE_ONE_OF;
+ queue_init(&q);
+ if (npieces > 1 && strcmp(pieces[1], "nothing") != 0)
+ {
+ int i;
+ for (i = 1; i < npieces; i++)
+ {
+ Id p = testcase_str2solvid(pool, pieces[i]);
+ if (!p)
+ {
+ queue_free(&q);
+ return pool_error(pool, -1, "%s: unknown package '%s'", caller, pieces[i]);
+ }
+ queue_push(&q, p);
+ }
+ }
+ what = pool_queuetowhatprovides(pool, &q);
+ queue_free(&q);
+ }
+ else if (!strcmp(pieces[0], "repo") && npieces == 2)
+ {
+ Repo *repo = testcase_str2repo(pool, pieces[1]);
+ if (!repo)
+ return pool_error(pool, -1, "%s: unknown repo '%s'", caller, pieces[1]);
+ job = SOLVER_SOLVABLE_REPO;
+ what = repo->repoid;
+ }
+ else if (!strcmp(pieces[0], "all") && npieces == 2 && !strcmp(pieces[1], "packages"))
+ {
+ job = SOLVER_SOLVABLE_ALL;
+ what = 0;
+ }
+ else
+ {
+ /* join em again for the error message... */
+ char *sp;
+ for (sp = pieces[0]; sp < pieces[npieces - 1]; sp++)
+ if (*sp == 0)
+ *sp = ' ';
+ return pool_error(pool, -1, "%s: bad line '%s'", caller, pieces[0]);
+ }
+ *whatp = what;
+ return job;
+}
+
Id
testcase_str2job(Pool *pool, const char *str, Id *whatp)
{
int i;
- Id job;
+ Id job, jobsel;
Id what;
char *s;
char **pieces = 0;
job |= str2jobflags(pool, flags);
}
}
- if (!strcmp(pieces[1], "pkg"))
- {
- if (npieces != 3)
- {
- pool_error(pool, -1, "str2job: bad pkg selector in '%s'", str);
- solv_free(pieces);
- return -1;
- }
- job |= SOLVER_SOLVABLE;
- what = testcase_str2solvid(pool, pieces[2]);
- if (!what)
- {
- pool_error(pool, -1, "str2job: unknown package '%s'", pieces[2]);
- solv_free(pieces);
- return -1;
- }
- }
- else if (!strcmp(pieces[1], "name") || !strcmp(pieces[1], "provides"))
- {
- /* join em again for dep2str... */
- char *sp;
- for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++)
- if (*sp == 0)
- *sp = ' ';
- what = 0;
- if (pieces[1][0] == 'p' && strncmp(pieces[2], "namespace:", 10) == 0)
- {
- char *spe = strchr(pieces[2], '(');
- int l = strlen(pieces[2]);
- if (spe && pieces[2][l - 1] == ')')
- {
- /* special namespace provides */
- if (strcmp(spe, "(<NULL>)") != 0)
- {
- pieces[2][l - 1] = 0;
- what = testcase_str2dep(pool, spe + 1);
- pieces[2][l - 1] = ')';
- }
- what = pool_rel2id(pool, pool_strn2id(pool, pieces[2], spe - pieces[2], 1), what, REL_NAMESPACE, 1);
- }
- }
- if (!what)
- what = testcase_str2dep(pool, pieces[2]);
- if (pieces[1][0] == 'n')
- job |= SOLVER_SOLVABLE_NAME;
- else
- job |= SOLVER_SOLVABLE_PROVIDES;
- }
- else if (!strcmp(pieces[1], "oneof"))
- {
- Queue q;
- job |= SOLVER_SOLVABLE_ONE_OF;
- queue_init(&q);
- if (npieces > 2 && strcmp(pieces[2], "nothing") != 0)
- {
- for (i = 2; i < npieces; i++)
- {
- Id p = testcase_str2solvid(pool, pieces[i]);
- if (!p)
- {
- pool_error(pool, -1, "str2job: unknown package '%s'", pieces[i]);
- queue_free(&q);
- solv_free(pieces);
- return -1;
- }
- queue_push(&q, p);
- }
- }
- what = pool_queuetowhatprovides(pool, &q);
- queue_free(&q);
- }
- else if (!strcmp(pieces[1], "repo"))
- {
- Repo *repo;
- if (npieces != 3)
- {
- pool_error(pool, -1, "str2job: bad line '%s'", str);
- solv_free(pieces);
- return -1;
- }
- repo = testcase_str2repo(pool, pieces[2]);
- if (!repo)
- {
- pool_error(pool, -1, "str2job: unknown repo '%s'", pieces[2]);
- solv_free(pieces);
- return -1;
- }
- job |= SOLVER_SOLVABLE_REPO;
- what = repo->repoid;
- }
- else if (!strcmp(pieces[1], "all"))
- {
- if (npieces != 3 && strcmp(pieces[2], "packages") != 0)
- {
- pool_error(pool, -1, "str2job: bad line '%s'", str);
- solv_free(pieces);
- return -1;
- }
- job |= SOLVER_SOLVABLE_ALL;
- what = 0;
- }
- else
- {
- pool_error(pool, -1, "str2job: unknown selection in '%s'", str);
- solv_free(pieces);
- return -1;
- }
- *whatp = what;
+ jobsel = testcase_str2jobsel(pool, "str2job", pieces + 1, npieces - 1, &what);
solv_free(pieces);
- return job;
+ if (jobsel == -1)
+ return -1;
+ *whatp = what;
+ return job | jobsel;
}
#define SELECTIONJOB_MATCHDEPS 1
{ SOLVER_RULE_LEARNT, "learnt" },
{ SOLVER_RULE_BEST, "best" },
{ SOLVER_RULE_YUMOBS, "yumobs" },
+ { SOLVER_RULE_RECOMMENDS, "recommends" },
{ 0, 0 }
};
/* map choice rules back to pkg rules */
if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
id = solver_rule2pkgrule(solv, id);
+ if (solver_ruleclass(solv, id) == SOLVER_RULE_RECOMMENDS)
+ id = solver_rule2pkgrule(solv, id);
solver_allruleinfos(solv, id, &rq);
for (i = 0; i < rq.count; i += 4)
{
Id lowscore;
FILE *fp;
Strqueue sq;
- char *cmd, *out;
+ char *cmd, *out, *result;
const char *s;
if (!testcasename)
if ((resultflags & ~TESTCASE_RESULT_REUSE_SOLVER) != 0)
{
- char *result;
cmd = 0;
for (i = 0; resultflags2str[i].str; i++)
if ((resultflags & resultflags2str[i].flag) != 0)
result = testcase_solverresult(solv, resultflags);
if (!strcmp(resultname, "<inline>"))
{
- int i;
Strqueue rsq;
strqueue_init(&rsq);
strqueue_split(&rsq, result);
if (fclose(fp))
{
pool_error(solv->pool, 0, "testcase_write: write error");
+ solv_free(result);
strqueue_free(&sq);
return 0;
}
solv_free(result);
}
- cmd = strqueue_join(&sq);
+ result = strqueue_join(&sq);
+ strqueue_free(&sq);
out = pool_tmpjoin(pool, dir, "/", testcasename);
if (!(fp = fopen(out, "w")))
{
pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out);
- strqueue_free(&sq);
+ solv_free(result);
return 0;
}
- if (*cmd && fwrite(cmd, strlen(cmd), 1, fp) != 1)
+ if (*result && fwrite(result, strlen(result), 1, fp) != 1)
{
pool_error(solv->pool, 0, "testcase_write: write error");
- strqueue_free(&sq);
+ solv_free(result);
fclose(fp);
return 0;
}
if (fclose(fp))
{
pool_error(solv->pool, 0, "testcase_write: write error");
- strqueue_free(&sq);
+ solv_free(result);
return 0;
}
- solv_free(cmd);
- strqueue_free(&sq);
+ solv_free(result);
return 1;
}
{
int i = strlen(pieces[1]);
s = strchr(pieces[1], '(');
- if (!s && pieces[1][i - 1] != ')')
+ if (!s || pieces[1][i - 1] != ')')
{
pool_error(pool, 0, "testcase_read: bad namespace '%s'", pieces[1]);
}
}
else if (!strcmp(pieces[0], "disable") && npieces == 3)
{
- Id p;
- if (strcmp(pieces[1], "pkg"))
- {
- pool_error(pool, 0, "testcase_read: bad disable type '%s'", pieces[1]);
- continue;
- }
+ Id p, pp, jobsel, what = 0;
if (!prepared)
pool_createwhatprovides(pool);
prepared = -1;
map_init(pool->considered, pool->nsolvables);
map_setall(pool->considered);
}
- p = testcase_str2solvid(pool, pieces[2]);
- if (p)
+ jobsel = testcase_str2jobsel(pool, "disable", pieces + 1, npieces - 1, &what);
+ if (jobsel < 0)
+ continue;
+ if (jobsel == SOLVER_SOLVABLE_ALL)
+ map_empty(pool->considered);
+ else if (jobsel == SOLVER_SOLVABLE_REPO)
+ {
+ Repo *repo = pool_id2repo(pool, what);
+ Solvable *s;
+ FOR_REPO_SOLVABLES(repo, p, s)
+ MAPCLR(pool->considered, p);
+ }
+ FOR_JOB_SELECT(p, pp, jobsel, what)
MAPCLR(pool->considered, p);
- else
- pool_error(pool, 0, "disable: unknown package '%s'", pieces[2]);
}
else if (!strcmp(pieces[0], "feature"))
{
-------------------------------------------------------------------
+Wed Jan 30 15:51:36 CET 2019 - mls@suse.de
+
+- fixed a couple of null pointer derefs
+ [bnc#1120629] [bnc#1120630] [bnc#1120631]
+- do favor evaluation before pruning allowing to (dis)favor
+ specific package versions
+- no longer disable infarch rules when they don't conflict with
+ the job
+- bump version to 0.7.3
+
+-------------------------------------------------------------------
Fri Dec 7 15:10:46 CET 2018 - mls@suse.de
- do not autouninstall packages because of forcebest updates
CMAKE_FLAGS="-DSUSE=1"
%endif
-cmake $CMAKE_FLAGS \
+cmake . $CMAKE_FLAGS \
-DCMAKE_INSTALL_PREFIX=%{_prefix} \
-DLIB=%{_lib} \
-DCMAKE_VERBOSE_MAKEFILE=TRUE \
continue;
if (strncmp(pool_id2str(pool, s->name), "pattern:", 8) != 0)
continue;
- dp = s->repo->idarraydata + s->requires;
for (dp = s->repo->idarraydata + s->requires; *dp; dp++)
FOR_PROVIDES(p, pp, *dp)
if (pool->solvables[p].repo == installed)
if (!r->p || r == fr || cleandeps_rule_is_true(solv, r))
{
/* update rule is true, check best rules */
- if (!solv->bestrules_pkg)
+ if (!solv->bestrules_info)
continue;
nj = solv->bestrules_end - solv->bestrules;
- for (j = 0; j < nj; j++)
- if (solv->bestrules_pkg[j] == i)
+ for (j = solv->bestrules_up - solv->bestrules; j < nj; j++)
+ if (solv->bestrules_info[j] == i)
{
r = solv->rules + solv->bestrules + j;
if (!cleandeps_rule_is_true(solv, r))
return;
dp->dirs = solv_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK);
dirtraverse = solv_calloc_block(dp->ndirs, sizeof(Id), DIR_BLOCK);
- for (parent = 0, i = 0; i < dp->ndirs; i++)
+ for (i = 0; i < dp->ndirs; i++)
{
if (dp->dirs[i] > 0)
continue;
#if 0
printf("do %s [%d]\n", pool_solvid2str(pool, te->p), temedianr[i]);
#endif
- s = pool->solvables + te->p;
for (j = te->edges; od.invedgedata[j]; j++)
{
struct s_TransactionElement *te2 = od.tes + od.invedgedata[j];
}
static int
-sort_by_favorq_cmp(const void *ap, const void *bp, void *dp)
+sort_by_favor_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);
+ if (solv->favormap && plist->count > 1)
+ solv_sort(plist->elements, plist->count, sizeof(Id), sort_by_favor_cmp, solv->favormap);
}
/*
queue_truncate(plist, count);
}
+/* support multiple favor groups by calling policy_filter_unwanted on
+ * each of them and combining the result */
+static void
+policy_filter_unwanted_favored(Solver *solv, Queue *plist, int mode)
+{
+ int i, j, f;
+ Queue qin, qprune;
+ queue_init_clone(&qin, plist);
+ queue_empty(plist);
+ /* sort by favor group */
+ solv_sort(qin.elements, qin.count, sizeof(Id), sort_by_favor_cmp, solv->favormap);
+ /* go over groups */
+ queue_init(&qprune);
+ for (i = 0; i < qin.count; i = j)
+ {
+ /* find end of group */
+ f = solv->favormap[qin.elements[i]];
+ for (j = i + 1; j < qin.count; j++)
+ if (solv->favormap[qin.elements[j]] != f)
+ break;
+ /* prune this group */
+ queue_empty(&qprune);
+ queue_insertn(&qprune, 0, j, qin.elements);
+ policy_filter_unwanted(solv, &qprune, mode | POLICY_MODE_FAVOR_REC);
+ for (i = 0; i < qprune.count; i++)
+ if (solv->favormap[qprune.elements[i]] == f)
+ queue_push(plist, qprune.elements[i]);
+ }
+ queue_free(&qprune);
+ queue_free(&qin);
+}
/*
* POLICY_MODE_CHOOSE: default, do all pruning steps
policy_prefer_favored(solv, plist);
return;
}
+ if (mode & POLICY_MODE_FAVOR_REC)
+ mode ^= POLICY_MODE_FAVOR_REC;
+ else if (solv->favormap && plist->count > 1)
+ {
+ /* check if we have multiple favor groups */
+ int i, f = solv->favormap[plist->elements[0]];
+ for (i = 1; i < plist->count; i++)
+ if (solv->favormap[plist->elements[i]] != f)
+ break;
+ if (i < plist->count)
+ {
+ policy_filter_unwanted_favored(solv, plist, mode);
+ return;
+ }
+ }
if (plist->count > 1)
{
if (mode != POLICY_MODE_SUGGEST)
#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_MODE_FAVOR_REC (1 << 30) /* internal, do not use */
#define POLICY_ILLEGAL_DOWNGRADE 1
vprintf(format, args);
else
vfprintf(stderr, format, args);
+ va_end(args);
return;
}
vsnprintf(buf, sizeof(buf), format, args);
}
v = -(v + 1);
jp = solv->ruletojob.elements;
- if (solv->bestrules_pkg)
+ if (solv->bestrules_info)
{
int ni = solv->bestrules_up - solv->bestrules;
for (i = 0; i < ni; i++)
{
- int j = solv->bestrules_pkg[i];
+ int j = solv->bestrules_info[i];
if (j < 0 && jp[-j - solv->jobrules] == v)
solver_disablerule(solv, solv->rules + solv->bestrules + i);
}
}
v = -(v + 1);
jp = solv->ruletojob.elements;
- if (solv->bestrules_pkg)
+ if (solv->bestrules_info)
{
int ni = solv->bestrules_up - solv->bestrules;
for (i = 0; i < ni; i++)
{
- int j = solv->bestrules_pkg[i];
+ int j = solv->bestrules_info[i];
if (j < 0 && jp[-j - solv->jobrules] == v)
solver_enablerule(solv, solv->rules + solv->bestrules + i);
}
{
if (rid >= solv->jobrules && rid < solv->jobrules_end)
rid = -(solv->ruletojob.elements[rid - solv->jobrules] + 1);
- else if (rid >= solv->bestrules && rid < solv->bestrules_up && solv->bestrules_pkg[rid - solv->bestrules] < 0)
- rid = -(solv->ruletojob.elements[-solv->bestrules_pkg[rid - solv->bestrules] - solv->jobrules] + 1);
+ else if (rid >= solv->bestrules && rid < solv->bestrules_up && solv->bestrules_info[rid - solv->bestrules] < 0)
+ rid = -(solv->ruletojob.elements[-solv->bestrules_info[rid - solv->bestrules] - solv->jobrules] + 1);
else if (rid > solv->infarchrules && rid < solv->infarchrules_end)
{
Pool *pool = solv->pool;
continue;
if (pool->considered && !MAPTST(pool->considered, p))
continue; /* do not uninstalled disabled packages */
- if (solv->bestrules_pkg && solv->bestrules_end > solv->bestrules)
+ if (solv->bestrules_info && solv->bestrules_end > solv->bestrules)
{
int j;
for (j = start + 1; j < solv->problems.count - 1; j++)
{
Id vv = solv->problems.elements[j];
- if (vv >= solv->bestrules && vv < solv->bestrules_end && solv->bestrules_pkg[vv - solv->bestrules] == p)
+ if (vv >= solv->bestrules && vv < solv->bestrules_end && solv->bestrules_info[vv - solv->bestrules] == p)
break;
}
if (j < solv->problems.count - 1)
if (p > 0 && solv->decisionmap[p] > 0)
return; /* false alarm */
/* check update/feature rule */
- p = solv->bestrules_pkg[why - solv->bestrules];
+ p = solv->bestrules_info[why - solv->bestrules];
if (p < 0)
{
/* install job */
litlen -= 32;
}
}
- litofs = 0;
}
return oo;
}
r = solv->rules + solv->featurerules + (p - solv->installed->start);
if (r->p && r->d >= 0)
solver_disablerule(solv, r);
- if (solv->bestrules_pkg)
+ if (solv->bestrules_info)
{
int i, ni;
ni = solv->bestrules_end - solv->bestrules;
for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
- if (solv->bestrules_pkg[i] == p)
+ if (solv->bestrules_info[i] == p)
solver_disablerule(solv, solv->rules + solv->bestrules + i);
}
}
}
}
}
- if (solv->bestrules_pkg)
+ if (solv->bestrules_info)
{
int i, ni;
ni = solv->bestrules_end - solv->bestrules;
for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
- if (solv->bestrules_pkg[i] == p)
+ if (solv->bestrules_info[i] == p)
solver_enablerule(solv, solv->rules + solv->bestrules + i);
}
}
}
if (installed && pool->solvables[p].repo == installed && !haveinstalled)
continue; /* installed package not in lock-step */
+ if (lsq.count < 2)
+ solver_addrule(solv, -p, lsq.count ? lsq.elements[0] : 0, 0);
+ else
+ solver_addrule(solv, -p, 0, pool_queuetowhatprovides(pool, &lsq));
}
- if (lsq.count < 2)
- solver_addrule(solv, -p, lsq.count ? lsq.elements[0] : 0, 0);
else
- solver_addrule(solv, -p, 0, pool_queuetowhatprovides(pool, &lsq));
+ {
+ solver_addrule(solv, -p, 0, 0);
+ }
}
}
queue_free(&lsq);
if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
{
if (select == SOLVER_SOLVABLE)
- queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
+ {
+ for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
+ if (solv->rules[i].p == -what)
+ break;
+ if (i < solv->infarchrules_end)
+ queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
+ }
else
{
int qcnt = q->count;
if (q->elements[i + 1] == s->name)
break;
if (i < q->count)
- continue;
- queue_push2(q, DISABLE_INFARCH, s->name);
+ continue; /* already have that DISABLE_INFARCH element */
+ for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
+ if (solv->rules[i].p == -p)
+ break;
+ if (i < solv->infarchrules_end)
+ queue_push2(q, DISABLE_INFARCH, s->name);
}
}
}
}
if (rid >= solv->bestrules && rid < solv->bestrules_end)
{
- if (fromp && solv->bestrules_pkg[rid - solv->bestrules] > 0)
- *fromp = solv->bestrules_pkg[rid - solv->bestrules];
+ if (fromp && solv->bestrules_info[rid - solv->bestrules] > 0)
+ *fromp = solv->bestrules_info[rid - solv->bestrules];
return SOLVER_RULE_BEST;
}
if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
return SOLVER_RULE_YUMOBS;
}
if (rid >= solv->choicerules && rid < solv->choicerules_end)
- {
- return SOLVER_RULE_CHOICE;
- }
+ return SOLVER_RULE_CHOICE;
+ if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
+ return SOLVER_RULE_RECOMMENDS;
if (rid >= solv->learntrules)
- {
- return SOLVER_RULE_LEARNT;
- }
+ return SOLVER_RULE_LEARNT;
return SOLVER_RULE_UNKNOWN;
}
return SOLVER_RULE_YUMOBS;
if (rid >= solv->choicerules && rid < solv->choicerules_end)
return SOLVER_RULE_CHOICE;
+ if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
+ return SOLVER_RULE_RECOMMENDS;
if (rid >= solv->learntrules && rid < solv->nrules)
return SOLVER_RULE_LEARNT;
return SOLVER_RULE_UNKNOWN;
solver_rule2pkgrule(Solver *solv, Id rid)
{
if (rid >= solv->choicerules && rid < solv->choicerules_end)
- return solv->choicerules_ref[rid - solv->choicerules];
+ return solv->choicerules_info[rid - solv->choicerules];
+ if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
+ return solv->recommendsrules_info[rid - solv->recommendsrules];
return 0;
}
Pool *pool = solv->pool;
Map m, mneg;
Rule *r;
- Queue q, qi, qcheck;
+ Queue q, qi, qcheck, infoq;
int i, j, rid, havechoice;
Id p, d, pp;
Id p2, pp2;
return;
}
now = solv_timems(0);
- solv->choicerules_ref = solv_calloc(solv->pkgrules_end, sizeof(Id));
+ solv->choicerules_info = solv_calloc(solv->pkgrules_end, sizeof(Id));
queue_init(&q);
queue_init(&qi);
queue_init(&qcheck);
+ queue_init(&infoq);
map_init(&m, pool->nsolvables);
map_init(&mneg, pool->nsolvables);
/* set up negative assertion map from infarch and dup rules */
solver_addrule(solv, r->p, 0, d);
queue_push(&solv->weakruleq, solv->nrules - 1);
- solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid;
+ queue_push(&infoq, rid);
#if 0
printf("OLD ");
solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid);
solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + solv->nrules - 1);
#endif
}
+ if (infoq.count)
+ solv->choicerules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id));
queue_free(&q);
queue_free(&qi);
queue_free(&qcheck);
+ queue_free(&infoq);
map_free(&m);
map_free(&mneg);
solv->choicerules_end = solv->nrules;
- /* shrink choicerules_ref */
- solv->choicerules_ref = solv_realloc2(solv->choicerules_ref, solv->choicerules_end - solv->choicerules, sizeof(Id));
POOL_DEBUG(SOLV_DEBUG_STATS, "choice rule creation took %d ms\n", solv_timems(now));
}
-/* called when a choice rule is disabled by analyze_unsolvable. We also
- * have to disable all other choice rules so that the best packages get
- * picked */
+/* called when a choice rule needs to be disabled by analyze_unsolvable.
+ * We also have to disable all other choice rules so that the best packages
+ * get picked */
void
solver_disablechoicerules(Solver *solv, Rule *r)
{
Map m;
Rule *or;
- or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
+ solver_disablerule(solv, r);
+ or = solv->rules + solv->choicerules_info[(r - solv->rules) - solv->choicerules];
map_init(&m, pool->nsolvables);
FOR_RULELITERALS(p, pp, or)
if (p > 0)
r = solv->rules + rid;
if (r->d < 0)
continue;
- or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
+ or = solv->rules + solv->choicerules_info[rid - solv->choicerules];
FOR_RULELITERALS(p, pp, or)
if (p > 0 && MAPTST(&m, p))
break;
Repo *installed = solv->installed;
Queue q, q2;
Rule *r;
- Queue r2pkg;
+ Queue infoq;
int i, oldcnt;
solv->bestrules = solv->nrules;
queue_init(&q);
queue_init(&q2);
- queue_init(&r2pkg);
+ queue_init(&infoq);
if (havebestinstalljobs)
{
solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
if ((how & SOLVER_WEAK) != 0)
queue_push(&solv->weakruleq, solv->nrules - 1);
- queue_push(&r2pkg, -(solv->jobrules + j));
+ queue_push(&infoq, -(solv->jobrules + j));
}
}
}
solver_addrule(solv, -p2, d, 0);
else
solver_addrule(solv, -p2, 0, -d);
- queue_push(&r2pkg, p);
+ queue_push(&infoq, p);
}
for (i = 0; i < q.count; i++)
MAPCLR(&m, q.elements[i]);
solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
else
solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
- queue_push(&r2pkg, p);
+ queue_push(&infoq, p);
}
map_free(&m);
}
- if (r2pkg.count)
- solv->bestrules_pkg = solv_memdup2(r2pkg.elements, r2pkg.count, sizeof(Id));
+ if (infoq.count)
+ solv->bestrules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id));
solv->bestrules_end = solv->nrules;
queue_free(&q);
queue_free(&q2);
- queue_free(&r2pkg);
+ queue_free(&infoq);
}
continue;
if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
continue;
- obsp2 = os->repo->idarraydata + os->obsoletes;
+ obsp2 = os->repo->idarraydata + os->obsoletes;
while ((obs2 = *obsp2++) != 0)
if (obs2 == obs)
break;
continue;
if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
continue;
- obsp2 = os->repo->idarraydata + os->obsoletes;
+ obsp2 = os->repo->idarraydata + os->obsoletes;
while ((obs2 = *obsp2++) != 0)
if (obs2 == obs)
break;
Repo *installed = solv->installed;
Id p, op, *opp;
Solvable *s;
- Queue qo, qq, yumobsinfoq;
+ Queue qo, qq, infoq;
int i, j, k;
unsigned int now;
queue_free(&qo);
return;
}
- queue_init(&yumobsinfoq);
+ queue_init(&infoq);
queue_init(&qq);
for (i = 0; i < qo.count; i++)
{
else
printf("%s\n", pool_solvid2str(pool, qq.elements[j]));
#endif
-
+
if (!qq.count)
continue;
/* at least two goups, build rules */
solver_addrule(solv, -p, qq.elements[groupstart], 0);
else
solver_addrule(solv, -p, 0, pool_ids2whatprovides(pool, qq.elements + groupstart, k - groupstart));
- queue_push(&yumobsinfoq, qo.elements[i]);
+ queue_push(&infoq, qo.elements[i]);
}
groupstart = k + 1;
groupk++;
}
}
}
- if (yumobsinfoq.count)
- solv->yumobsrules_info = solv_memdup2(yumobsinfoq.elements, yumobsinfoq.count, sizeof(Id));
- queue_free(&yumobsinfoq);
+ if (infoq.count)
+ solv->yumobsrules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id));
+ queue_free(&infoq);
queue_free(&qq);
queue_free(&qo);
solv->yumobsrules_end = solv->nrules;
POOL_DEBUG(SOLV_DEBUG_STATS, "yumobs rule creation took %d ms\n", solv_timems(now));
}
+/* recommendsrules are a copy of some recommends package rule but
+ * with some disfavored literals removed */
+void
+solver_addrecommendsrules(Solver *solv)
+{
+ Pool *pool = solv->pool;
+ int i, havedis, havepos;
+ Id p, pp;
+ Queue q, infoq;
+
+ solv->recommendsrules = solv->nrules;
+ queue_init(&q);
+ queue_init(&infoq);
+ for (i = 0; i < solv->recommendsruleq->count; i++)
+ {
+ int rid = solv->recommendsruleq->elements[i];
+ Rule *r = solv->rules + rid;
+ queue_empty(&q);
+ havedis = havepos = 0;
+ FOR_RULELITERALS(p, pp, r)
+ {
+ if (p > 0 && solv->favormap[p] < 0)
+ havedis = 1;
+ else
+ {
+ if (p > 0)
+ havepos = 1;
+ queue_push(&q, p);
+ }
+ }
+ if (!havedis)
+ continue;
+ solver_disablerule(solv, r);
+ if (!havepos || q.count < 2)
+ continue;
+ if (q.count == 2)
+ solver_addrule(solv, q.elements[0], q.elements[1], 0);
+ else
+ solver_addrule(solv, q.elements[0], 0, pool_ids2whatprovides(pool, q.elements + 1, q.count - 1));
+ queue_push(&infoq, rid);
+ }
+ if (infoq.count)
+ solv->recommendsrules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id));
+ queue_free(&infoq);
+ queue_free(&q);
+ solv->recommendsrules_end = solv->nrules;
+}
+
void
solver_breakorphans(Solver *solv)
{
Pool *pool = solv->pool;
int i;
Id l, pp;
-
+
queue_empty(dq);
if (!solv->brokenorphanrules)
return;
SOLVER_RULE_CHOICE = 0x700,
SOLVER_RULE_LEARNT = 0x800,
SOLVER_RULE_BEST = 0x900,
- SOLVER_RULE_YUMOBS = 0xa00
+ SOLVER_RULE_YUMOBS = 0xa00,
+ SOLVER_RULE_RECOMMENDS = 0xb00
} SolverRuleinfo;
#define SOLVER_RULE_TYPEMASK 0xff00
/* yumobs rules */
extern void solver_addyumobsrules(struct s_Solver *solv);
+/* recommends rules */
+extern void solver_addrecommendsrules(struct s_Solver *solv);
+
/* policy rule disabling/reenabling */
extern void solver_disablepolicyrules(struct s_Solver *solv);
extern void solver_reenablepolicyrules(struct s_Solver *solv, int jobidx);
continue;
if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */
continue;
-
+
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
solver_recordproblem(solv, i);
disable_recommendsrules(Solver *solv, Queue *weakq)
{
Pool *pool = solv->pool;
- int i;
+ int i, rid;
for (i = 0; i < weakq->count; i++)
{
- Rule *r;
- if (!queue_contains(solv->recommendsruleq, weakq->elements[i]))
- continue;
- r = solv->rules + weakq->elements[i];
- if (r->d >= 0)
+ rid = weakq->elements[i];
+ if ((rid >= solv->recommendsrules && rid < solv->recommendsrules_end) || queue_contains(solv->recommendsruleq, rid))
{
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
- solver_disablerule(solv, r);
+ Rule *r = solv->rules + rid;
+ if (r->d >= 0)
+ {
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
+ solver_disablerule(solv, r);
+ }
}
}
}
solver_recordproblem(solv, why);
}
+/* fix a problem by disabling one or more weak rules */
+static void
+disable_weakrules(Solver *solv, Queue *weakq)
+{
+ Pool *pool = solv->pool;
+ int i;
+ Id lastweak = 0;
+ for (i = 0; i < weakq->count; i++)
+ if (weakq->elements[i] > lastweak)
+ lastweak = weakq->elements[i];
+ if (lastweak >= solv->recommendsrules && lastweak < solv->recommendsrules_end)
+ {
+ lastweak = 0;
+ for (i = 0; i < weakq->count; i++)
+ if (weakq->elements[i] < solv->recommendsrules && weakq->elements[i] > lastweak)
+ lastweak = weakq->elements[i];
+ if (lastweak < solv->pkgrules_end)
+ {
+ disable_recommendsrules(solv, weakq);
+ return;
+ }
+ }
+ if (lastweak < solv->pkgrules_end && solv->strongrecommends && solv->recommendsruleq && queue_contains(solv->recommendsruleq, lastweak))
+ {
+ disable_recommendsrules(solv, weakq);
+ return;
+ }
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
+ /* choice rules need special handling */
+ if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
+ solver_disablechoicerules(solv, solv->rules + lastweak);
+ else
+ solver_fixproblem(solv, lastweak);
+}
/*-------------------------------------------------------------------
*
Map rseen;
Queue weakq;
Id pp, v, vv, why;
- int i, idx;
+ int idx;
Id *decisionmap = solv->decisionmap;
int oldproblemcount;
int oldlearntpoolcount;
if (weakq.count)
{
- Id lastweak;
/* revert problems */
solv->problems.count = oldproblemcount;
solv->learnt_pool.count = oldlearntpoolcount;
- /* find last weak */
- lastweak = 0;
- for (i = 0; i < weakq.count; i++)
- if (weakq.elements[i] > lastweak)
- lastweak = weakq.elements[i];
- if (lastweak < solv->pkgrules_end && solv->strongrecommends && solv->recommendsruleq && queue_contains(solv->recommendsruleq, lastweak))
- {
- disable_recommendsrules(solv, &weakq);
- queue_free(&weakq);
- solver_reset(solv);
- return 0;
- }
+ /* disable some weak rules */
+ disable_weakrules(solv, &weakq);
queue_free(&weakq);
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
- if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
- solver_disablechoicerules(solv, solv->rules + lastweak);
- solver_fixproblem(solv, lastweak);
solver_reset(solv);
return 0;
}
/*-------------------------------------------------------------------
*
* branch handling
+ *
+ * format is:
+ * [ -p1 p2 p3 .. pn opt_pkg opt_data size level ]
+ *
+ * pkgs are negative if we tried them (to prevent inifinite recursion)
+ * opt_pkg: recommends: package with the recommends
+ * rule: 0
+ * opt_data: recommends: depid
+ * rule: ruleid
*/
static void
map_free(&solv->droporphanedmap);
map_free(&solv->cleandepsmap);
map_free(&solv->allowuninstallmap);
- map_free(&solv->favormap);
- map_free(&solv->isdisfavormap);
+ solv_free(solv->favormap);
solv_free(solv->decisionmap);
solv_free(solv->rules);
solv_free(solv->watches);
solv_free(solv->obsoletes);
solv_free(solv->obsoletes_data);
solv_free(solv->specialupdaters);
- solv_free(solv->choicerules_ref);
- solv_free(solv->bestrules_pkg);
+ solv_free(solv->choicerules_info);
+ solv_free(solv->bestrules_info);
solv_free(solv->yumobsrules_info);
+ solv_free(solv->recommendsrules_info);
solv_free(solv->instbuddy);
solv_free(solv);
}
prune_disfavored(Solver *solv, Queue *plist)
{
int i, j;
- if (!solv->isdisfavormap.size)
- return;
- for (i = j = 0; i < plist->count; i++)
- {
+ for (i = j = 0; i < plist->count; i++)
+ {
Id p = plist->elements[i];
- if (!MAPTST(&solv->isdisfavormap, p))
- plist->elements[j++] = p;
- }
+ if (solv->favormap[p] >= 0)
+ plist->elements[j++] = p;
+ }
if (i != j)
queue_truncate(plist, j);
}
continue;
if (solv->process_orphans && 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))
+ if (solv->havedisfavored && solv->favormap[i] < 0)
continue; /* disfavored supplements, do not install */
queue_push(dqs, i);
}
}
/* filter out disfavored recommended packages */
- if (dq->count && solv->isdisfavormap.size)
+ if (dq->count && solv->havedisfavored)
prune_disfavored(solv, dq);
/* filter out all packages obsoleted by installed packages */
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);
+ 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;
break;
}
*rerunp = 1;
+ return level;
}
}
return level;
if (rerun)
continue;
}
-
+
/* one final pass to make sure we decided all installed packages */
if (solv->installed)
{
lastsi = -1;
break;
}
- if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p))
+ if (solv->havedisfavored && solv->favormap[p] < 0)
continue;
if (lastsi < 0 && (MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
lastsi = i;
if (lastsi >= 0)
{
/* we have a recommended package that could not be installed */
- /* take it if our current selection is not recommended */
+ /* find current selection and take new one if it is not recommended */
for (i = starti; i < endi - 4; i++)
{
p = -solv->branches.elements[i];
if (p <= 0 || solv->decisionmap[p] != l + 1)
continue;
- if (solv->favormap.size && MAPTST(&solv->favormap, p))
- if (!(solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p)))
- continue; /* current selection is favored */
+ if (solv->favormap && solv->favormap[p] > solv->favormap[solv->branches.elements[lastsi]])
+ continue; /* current selection is more favored */
if (!(MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
{
lasti = lastsi;
for (; i < pool->nsolvables; i++)
if (MAPTST(addedmap, i))
queue_push(&solv->addedmap_deduceq, i);
- j = 0;
- for (i = 2; i < pool->nsolvables; i++)
- if (MAPTST(addedmap, i))
- j++;
}
static void
/* sort by package id, last entry wins */
static int
-setup_favormaps_cmp(const void *ap, const void *bp, void *dp)
+setup_favormap_cmp(const void *ap, const void *bp, void *dp)
{
const Id *a = ap, *b = bp;
if ((*a - *b) != 0)
}
static void
-setup_favormaps(Solver *solv)
+setup_favormap(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);
+ solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), setup_favormap_cmp, solv);
+ solv->favormap = solv_calloc(pool->nsolvables, sizeof(Id));
+ solv->havedisfavored = 0;
for (i = 0; i < q->count; i += 2)
{
Id p = q->elements[i];
if (p == oldp)
continue;
oldp = p;
- MAPSET(&solv->favormap, p);
+ solv->favormap[p] = q->elements[i + 1];
if (q->elements[i + 1] < 0)
- {
- if (!solv->isdisfavormap.size)
- map_grow(&solv->isdisfavormap, pool->nsolvables);
- MAPSET(&solv->isdisfavormap, p);
- }
+ solv->havedisfavored = 1;
}
}
queuep_free(&solv->update_targets);
queuep_free(&solv->cleandeps_updatepkgs);
queue_empty(&solv->ruleassertions);
- solv->bestrules_pkg = solv_free(solv->bestrules_pkg);
+ solv->bestrules_info = solv_free(solv->bestrules_info);
solv->yumobsrules_info = solv_free(solv->yumobsrules_info);
- solv->choicerules_ref = solv_free(solv->choicerules_ref);
+ solv->recommendsrules_info = solv_free(solv->recommendsrules_info);
+ solv->choicerules_info = solv_free(solv->choicerules_info);
if (solv->noupdate.size)
map_empty(&solv->noupdate);
map_zerosize(&solv->multiversion);
map_zerosize(&solv->allowuninstallmap);
map_zerosize(&solv->cleandepsmap);
map_zerosize(&solv->weakrulemap);
- map_zerosize(&solv->favormap);
- map_zerosize(&solv->isdisfavormap);
+ solv->favormap = solv_free(solv->favormap);
queue_empty(&solv->weakruleq);
solv->watches = solv_free(solv->watches);
queue_empty(&solv->ruletojob);
*/
initialnrules = solv->pkgrules_end ? solv->pkgrules_end : 1;
if (initialnrules > 1)
- deduceq2addedmap(solv, &addedmap);
+ deduceq2addedmap(solv, &addedmap); /* also enables all pkg rules */
if (solv->nrules != initialnrules)
- solver_shrinkrules(solv, initialnrules);
+ solver_shrinkrules(solv, initialnrules); /* shrink to just pkg rules */
solv->lastpkgrule = 0;
solv->pkgrules_end = 0;
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);
+ queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? i + 1 : -(i + 1));
}
break;
default:
assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
solv->jobrules_end = solv->nrules;
- /* transform favorq into two maps */
+ /* sort favorq and transform it into two maps */
if (solv->favorq)
- setup_favormaps(solv);
+ setup_favormap(solv);
/* now create infarch and dup rules */
if (!solv->noinfarchcheck)
else
solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
+ if (solv->havedisfavored && solv->strongrecommends)
+ solver_addrecommendsrules(solv);
+ else
+ solv->recommendsrules = solv->recommendsrules_end = solv->nrules;
+
if (1)
solver_addchoicerules(solv);
else
solv->choicerules = solv->choicerules_end = solv->nrules;
- if (0)
- {
- for (i = solv->featurerules; i < solv->nrules; i++)
- solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
- }
/* all rules created
* --------------------------------------------------------------
* prepare for solving
char buf[64];
if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
id = solver_rule2pkgrule(solv, id);
+ if (solver_ruleclass(solv, id) == SOLVER_RULE_RECOMMENDS)
+ id = solver_rule2pkgrule(solv, id);
rtype = solver_ruleinfo(solv, id, &depfrom, &depto, &dep);
if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
{
Id bestrules; /* rules from SOLVER_FORCEBEST */
Id bestrules_up; /* update rule part starts here*/
Id bestrules_end;
- Id *bestrules_pkg;
+ Id *bestrules_info; /* < 0 : install rule, > 0 : pkg that needs to be updated */
Id yumobsrules; /* rules from yum obsoletes handling */
Id yumobsrules_end;
Id choicerules; /* choice rules (always weak) */
Id choicerules_end;
- Id *choicerules_ref;
+ Id *choicerules_info; /* the rule we used to generate the choice rule */
+
+ Id recommendsrules; /* rules from recommends pkg rules with disfavored literals */
+ Id recommendsrules_end;
+ Id *recommendsrules_info; /* the original pkg rule rule */
Id learntrules; /* learnt rules, (end == nrules) */
int allowuninstall_all;
Queue *favorq;
- Map favormap; /* favored / disfavored packages */
- Map isdisfavormap;
+ Id *favormap; /* favor job index, > 0: favored, < 0: disfavored */
+ int havedisfavored; /* do we have disfavored packages? */
int installedpos; /* for resolve_installed */
int do_extra_reordering; /* reorder for future installed packages */
POOL_DEBUG(type, "FEATURE ");
else if (p >= solv->yumobsrules && p < solv->yumobsrules_end)
POOL_DEBUG(type, "YUMOBS ");
+ else if (p >= solv->recommendsrules && p < solv->recommendsrules_end)
+ POOL_DEBUG(type, "RECOMMENDS ");
solver_printrule(solv, type, r);
}
--- /dev/null
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: a 1 1 noarch
+#>=Req: b
+#>=Rec: b1
+#>=Pkg: b1 1 1 noarch
+#>=Prv: b
+#>=Pkg: b2 1 1 noarch
+#>=Prv: b
+system x86_64 rpm system
+poolflags implicitobsoleteusescolors
+solverflags ignorerecommended
+job install pkg a-1-1.noarch@available
+job favor name b2
+result transaction,problems,alternatives <inline>
+#>alternative 64eb4d87 0 a-1-1.noarch@available requires b
+#>alternative 64eb4d87 1 + b2-1-1.noarch@available
+#>alternative 64eb4d87 2 b1-1-1.noarch@available
+#>install a-1-1.noarch@available
+#>install b2-1-1.noarch@available
--- /dev/null
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: gcc 5 1 noarch
+#>=Prv: gcc
+#>=Pkg: gcc 6 1 noarch
+#>=Prv: gcc
+#>=Pkg: build-tools 1 1 noarch
+#>=Req: gcc
+system unset * system
+
+job install name build-tools
+job favor pkg gcc-5-1.noarch@available
+result transaction,problems,alternatives <inline>
+#>alternative 6e50ec1a 0 build-tools-1-1.noarch@available requires gcc
+#>alternative 6e50ec1a 1 + gcc-5-1.noarch@available
+#>alternative 6e50ec1a 2 gcc-6-1.noarch@available
+#>install build-tools-1-1.noarch@available
+#>install gcc-5-1.noarch@available
+
+nextjob
+
+job install name build-tools
+job disfavor pkg gcc-6-1.noarch@available
+result transaction,problems,alternatives <inline>
+#>alternative 6e50ec1a 0 build-tools-1-1.noarch@available requires gcc
+#>alternative 6e50ec1a 1 + gcc-5-1.noarch@available
+#>alternative 6e50ec1a 2 gcc-6-1.noarch@available
+#>install build-tools-1-1.noarch@available
+#>install gcc-5-1.noarch@available
+
--- /dev/null
+# test for issue 292
+repo system 0 testtags <inline>
+#>=Pkg: nss 3.39.0 2.fc29 x86_64
+#>=Pkg: nss-sysinit 3.39.0 2.fc29 x86_64
+#>=Req: nss = 3.39.0-2.fc29
+repo available 0 testtags <inline>
+#>=Pkg: nss 3.39.0 2.fc29 i686
+#>=Pkg: nss 3.41.0 1.fc29 x86_64
+#>=Pkg: nss-sysinit 3.41.0 1.fc29 x86_64
+#>=Req: nss = 3.41.0-1.fc29
+
+system x86_64 rpm system
+
+poolflags implicitobsoleteusescolors
+solverflags allowvendorchange keepexplicitobsoletes bestobeypolicy keeporphans yumobsoletes
+
+job install oneof nss-3.41.0-1.fc29.x86_64@available [setevr,setarch]
+result transaction,problems <inline>
+#>upgrade nss-3.39.0-2.fc29.x86_64@system nss-3.41.0-1.fc29.x86_64@available
+#>upgrade nss-sysinit-3.39.0-2.fc29.x86_64@system nss-sysinit-3.41.0-1.fc29.x86_64@available
--- /dev/null
+# test strong recommends
+#
+# with normal recommends, the solver will
+# not backtrack to fulfill them.
+#
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Con: C
+#>=Pkg: A2 1 1 noarch
+#>=Con: C2
+repo available 0 testtags <inline>
+#>=Pkg: A 1 2 noarch
+#>=Pkg: B 1 1 noarch
+#>=Rec: C
+#>=Pkg: C 1 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Rec: C2
+#>=Pkg: C2 1 1 noarch
+#>=Pkg: D 1 1 noarch
+#>=Prv: C
+#>=Pkg: E 1 1 noarch
+#>=Prv: C
+system i686 rpm system
+solverflags strongrecommends
+job install name B
+job install name B2
+job disfavor name C
+result transaction,problems,alternatives <inline>
+#>alternative 6b91d100 1 + D-1-1.noarch@available
+#>alternative 6b91d100 2 E-1-1.noarch@available
+#>install B-1-1.noarch@available
+#>install B2-1-1.noarch@available
+#>install D-1-1.noarch@available
+#>upgrade A-1-1.noarch@system A-1-2.noarch@available
close(fds[1]);
}
if (recursive)
- execl("/usr/bin/find", ".", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
+ execl("/usr/bin/find", "/usr/bin/find", ".", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
else
- execl("/usr/bin/find", ".", "-maxdepth", "1", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
+ execl("/usr/bin/find", "/usr/bin/find", ".", "-maxdepth", "1", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
perror("/usr/bin/find");
_exit(1);
}
repodata_set_location(data, p, 0, 0, bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp);
solv_free(rpm);
}
+ solv_free(buf);
fclose(fp);
while (waitpid(pid, &wstatus, 0) == -1)
{