+/*
+ * Copyright (c) 2009 - 2017 SUSE Linux Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the same terms as Perl itself.
+ *
+ */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#define MULTI_SEMANTICS
+#include "solvversion.h"
+#if LIBSOLV_VERSION < 623
+#define LIBSOLVEXT_FEATURE_DEBIAN
+#define LIBSOLVEXT_FEATURE_ARCHREPO
+#endif
+
#include "pool.h"
#include "repo.h"
#include "util.h"
#include "evr.h"
#include "hash.h"
#include "chksum.h"
+#include "testcase.h"
#include "repo_solv.h"
#include "repo_write.h"
#include "repo_rpmdb.h"
+#if defined(LIBSOLVEXT_FEATURE_DEBIAN)
#include "repo_deb.h"
-#if 1
+#endif
+#if defined(LIBSOLVEXT_FEATURE_ARCHREPO)
#include "repo_arch.h"
#endif
+#if defined(LIBSOLV_FEATURE_COMPLEX_DEPS)
+#include "pool_parserpmrichdep.h"
+#endif
+
+#ifndef REL_ERROR
+# define REL_ERROR 27 /* for old libsolv versions */
+#endif
+#ifndef REL_UNLESS
+# define REL_UNLESS 29 /* for old libsolv versions */
+#endif
+
+#define EXPANDER_DEBUG_ALL (1 << 0)
+#define EXPANDER_DEBUG_STDOUT (1 << 1)
+#define EXPANDER_DEBUG_STR (1 << 2)
+
+#define EXPANDER_OPTION_IGNOREIGNORE (1 << 0)
+#define EXPANDER_OPTION_IGNORECONFLICTS (1 << 1)
+#define EXPANDER_OPTION_DORECOMMENDS (1 << 2)
+#define EXPANDER_OPTION_DOSUPPLEMENTS (1 << 3)
+#define EXPANDER_OPTION_USERECOMMENDSFORCHOICES (1 << 4)
+#define EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES (1 << 5)
typedef struct _Expander {
Pool *pool;
Queue conflictsq;
Map conflicts;
- int debug;
int havefileprovides;
- int ignoreconflicts;
- int ignoreignore;
+ /* debug support */
+ int debug;
char *debugstr;
int debugstrl;
int debugstrf;
+
+ /* options */
+ int ignoreconflicts;
+ int ignoreignore;
int userecommendsforchoices;
+ int usesupplementsforchoices;
+ int dorecommends;
+ int dosupplements;
} Expander;
+typedef struct _ExpanderCtx {
+ Pool *pool;
+ Expander *xp;
+ Queue *out; /* the result */
+ Map installed; /* installed packages */
+ Map conflicts; /* conflicts from installed packages */
+ Queue conflictsinfo; /* source info for the above */
+ int cidone; /* conflictsinfo done position */
+ Queue todo; /* requires todo list */
+ Queue errors; /* expansion errors */
+ Queue cplxq; /* complex dep work queue */
+ Queue cplxblks; /* complex dep block data, add only */
+ Queue todo_cond; /* delayed requires/conflicts */
+ Queue pruneq; /* multi purpose queue for pruning packages */
+ Map todo_condmap; /* all neg packages in todo_cond blocks */
+ Map recommended; /* recommended packages */
+ int recdone; /* recommended done position */
+
+ /* options */
+ int ignoreconflicts;
+ int ignoreignore;
+ int userecommendsforchoices;
+ int usesupplementsforchoices;
+ int dorecommends;
+ int dosupplements;
+
+ /* hacks */
+ Solvable *ignore_s; /* small hack: ignore requires of this solvable */
+} ExpanderCtx;
+
+
typedef Pool *BSSolv__pool;
typedef Repo *BSSolv__repo;
typedef Expander *BSSolv__expander;
static Id buildservice_repocookie;
static Id buildservice_external;
static Id buildservice_dodurl;
-static Id expander_directdepsend;
static Id buildservice_dodcookie;
+static Id buildservice_dodresources;
+static Id buildservice_annotation;
+static Id buildservice_modules;
+static Id expander_directdepsend;
+
static int genmetaalgo;
+static int depsortsccs;
/* make sure bit n is usable */
#define MAPEXP(m, n) ((m)->size < (((n) + 8) >> 3) ? map_grow(m, n + 256) : 0)
}
static Id
-dep2id(Pool *pool, char *s)
+dep2id_rec(Pool *pool, char *s)
{
char *n;
Id id;
if ((n = strchr(s, '|')) != 0)
{
- id = dep2id(pool, n + 1);
+ id = dep2id_rec(pool, n + 1);
*n = 0;
- id = pool_rel2id(pool, dep2id(pool, s), id, REL_OR, 1);
+ id = pool_rel2id(pool, dep2id_rec(pool, s), id, REL_OR, 1);
*n = '|';
return id;
}
while (*s == ' ' || *s == '\t')
s++;
n = s;
- while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>')
- s++;
+ if (pool->disttype == DISTTYPE_RPM)
+ {
+ /* rpm delimits the name by whitespace only */
+ while (*s && *s != ' ' && *s != '\t')
+ s++;
+ }
+ else
+ {
+ while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>')
+ s++;
+ }
#ifdef REL_MULTIARCH
if (s - n > 4 && s[-4] == ':' && !strncmp(s - 4, ":any", 4))
{
for (;;s++)
{
if (*s == '<')
- flags |= REL_LT;
+ flags |= REL_LT;
else if (*s == '=')
- flags |= REL_EQ;
+ flags |= REL_EQ;
else if (*s == '>')
- flags |= REL_GT;
+ flags |= REL_GT;
else
- break;
+ break;
}
if (!flags)
return id;
return pool_rel2id(pool, id, pool_strn2id(pool, n, s - n, 1), flags, 1);
}
-static inline Offset
+static Id
+parsedep_error(Pool *pool, const char *s)
+{
+ Id id;
+ id = pool_str2id(pool, s, 1);
+ return pool_rel2id(pool, pool_str2id(pool, "dependency parse error", 1), id, REL_ERROR, 1);
+}
+
+static Id
+dep2id(Pool *pool, char *s)
+{
+ Id id;
+ if (pool->disttype == DISTTYPE_RPM && *s == '(')
+ {
+#if defined(LIBSOLV_FEATURE_COMPLEX_DEPS)
+ id = pool_parserpmrichdep(pool, s);
+#else
+ id = 0;
+#endif
+ }
+ else
+ id = dep2id_rec(pool, s);
+ if (!id)
+ id = parsedep_error(pool, s);
+ return id;
+}
+
+static Offset
importdeps(HV *hv, const char *key, int keyl, Repo *repo)
{
Pool *pool = repo->pool;
- int i;
+ SSize_t i;
AV *av = hvlookupav(hv, key, keyl);
Offset off = 0;
if (av)
{
char *str = avlookupstr(av, i);
if (str)
- off = repo_addid_dep(repo, off, dep2id(pool, str), 0);
+ {
+ Id id = testcase_str2dep(pool, str);
+ if (!id)
+ id = parsedep_error(pool, str);
+ off = repo_addid_dep(repo, off, id, 0);
+ }
}
}
return off;
}
-void
+static void
exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey)
{
Pool *pool = repo->pool;
{
if (id == SOLVABLE_FILEMARKER)
break;
- str = pool_dep2str(pool, id);
- if (ISRELDEP(id))
- {
- Reldep *rd = GETRELDEP(pool, id);
- if (skey == SOLVABLE_CONFLICTS && rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
- {
- if (!strncmp(str, "namespace:", 10))
- str += 10;
- }
- if (skey == SOLVABLE_SUPPLEMENTS)
- {
- if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_FILESYSTEM)
- {
- if (!strncmp(str, "namespace:", 10))
- str += 10;
- }
- else if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_MODALIAS)
- {
- if (!strncmp(str, "namespace:", 10))
- str += 10;
- }
- else if (rd->flags == REL_AND)
- {
- /* either packageand chain or modalias */
- str = 0;
- if (ISRELDEP(rd->evr))
- {
- Reldep *mrd = GETRELDEP(pool, rd->evr);
- if (mrd->flags == REL_NAMESPACE && mrd->name == NAMESPACE_MODALIAS)
- {
- str = pool_tmpjoin(pool, "modalias(", pool_dep2str(pool, rd->name), ":");
- str = pool_tmpappend(pool, str, pool_dep2str(pool, mrd->evr), ")");
- }
- else if (mrd->flags >= 8)
- continue;
- }
- if (!str)
- {
- /* must be and chain */
- str = pool_dep2str(pool, rd->evr);
- for (;;)
- {
- id = rd->name;
- if (!ISRELDEP(id))
- break;
- rd = GETRELDEP(pool, id);
- if (rd->flags != REL_AND)
- break;
- str = pool_tmpjoin(pool, pool_dep2str(pool, rd->evr), ":", str);
- }
- str = pool_tmpjoin(pool, pool_dep2str(pool, id), ":", str);
- str = pool_tmpjoin(pool, "packageand(", str, ")");
- }
- }
- else if (rd->flags >= 8)
- continue;
- }
- }
+ str = testcase_dep2str(pool, id);
if (skey == SOLVABLE_REQUIRES)
{
if (id == SOLVABLE_PREREQMARKER)
(void)hv_store(hv, key, keyl, newRV_noinc((SV*)av), 0);
}
-void
-data2solvables(Repo *repo, Repodata *data, HV *rhv)
+static int
+data2pkg(Repo *repo, Repodata *data, HV *hv, int isdod)
{
Pool *pool = repo->pool;
- SV *sv;
- HV *hv;
- char *str, *key;
- I32 keyl;
+ char *str;
Id p;
Solvable *s;
+ AV *av;
- hv_iterinit(rhv);
- while ((sv = hv_iternextsv(rhv, &key, &keyl)) != 0)
+ str = hvlookupstr(hv, "name", 4);
+ if (!str)
+ return 0; /* need to have a name */
+ p = repo_add_solvable(repo);
+ s = pool_id2solvable(pool, p);
+ s->name = pool_str2id(pool, str, 1);
+ str = hvlookupstr(hv, "arch", 4);
+ if (!str)
+ str = ""; /* dummy, need to have arch */
+ s->arch = pool_str2id(pool, str, 1);
+ s->evr = makeevr(pool, hvlookupstr(hv, "epoch", 5), hvlookupstr(hv, "version", 7), hvlookupstr(hv, "release", 7));
+ str = hvlookupstr(hv, "path", 4);
+ if (str)
{
- if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV)
- continue;
- hv = (HV *)SvRV(sv);
- str = hvlookupstr(hv, "name", 4);
- if (!str)
- continue; /* need to have a name */
- p = repo_add_solvable(repo);
- s = pool_id2solvable(pool, p);
- s->name = pool_str2id(pool, str, 1);
- str = hvlookupstr(hv, "arch", 4);
- if (!str)
- str = ""; /* dummy, need to have arch */
- s->arch = pool_str2id(pool, str, 1);
- s->evr = makeevr(pool, hvlookupstr(hv, "epoch", 5), hvlookupstr(hv, "version", 7), hvlookupstr(hv, "release", 7));
- str = hvlookupstr(hv, "path", 4);
- if (str)
+ char *ss = strrchr(str, '/');
+ if (ss)
{
- char *ss = strrchr(str, '/');
- if (ss)
- {
- *ss = 0;
- repodata_set_str(data, p, SOLVABLE_MEDIADIR, str);
- *ss++ = '/';
- }
- else
- ss = str;
- repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss);
+ *ss = 0;
+ repodata_set_str(data, p, SOLVABLE_MEDIADIR, str);
+ *ss++ = '/';
}
+ else
+ ss = str;
+ repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss);
+ }
+ if (isdod)
+ repodata_set_str(data, p, buildservice_id, "dod");
+ else
+ {
str = hvlookupstr(hv, "id", 2);
if (str)
repodata_set_str(data, p, buildservice_id, str);
- str = hvlookupstr(hv, "source", 6);
- if (str)
- repodata_set_poolstr(data, p, SOLVABLE_SOURCENAME, str);
+ }
+ str = hvlookupstr(hv, "source", 6);
+ if (str)
+ repodata_set_poolstr(data, p, SOLVABLE_SOURCENAME, str);
+ if (isdod)
+ {
+ static unsigned char dod_pkgid[16] = { 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0 };
+ repodata_set_bin_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, dod_pkgid);
+ }
+ else
+ {
str = hvlookupstr(hv, "hdrmd5", 6);
if (str && strlen(str) == 32)
repodata_set_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, str);
- s->provides = importdeps(hv, "provides", 8, repo);
- s->obsoletes = importdeps(hv, "obsoletes", 9, repo);
- s->conflicts = importdeps(hv, "conflicts", 9, repo);
- s->requires = importdeps(hv, "requires", 8, repo);
- s->recommends = importdeps(hv, "recommends", 10, repo);
- s->suggests = importdeps(hv, "suggests", 8, repo);
- s->supplements = importdeps(hv, "supplements", 11, repo);
- s->enhances = importdeps(hv, "enhances", 8, repo);
- if (!s->evr && s->provides)
- {
- /* look for self provides */
- Id pro, *prop = s->repo->idarraydata + s->provides;
- while ((pro = *prop++) != 0)
- {
- Reldep *rd;
- if (!ISRELDEP(pro))
- continue;
- rd = GETRELDEP(pool, pro);
- if (rd->name == s->name && rd->flags == REL_EQ)
- s->evr = rd->evr;
- }
+ }
+ s->provides = importdeps(hv, "provides", 8, repo);
+ s->obsoletes = importdeps(hv, "obsoletes", 9, repo);
+ s->conflicts = importdeps(hv, "conflicts", 9, repo);
+ s->requires = importdeps(hv, "requires", 8, repo);
+ s->recommends = importdeps(hv, "recommends", 10, repo);
+ s->suggests = importdeps(hv, "suggests", 8, repo);
+ s->supplements = importdeps(hv, "supplements", 11, repo);
+ s->enhances = importdeps(hv, "enhances", 8, repo);
+ if (!s->evr && s->provides)
+ {
+ /* look for self provides */
+ Id pro, *prop = s->repo->idarraydata + s->provides;
+ while ((pro = *prop++) != 0)
+ {
+ Reldep *rd;
+ if (!ISRELDEP(pro))
+ continue;
+ rd = GETRELDEP(pool, pro);
+ if (rd->name == s->name && rd->flags == REL_EQ)
+ s->evr = rd->evr;
+ }
+ }
+ if (s->evr && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+ s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+ str = hvlookupstr(hv, "checksum", 8);
+ if (str)
+ {
+ char *cp, typebuf[8];
+ Id ctype;
+ if (*str != ':' && (cp = strchr(str, ':')) != 0 && cp - str < sizeof(typebuf))
+ {
+ strncpy(typebuf, str, cp - str);
+ typebuf[cp - str] = 0;
+ ctype = solv_chksum_str2type(typebuf);
+ if (ctype)
+ repodata_set_checksum(data, p, SOLVABLE_CHECKSUM, ctype, cp + 1);
+ }
+ }
+ str = hvlookupstr(hv, "annotation", 10);
+ if (str && strlen(str) < 100000)
+ repodata_set_str(data, p, buildservice_annotation, str);
+ av = hvlookupav(hv, "modules", 7);
+ if (av)
+ {
+ SSize_t i;
+ for (i = 0; i <= av_len(av); i++)
+ {
+ char *str = avlookupstr(av, i);
+ repodata_add_idarray(data, p, buildservice_modules, pool_str2id(pool, str, 1));
+ }
+ }
+ return p;
+}
+
+static void
+data2solvables(Repo *repo, Repodata *data, SV *rsv, int isdod)
+{
+ AV *rav = 0;
+ SSize_t ravi = 0;
+ HV *rhv = 0;
+ SV *sv;
+ char *key;
+ I32 keyl;
+
+ if (SvTYPE(rsv) == SVt_PVAV)
+ rav = (AV *)rsv;
+ else
+ rhv = (HV *)rsv;
+
+ if (rhv)
+ hv_iterinit(rhv);
+ for (;;)
+ {
+ if (rhv)
+ {
+ sv = hv_iternextsv(rhv, &key, &keyl);
+ if (!sv)
+ break;
+ }
+ else
+ {
+ SV **svp;
+ if (ravi > av_len(rav))
+ break;
+ svp = av_fetch(rav, ravi++, 0);
+ if (!svp || !*svp)
+ continue;
+ sv = *svp;
}
- if (s->evr)
- s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
- str = hvlookupstr(hv, "checksum", 8);
+ if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV)
+ continue;
+ data2pkg(repo, data, (HV *)SvRV(sv), isdod);
+ }
+
+ /* set meta information */
+ repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
+ if (rhv)
+ {
+ char *str;
+ AV *av;
+ str = hvlookupstr(rhv, "/url", 4);
if (str)
+ repodata_set_str(data, SOLVID_META, buildservice_dodurl, str);
+ str = hvlookupstr(rhv, "/dodcookie", 10);
+ if (str)
+ repodata_set_str(data, SOLVID_META, buildservice_dodcookie, str);
+ av = hvlookupav(rhv, "/dodresources", 13);
+ if (av)
{
- char *cp, typebuf[8];
- Id ctype;
- if (*str != ':' && (cp = strchr(str, ':')) != 0 && cp - str < sizeof(typebuf))
+ SSize_t i;
+ for (i = 0; i <= av_len(av); i++)
{
- strncpy(typebuf, str, cp - str);
- typebuf[cp - str] = 0;
- ctype = solv_chksum_str2type(typebuf);
- if (ctype)
- repodata_set_checksum(data, p, SOLVABLE_CHECKSUM, ctype, cp + 1);
+ Id id = pool_str2id(repo->pool, avlookupstr(av, i), 1);
+ repodata_add_idarray(data, SOLVID_META, buildservice_dodresources, id);
}
}
}
-
- repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
- str = hvlookupstr(rhv, "/url", 4);
- if (str)
- repodata_set_str(data, SOLVID_META, buildservice_dodurl, str);
- str = hvlookupstr(rhv, "/dodcookie", 10);
- if (str)
- repodata_set_str(data, SOLVID_META, buildservice_dodcookie, str);
}
static SV *
return sv;
}
-static void
-expander_dbg(Expander *xp, const char *format, ...)
+#define CPLXDEPS_TODNF (1 << 0)
+
+static int
+invert_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int r)
{
- va_list args;
- char buf[1024];
- int l;
- if (!xp->debug)
- return;
- va_start(args, format);
- vsnprintf(buf, sizeof(buf), format, args);
- va_end(args);
- printf("%s", buf);
- l = strlen(buf);
- if (buf[0] != ' ' || (l && buf[l - 1] == '\n'))
- fflush(stdout);
- if (l >= xp->debugstrf) /* >= because of trailing \0 */
+ int i, j, end;
+ if (r == 0 || r == 1)
+ return r ? 0 : 1;
+ end = bq->count;
+ for (i = j = start; i < end; i++)
{
- xp->debugstr = solv_realloc(xp->debugstr, xp->debugstrl + l + 1024);
- xp->debugstrf = l + 1024;
+ if (bq->elements[i])
+ {
+ bq->elements[i] = -bq->elements[i];
+ continue;
+ }
+ /* end of block reached, reverse */
+ if (i - 1 > j)
+ {
+ int k;
+ for (k = i - 1; j < k; j++, k--)
+ {
+ Id t = bq->elements[j];
+ bq->elements[j] = bq->elements[k];
+ bq->elements[k] = t;
+ }
+ }
+ j = i + 1;
}
- strcpy(xp->debugstr + xp->debugstrl, buf);
- xp->debugstrl += l;
- xp->debugstrf -= l;
-}
-
-static const char *
-expander_solvid2name(Expander *xp, Id p)
-{
- const char *n = pool_id2str(xp->pool, xp->pool->solvables[p].name);
- Repo *r;
- if (!xp->debug)
- return n;
- r = xp->pool->solvables[p].repo;
- if (!r)
- return n;
- return pool_tmpjoin(xp->pool, n, "@", r->name);
+ return -1;
}
-static inline void
-expander_installed(Expander *xp, Id p, Map *installed, Map *conflicts, Queue *conflictsinfo, int *cidone, Queue *out, Queue *todo)
+static int
+distribute_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int start2, int flags)
{
- Pool *pool = xp->pool;
- Solvable *s = pool->solvables + p;
- Id req, id, *reqp, con, *conp;
- const char *n;
-
- MAPSET(installed, p);
- queue_push(out, p);
- if (MAPTST(&xp->conflicts, s->name))
- {
- int i;
- for (i = 0; i < xp->conflictsq.count; i++)
- {
- Id p2, pp2;
- Id id = xp->conflictsq.elements[i];
- if (id != s->name)
- continue;
- id = xp->conflictsq.elements[i ^ 1];
- FOR_PROVIDES(p2, pp2, id)
- {
- if (pool->solvables[p2].name == id)
- {
- MAPEXP(conflicts, pool->nsolvables);
- MAPSET(conflicts, p2);
- }
- }
- }
- }
- if (s->requires)
+ int i, j, end2 = bq->count;
+ for (i = start; i < start2; i++)
{
- reqp = s->repo->idarraydata + s->requires;
- while ((req = *reqp++) != 0)
+ for (j = start2; j < end2; j++)
{
- if (req == SOLVABLE_PREREQMARKER)
- continue;
- id = id2name(pool, req);
- if (!xp->ignoreignore)
+ int a, b;
+ int bqcnt4 = bq->count;
+ int k = i;
+
+ /* distribute i block with j block, both blocks are sorted */
+ while (bq->elements[k] && bq->elements[j])
{
- if (MAPTST(&xp->ignored, id))
- continue;
- if (MAPTST(&xp->ignoredx, id))
+ if (bq->elements[k] < bq->elements[j])
+ queue_push(bq, bq->elements[k++]);
+ else
{
- Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, s->name), ":", pool_id2str(pool, id)), 0);
- if (xid && MAPTST(&xp->ignored, xid))
- continue;
+ if (bq->elements[k] == bq->elements[j])
+ k++;
+ queue_push(bq, bq->elements[j++]);
}
}
- n = pool_id2str(pool, id);
- if (!strncmp(n, "rpmlib(", 7))
- {
- MAPEXP(&xp->ignored, id);
- MAPSET(&xp->ignored, id);
- continue;
- }
- if (*n == '/')
+ while (bq->elements[j])
+ queue_push(bq, bq->elements[j++]);
+ while (bq->elements[k])
+ queue_push(bq, bq->elements[k++]);
+
+ /* block is finished, check for A + -A */
+ for (a = bqcnt4, b = bq->count - 1; a < b; )
{
- if (!xp->havefileprovides || pool->whatprovides[id] <= 1)
- {
- MAPEXP(&xp->ignored, id);
- MAPSET(&xp->ignored, id);
- continue;
- }
+ if (-bq->elements[a] == bq->elements[b])
+ break;
+ if (-bq->elements[a] > bq->elements[b])
+ a++;
+ else
+ b--;
}
- queue_push2(todo, req, p);
+ if (a < b)
+ queue_truncate(bq, bqcnt4); /* ignore this block */
+ else
+ queue_push(bq, 0); /* finish block */
}
+ /* advance to next block */
+ while (bq->elements[i])
+ i++;
}
- if (!xp->ignoreconflicts)
+ queue_deleten(bq, start, end2 - start);
+ if (start == bq->count)
+ return flags & CPLXDEPS_TODNF ? 0 : 1;
+ return -1;
+}
+
+#if 0
+static void
+print_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int r)
+{
+ Pool *pool = xpctx->pool;
+ int i;
+
+ if (r == 0)
{
- if (s->conflicts)
- {
- conp = s->repo->idarraydata + s->conflicts;
- while ((con = *conp++) != 0)
- {
- Id p2, pp2;
- FOR_PROVIDES(p2, pp2, con)
- {
- if (p2 == p)
- continue;
- MAPEXP(conflicts, pool->nsolvables);
- MAPSET(conflicts, p2);
- if (xp->debug)
- queue_push2(conflictsinfo, p2, p);
- }
- }
- }
- if (s->obsoletes)
- {
+ printf("[NONE]\n");
+ return;
+ }
+ if (r == 1)
+ {
+ printf("[ALL]\n");
+ return;
+ }
+ for (i = start; i < bq->count; i++)
+ {
+ if (bq->elements[i] > 0)
+ printf(" %s", pool_solvid2str(pool, bq->elements[i]));
+ else if (bq->elements[i] < 0)
+ printf(" -%s", pool_solvid2str(pool, -bq->elements[i]));
+ else
+ printf(" ||");
+ }
+ printf("\n");
+}
+#endif
+
+
+static int
+pool_is_complex_dep_rd(Pool *pool, Reldep *rd)
+{
+ for (;;)
+ {
+ if (rd->flags == REL_AND || rd->flags == REL_COND || rd->flags == REL_UNLESS) /* those are the complex ones */
+ return 1;
+ if (rd->flags != REL_OR)
+ return 0;
+ if (ISRELDEP(rd->name) && pool_is_complex_dep_rd(pool, GETRELDEP(pool, rd->name)))
+ return 1;
+ if (!ISRELDEP(rd->evr))
+ return 0;
+ rd = GETRELDEP(pool, rd->evr);
+ }
+}
+
+static inline int
+pool_is_complex_dep(Pool *pool, Id dep)
+{
+ if (ISRELDEP(dep))
+ {
+ Reldep *rd = GETRELDEP(pool, dep);
+ if (rd->flags >= 8 && pool_is_complex_dep_rd(pool, rd))
+ return 1;
+ }
+ return 0;
+}
+
+static int normalize_dep(ExpanderCtx *xpctx, Id dep, Queue *bq, int flags);
+
+static int
+normalize_dep_or(ExpanderCtx *xpctx, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
+{
+ int r1, r2, bqcnt2, bqcnt = bq->count;
+ r1 = normalize_dep(xpctx, dep1, bq, flags);
+ if (r1 == 1)
+ return 1; /* early exit */
+ bqcnt2 = bq->count;
+ r2 = normalize_dep(xpctx, dep2, bq, flags ^ invflags);
+ if (invflags)
+ r2 = invert_depblocks(xpctx, bq, bqcnt2, r2);
+ if (r1 == 1 || r2 == 1)
+ {
+ queue_truncate(bq, bqcnt);
+ return 1;
+ }
+ if (r1 == 0)
+ return r2;
+ if (r2 == 0)
+ return r1;
+ if ((flags & CPLXDEPS_TODNF) == 0)
+ return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
+ return -1;
+}
+
+static int
+normalize_dep_and(ExpanderCtx *xpctx, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
+{
+ int r1, r2, bqcnt2, bqcnt = bq->count;
+ r1 = normalize_dep(xpctx, dep1, bq, flags);
+ if (r1 == 0)
+ return 0; /* early exit */
+ bqcnt2 = bq->count;
+ r2 = normalize_dep(xpctx, dep2, bq, flags ^ invflags);
+ if (invflags)
+ r2 = invert_depblocks(xpctx, bq, bqcnt2, r2);
+ if (r1 == 0 || r2 == 0)
+ {
+ queue_truncate(bq, bqcnt);
+ return 0;
+ }
+ if (r1 == 1)
+ return r2;
+ if (r2 == 1)
+ return r1;
+ if ((flags & CPLXDEPS_TODNF) != 0)
+ return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
+ return -1;
+}
+
+static int
+normalize_dep_if_else(ExpanderCtx *xpctx, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
+{
+ /* A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */
+ int r1, r2, bqcnt2, bqcnt = bq->count;
+ r1 = normalize_dep_or(xpctx, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
+ if (r1 == 0)
+ return 0; /* early exit */
+ bqcnt2 = bq->count;
+ r2 = normalize_dep_or(xpctx, dep2, dep3, bq, flags, 0);
+ if (r1 == 0 || r2 == 0)
+ {
+ queue_truncate(bq, bqcnt);
+ return 0;
+ }
+ if (r1 == 1)
+ return r2;
+ if (r2 == 1)
+ return r1;
+ if ((flags & CPLXDEPS_TODNF) != 0)
+ return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
+ return -1;
+}
+
+static int
+normalize_dep_unless_else(ExpanderCtx *xpctx, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
+{
+ /* A UNLESS (B ELSE C) -> (A AND ~B) OR (C AND B) */
+ int r1, r2, bqcnt2, bqcnt = bq->count;
+ r1 = normalize_dep_and(xpctx, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
+ if (r1 == 1)
+ return 1; /* early exit */
+ bqcnt2 = bq->count;
+ r2 = normalize_dep_and(xpctx, dep2, dep3, bq, flags, 0);
+ if (r1 == 1 || r2 == 1)
+ {
+ queue_truncate(bq, bqcnt);
+ return 1;
+ }
+ if (r1 == 0)
+ return r2;
+ if (r2 == 0)
+ return r1;
+ if ((flags & CPLXDEPS_TODNF) == 0)
+ return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
+ return -1;
+}
+
+static int expander_isignored(Expander *xp, Solvable *s, Id req);
+
+static int
+normalize_dep(ExpanderCtx *xpctx, Id dep, Queue *bq, int flags)
+{
+ Pool *pool = xpctx->pool;
+ Id p, dp;
+
+ if (pool_is_complex_dep(pool, dep))
+ {
+ Reldep *rd = GETRELDEP(pool, dep);
+ if (rd->flags == REL_COND)
+ {
+ Id evr = rd->evr;
+ if (ISRELDEP(evr))
+ {
+ Reldep *rd2 = GETRELDEP(pool, evr);
+ if (rd2->flags == REL_ELSE)
+ return normalize_dep_if_else(xpctx, rd->name, rd2->name, rd2->evr, bq, flags);
+ }
+ return normalize_dep_or(xpctx, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
+ }
+ if (rd->flags == REL_UNLESS)
+ {
+ Id evr = rd->evr;
+ if (ISRELDEP(evr))
+ {
+ Reldep *rd2 = GETRELDEP(pool, evr);
+ if (rd2->flags == REL_ELSE)
+ return normalize_dep_unless_else(xpctx, rd->name, rd2->name, rd2->evr, bq, flags);
+ }
+ return normalize_dep_and(xpctx, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
+ }
+ if (rd->flags == REL_OR)
+ return normalize_dep_or(xpctx, rd->name, rd->evr, bq, flags, 0);
+ if (rd->flags == REL_AND)
+ return normalize_dep_and(xpctx, rd->name, rd->evr, bq, flags, 0);
+ }
+
+ if (xpctx->ignore_s && (flags & CPLXDEPS_TODNF) == 0)
+ {
+ if (expander_isignored(xpctx->xp, xpctx->ignore_s, dep))
+ return 1;
+ }
+
+ dp = pool_whatprovides(pool, dep);
+ if (dp == 2)
+ return 1;
+ if (dp < 2 || !pool->whatprovidesdata[dp])
+ return 0;
+ if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE)
+ return 1;
+ if ((flags & CPLXDEPS_TODNF) != 0)
+ {
+ while ((p = pool->whatprovidesdata[dp++]) != 0)
+ queue_push2(bq, p, 0);
+ }
+ else
+ {
+ while ((p = pool->whatprovidesdata[dp++]) != 0)
+ queue_push(bq, p);
+ queue_push(bq, 0);
+ }
+ return -1;
+}
+
+#define ISCPLX(pool, d) (ISRELDEP(d) && GETRELID(d) >= pool->nrels)
+#define GETCPLX(pool, d) (GETRELID(d) - pool->nrels)
+#define MAKECPLX(pool, d) (MAKERELDEP(pool->nrels + d))
+
+#define DEPTYPE_REQUIRES 0
+#define DEPTYPE_CONFLICTS 1
+#define DEPTYPE_OBSOLETES 2
+#define DEPTYPE_RECOMMENDS 3
+#define DEPTYPE_PROVIDES 4
+
+#define ERROR_NOPROVIDER 1
+#define ERROR_CHOICE 2
+#define ERROR_CONFLICTINGPROVIDERS 3
+#define ERROR_PROVIDERINFO 4
+#define ERROR_PROVIDERINFO2 5
+#define ERROR_BADDEPENDENCY 6
+#define ERROR_CONFLICT 7
+#define ERROR_CONFLICT2 8
+#define ERROR_ALLCONFLICT 9
+#define ERROR_NOPROVIDERINFO 10
+
+static void
+expander_dbg(Expander *xp, const char *format, ...)
+{
+ va_list args;
+ char buf[1024];
+ int l;
+
+ if (!xp->debug)
+ return;
+ va_start(args, format);
+ vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+ l = strlen(buf);
+ if ((xp->debug & (EXPANDER_DEBUG_ALL | EXPANDER_DEBUG_STDOUT)) != 0)
+ {
+ printf("%s", buf);
+ if (buf[0] != ' ' || (l && buf[l - 1] == '\n'))
+ fflush(stdout);
+ }
+ if ((xp->debug & (EXPANDER_DEBUG_ALL | EXPANDER_DEBUG_STR)) != 0)
+ {
+ if (l >= xp->debugstrf) /* >= because of trailing \0 */
+ {
+ xp->debugstr = solv_realloc(xp->debugstr, xp->debugstrl + l + 1024);
+ xp->debugstrf = l + 1024;
+ }
+ strcpy(xp->debugstr + xp->debugstrl, buf);
+ xp->debugstrl += l;
+ xp->debugstrf -= l;
+ }
+}
+
+static void
+expander_clrdbg(Expander *xp)
+{
+ if (xp->debugstr)
+ free(xp->debugstr);
+ xp->debugstr = 0;
+ xp->debugstrl = xp->debugstrf = 0;
+}
+
+static const char *
+expander_solvid2name(Expander *xp, Id p)
+{
+ const char *n = pool_id2str(xp->pool, xp->pool->solvables[p].name);
+ Repo *r;
+ if (!xp->debug)
+ return n;
+ r = xp->pool->solvables[p].repo;
+ if (!r)
+ return n;
+ return pool_tmpjoin(xp->pool, n, "@", r->name);
+}
+
+static const char *
+expander_solvid2str(Expander *xp, Id p)
+{
+ const char *n = pool_solvid2str(xp->pool, p);
+ Repo *r;
+ if (!xp->debug)
+ return n;
+ r = xp->pool->solvables[p].repo;
+ if (!r)
+ return n;
+ return pool_tmpjoin(xp->pool, n, "@", r->name);
+}
+
+static int
+pkgname_sort_cmp(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = (Pool *)dp;
+ Id a = *(Id *)ap;
+ Id b = *(Id *)bp;
+ return strcmp(pool_id2str(pool, pool->solvables[a].name), pool_id2str(pool, pool->solvables[b].name));
+}
+
+static int
+expander_isignored(Expander *xp, Solvable *s, Id req)
+{
+ Pool *pool = xp->pool;
+ Id id = id2name(pool, req);
+ const char *n;
+
+ if (!xp->ignoreignore)
+ {
+ if (MAPTST(&xp->ignored, id))
+ return 1;
+ if (MAPTST(&xp->ignoredx, id))
+ {
+ Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, s->name), ":", pool_id2str(pool, id)), 0);
+ if (xid && MAPTST(&xp->ignored, xid))
+ return 1;
+ }
+ }
+ n = pool_id2str(pool, id);
+ if (!strncmp(n, "rpmlib(", 7))
+ {
+ MAPEXP(&xp->ignored, id);
+ MAPSET(&xp->ignored, id);
+ return 1;
+ }
+ if (*n == '/')
+ {
+ if (!xp->havefileprovides || pool->whatprovides[id] <= 1)
+ {
+ MAPEXP(&xp->ignored, id);
+ MAPSET(&xp->ignored, id);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+expander_to_cplxblks(ExpanderCtx *xpctx, Id p, Id dep, int deptype, Id *ptr)
+{
+ int blkoff = xpctx->cplxblks.count;
+ queue_push(&xpctx->cplxblks, p);
+ queue_push(&xpctx->cplxblks, dep);
+ queue_push(&xpctx->cplxblks, deptype);
+ for (;;)
+ {
+ Id pp = *ptr++;
+ queue_push(&xpctx->cplxblks, pp);
+ if (!pp)
+ break;
+ }
+ return blkoff;
+}
+
+static int
+expander_check_cplxblock(ExpanderCtx *xpctx, Id p, Id dep, int deptype, Id *ptr, int blkoff)
+{
+ Pool *pool = xpctx->pool;
+ int posn = 0, posi = 0, negn = 0, negi = 0;
+ Id pp, *ptr2 = ptr;
+ Id lastcon = 0;
+
+ while ((pp = *ptr2++) != 0)
+ {
+ if (pp > 0)
+ {
+ posn++;
+ if (MAPTST(&xpctx->installed, pp))
+ posi++;
+ }
+ else
+ {
+ if (p == -pp)
+ continue; /* ignore redundant self-entry */
+ negn++;
+ if (MAPTST(&xpctx->installed, -pp))
+ negi++;
+ else
+ lastcon = -pp;
+ }
+ }
+#if 0
+ printf("expander_check_cplxblock pos: %d,%d neg: %d,%d\n", posn, posi, negn, negi);
+#endif
+ if (posi)
+ return -1;
+ if (!posn && deptype == DEPTYPE_RECOMMENDS)
+ return -1;
+ if (negi == negn)
+ {
+ /* all neg installed */
+ if (posn)
+ {
+ /* posn > 0 and all neg installed, add to todo */
+ if (blkoff < 0)
+ blkoff = expander_to_cplxblks(xpctx, p, dep, deptype, ptr);
+#if 0
+ printf("put on todo, blkoff = %d\n", blkoff);
+#endif
+ queue_push2(&xpctx->todo, MAKECPLX(pool, blkoff), p);
+ }
+ else
+ {
+ /* no posn, conflict */
+ for (ptr2 = ptr; (pp = *ptr2++) != 0; )
+ {
+ if (p == -pp)
+ continue; /* ignore redundant self-entry */
+ if (deptype == DEPTYPE_REQUIRES)
+ {
+ /* do not report a requires as conflicts */
+ queue_push(&xpctx->errors, ERROR_NOPROVIDER);
+ queue_push2(&xpctx->errors, dep, p);
+ break;
+ }
+ queue_push(&xpctx->errors, ERROR_CONFLICT);
+ queue_push2(&xpctx->errors, p, -pp);
+ }
+ }
+ return -1;
+ }
+ else if (!posn && negn && negi == negn - 1)
+ {
+ /* add conflict */
+#if 0
+ printf("add conflict %d %d\n", lastcon, p);
+#endif
+ MAPEXP(&xpctx->conflicts, pool->nsolvables);
+ MAPSET(&xpctx->conflicts, lastcon);
+ if (p)
+ queue_push2(&xpctx->conflictsinfo, lastcon, p); /* always do this for rich deps */
+ return -1;
+ }
+ else
+ {
+#ifdef DEBUG_COND
+ printf("put/stay on cond queue, blkoff = %d\n", blkoff);
+#endif
+ /* either posn > 0 and 1 neg not installed or more than 1 neg not installed */
+ if (blkoff < 0)
+ blkoff = expander_to_cplxblks(xpctx, p, dep, deptype, ptr);
+ return blkoff;
+ }
+}
+
+static void
+expander_installed_complexdep(ExpanderCtx *xpctx, Id p, Id dep, int deptype)
+{
+ Queue *cplxq = &xpctx->cplxq;
+ int r, i, start = cplxq->count, blkoff;
+
+#if 0
+ printf("expander_installed_complexdep %s type %d\n", pool_dep2str(xpctx->pool, dep), deptype);
+#endif
+ if (deptype == DEPTYPE_CONFLICTS)
+ {
+ r = normalize_dep(xpctx, dep, cplxq, CPLXDEPS_TODNF);
+ r = invert_depblocks(xpctx, cplxq, start, r);
+ }
+ else
+ r = normalize_dep(xpctx, dep, cplxq, 0);
+#if 0
+ print_depblocks(xpctx, cplxq, start, r);
+#endif
+ if (r == 1)
+ return;
+ if (r == 0)
+ {
+ if (deptype == DEPTYPE_CONFLICTS)
+ {
+ queue_push(&xpctx->errors, ERROR_ALLCONFLICT);
+ queue_push2(&xpctx->errors, dep, p);
+ }
+ else if (deptype != DEPTYPE_RECOMMENDS)
+ {
+ queue_push(&xpctx->errors, ERROR_NOPROVIDER);
+ queue_push2(&xpctx->errors, dep, p);
+ }
+ return;
+ }
+ while (start < cplxq->count)
+ {
+ /* find end */
+ for (i = start; cplxq->elements[i] != 0; i++)
+ ;
+ blkoff = expander_check_cplxblock(xpctx, p, dep, deptype, cplxq->elements + start, -1);
+ if (blkoff >= 0)
+ {
+ Pool *pool = xpctx->pool;
+ Id p;
+ MAPEXP(&xpctx->todo_condmap, pool->nsolvables);
+ for (i = start; (p = cplxq->elements[i]) != 0; i++)
+ if (p < 0)
+ MAPSET(&xpctx->todo_condmap, -p);
+ queue_push(&xpctx->todo_cond, blkoff);
+ }
+ start = i + 1;
+ }
+ queue_truncate(cplxq, start);
+}
+
+static int
+expander_checkconflicts_complexdep(ExpanderCtx *xpctx, Id p, Id dep, int deptype, int recorderrors)
+{
+ Queue *cplxq = &xpctx->cplxq;
+ int r, i, start = cplxq->count;
+ Id pp;
+ int ret = 0;
+
+#if 0
+ printf("expander_checkconflicts_complexdep %s type %d\n", pool_dep2str(xpctx->pool, dep), deptype);
+#endif
+ if (deptype == DEPTYPE_CONFLICTS)
+ {
+ r = normalize_dep(xpctx, dep, cplxq, CPLXDEPS_TODNF);
+ r = invert_depblocks(xpctx, cplxq, start, r);
+ }
+ else
+ r = normalize_dep(xpctx, dep, cplxq, 0);
+#if 0
+ print_depblocks(xpctx, cplxq, start, r);
+#endif
+ /* r == 0: conflict with everything. Ignore here, pick error up when package gets installed */
+ if (r == 0 || r == 1)
+ return 0;
+ while (start < cplxq->count)
+ {
+ for (i = start; (pp = cplxq->elements[i]) != 0; i++)
+ if (pp > 0 || (pp < 0 && !MAPTST(&xpctx->installed, -pp)))
+ break;
+ if (pp == 0)
+ {
+ /* no pos and all neg installed -> conflict */
+ for (i = start; (pp = cplxq->elements[i]) != 0; i++)
+ {
+ pp = -cplxq->elements[i];
+ if (recorderrors)
+ {
+ queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT : ERROR_PROVIDERINFO);
+ queue_push2(&xpctx->errors, p, pp);
+ }
+ else if (xpctx->xp->debug)
+ {
+ Pool *pool = xpctx->pool;
+ expander_dbg(xpctx->xp, "ignoring provider %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, pp));
+ }
+ ret = ret ? 1 : pp;
+ }
+ }
+ for (; cplxq->elements[i] != 0; i++)
+ ;
+ start = i + 1;
+ }
+ queue_truncate(cplxq, start);
+ return ret;
+}
+
+static void
+updateconflictsinfo(ExpanderCtx *xpctx)
+{
+ int i;
+ Pool *pool = xpctx->pool;
+ Queue *out = xpctx->out;
+ Queue *conflictsinfo = &xpctx->conflictsinfo;
+
+ if (xpctx->ignoreconflicts)
+ return;
+ for (i = xpctx->cidone; i < out->count; i++)
+ {
+ Id p, p2, pp2;
+ Id con, *conp;
+ Solvable *s;
+ p = out->elements[i];
+ s = pool->solvables + p;
+ /* keep in sync with expander_installed! */
+ if (s->conflicts)
+ {
+ conp = s->repo->idarraydata + s->conflicts;
+ while ((con = *conp++) != 0)
+ {
+ if (pool_is_complex_dep(pool, con))
+ continue; /* already pushed */
+ FOR_PROVIDES(p2, pp2, con)
+ {
+ if (p2 == p)
+ continue;
+ queue_push2(conflictsinfo, p2, p);
+ }
+ }
+ }
+ if (s->obsoletes)
+ {
conp = s->repo->idarraydata + s->obsoletes;
while ((con = *conp++) != 0)
{
- Id p2, pp2;
FOR_PROVIDES(p2, pp2, con)
{
if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
continue;
- MAPEXP(conflicts, pool->nsolvables);
- MAPSET(conflicts, p2);
- if (xp->debug)
- queue_push2(conflictsinfo, p2, -p);
+ queue_push2(conflictsinfo, p2, -p);
}
}
}
- if (xp->debug)
- *cidone = out->count;
}
+ xpctx->cidone = out->count;
}
-static inline int
-expander_checkconflicts(Expander *xp, Id p, Map *installed, Id *conflicts, int isobsoletes)
+static int
+findconflictsinfo(ExpanderCtx *xpctx, Id p, int recorderrors)
{
- Pool *pool = xp->pool;
- Id con, p2, pp2;
+ Queue *conflictsinfo = &xpctx->conflictsinfo;
+ int i, ret = 0;
- if (xp->ignoreconflicts)
- return 0;
- while ((con = *conflicts++) != 0)
+ if (xpctx->cidone < xpctx->out->count)
+ updateconflictsinfo(xpctx);
+
+ for (i = 0; i < conflictsinfo->count; i++)
+ if (conflictsinfo->elements[i] == p)
+ {
+ ret = conflictsinfo->elements[i + 1];
+ if (recorderrors)
+ {
+ queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT2 : ERROR_PROVIDERINFO2);
+ queue_push2(&xpctx->errors, p, ret);
+ }
+ else if (xpctx->xp->debug)
+ {
+ Pool *pool = xpctx->pool;
+ expander_dbg(xpctx->xp, "ignoring provider %s because installed %s %s it\n", pool_solvid2str(pool, p), pool_solvid2str(pool, ret > 0 ? ret : -ret), ret > 0 ? "conflicts with" : "obsoletes");
+ }
+ }
+ if (!ret)
{
- FOR_PROVIDES(p2, pp2, con)
+ /* conflict from our job, i.e. a !xxx dep */
+ if (recorderrors)
{
- if (p == p2)
- continue;
- if (isobsoletes && !pool_match_nevr(pool, pool->solvables + p2, con))
- continue;
- if (MAPTST(installed, p2))
- return p2;
+ queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT2 : ERROR_PROVIDERINFO2);
+ queue_push2(&xpctx->errors, p, 0);
+ }
+ else if (xpctx->xp->debug)
+ {
+ Pool *pool = xpctx->pool;
+ expander_dbg(xpctx->xp, "ignoring conflicted provider %s\n", pool_solvid2str(pool, p));
}
}
- return 0;
+ return ret;
}
+
static void
-expander_updateconflictsinfo(Expander *xp, Queue *conflictsinfo, int *cidone, Queue *out)
+recheck_conddeps(ExpanderCtx *xpctx)
{
- Pool *pool = xp->pool;
int i;
- if (xp->ignoreconflicts)
- return;
- for (i = *cidone; i < out->count; i++)
+ for (i = 0; i < xpctx->todo_cond.count; i++)
+ {
+ int blkoff = xpctx->todo_cond.elements[i];
+#ifdef DEBUG_COND
+ printf("todo_cond %d\n", blkoff);
+#endif
+ Id *ptr = xpctx->cplxblks.elements + blkoff;
+ if (expander_check_cplxblock(xpctx, ptr[0], ptr[1], ptr[2], ptr + 3, blkoff) < 0)
+ {
+#ifdef DEBUG_COND
+ printf("remove no longer needed cond entry\n");
+#endif
+ queue_delete(&xpctx->todo_cond, i);
+ i--;
+ }
+ }
+}
+
+/* install a single package */
+static void
+expander_installed(ExpanderCtx *xpctx, Id p)
+{
+ Pool *pool = xpctx->pool;
+ Expander *xp = xpctx->xp;
+ Solvable *s = pool->solvables + p;
+ Id req, *reqp, con, *conp;
+
+#if 0
+printf("expander_installed %s\n", pool_solvid2str(pool, p));
+#endif
+ MAPSET(&xpctx->installed, p);
+ queue_push(xpctx->out, p);
+
+ if (xpctx->conflicts.size && MAPTST(&xpctx->conflicts, p))
+ findconflictsinfo(xpctx, p, 2);
+
+ /* add synthetic conflicts from the project config */
+ if (MAPTST(&xp->conflicts, s->name))
+ {
+ int i;
+ for (i = 0; i < xp->conflictsq.count; i++)
+ {
+ Id p2, pp2;
+ Id id = xp->conflictsq.elements[i];
+ if (id != s->name)
+ continue;
+ id = xp->conflictsq.elements[i ^ 1];
+ FOR_PROVIDES(p2, pp2, id)
+ {
+ if (pool->solvables[p2].name != id)
+ continue;
+ if (MAPTST(&xpctx->installed, p2))
+ {
+ queue_push(&xpctx->errors, ERROR_CONFLICT);
+ queue_push2(&xpctx->errors, p, p2);
+ continue;
+ }
+ MAPEXP(&xpctx->conflicts, pool->nsolvables);
+ MAPSET(&xpctx->conflicts, p2);
+ queue_push2(&xpctx->conflictsinfo, p2, p);
+ }
+ }
+ }
+
+ if (s->requires)
+ {
+ reqp = s->repo->idarraydata + s->requires;
+ while ((req = *reqp++) != 0)
+ {
+ if (req == SOLVABLE_PREREQMARKER)
+ continue;
+ if (ISRELDEP(req) && GETRELDEP(pool, req)->flags == REL_ERROR)
+ {
+ queue_push(&xpctx->errors, ERROR_BADDEPENDENCY);
+ queue_push2(&xpctx->errors, GETRELDEP(pool, req)->evr, p);
+ continue;
+ }
+ if (pool_is_complex_dep(pool, req))
+ {
+ xpctx->ignore_s = s;
+ expander_installed_complexdep(xpctx, p, req, DEPTYPE_REQUIRES);
+ xpctx->ignore_s = 0;
+ continue;
+ }
+ if (expander_isignored(xp, s, req))
+ continue;
+ queue_push2(&xpctx->todo, req, p);
+ }
+ }
+ if (!xpctx->ignoreconflicts)
{
- Id p, p2, pp2;
- Id con, *conp;
- Solvable *s;
- p = out->elements[i];
- s = pool->solvables + p;
- /* keep in sync with expander_installed! */
if (s->conflicts)
{
conp = s->repo->idarraydata + s->conflicts;
while ((con = *conp++) != 0)
{
+ Id p2, pp2;
+ if (ISRELDEP(con) && GETRELDEP(pool, con)->flags == REL_ERROR)
+ {
+ queue_push(&xpctx->errors, ERROR_BADDEPENDENCY);
+ queue_push2(&xpctx->errors, GETRELDEP(pool, con)->evr, p);
+ continue;
+ }
+ if (pool_is_complex_dep(pool, con))
+ {
+ expander_installed_complexdep(xpctx, p, con, DEPTYPE_CONFLICTS);
+ continue;
+ }
FOR_PROVIDES(p2, pp2, con)
{
if (p2 == p)
continue;
- queue_push2(conflictsinfo, p2, p);
+ if (MAPTST(&xpctx->installed, p2))
+ {
+ queue_push(&xpctx->errors, ERROR_CONFLICT);
+ queue_push2(&xpctx->errors, p, p2);
+ continue;
+ }
+ MAPEXP(&xpctx->conflicts, pool->nsolvables);
+ MAPSET(&xpctx->conflicts, p2);
+ if (xp->debug)
+ queue_push2(&xpctx->conflictsinfo, p2, p);
}
}
}
conp = s->repo->idarraydata + s->obsoletes;
while ((con = *conp++) != 0)
{
+ Id p2, pp2;
FOR_PROVIDES(p2, pp2, con)
{
if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
continue;
- queue_push2(conflictsinfo, p2, -p);
+ if (MAPTST(&xpctx->installed, p2))
+ {
+ queue_push(&xpctx->errors, ERROR_CONFLICT);
+ queue_push2(&xpctx->errors, p, -p2);
+ continue;
+ }
+ MAPEXP(&xpctx->conflicts, pool->nsolvables);
+ MAPSET(&xpctx->conflicts, p2);
+ if (xp->debug)
+ queue_push2(&xpctx->conflictsinfo, p2, -p);
}
}
}
+ if (xp->debug)
+ xpctx->cidone = xpctx->out->count;
}
- *cidone = out->count;
+ if (xpctx->todo_condmap.size && MAPTST(&xpctx->todo_condmap, p))
+ recheck_conddeps(xpctx);
}
+/* same as expander_installed, but install multiple packages
+ * in one block */
static void
-expander_updaterecommendedmap(Expander *xp, Map *recommended, int *recdone, Queue *out)
+expander_installed_multiple(ExpanderCtx *xpctx, Queue *toinstall)
{
- Pool *pool = xp->pool;
+ int i, j, havecond = 0;
+
+ /* unify */
+ for (i = j = 0; i < toinstall->count; i++)
+ {
+ Id p = toinstall->elements[i];
+ if (MAPTST(&xpctx->installed, p))
+ continue; /* already seen */
+ MAPSET(&xpctx->installed, p);
+ toinstall->elements[j++] = p;
+ if (xpctx->todo_condmap.size && MAPTST(&xpctx->todo_condmap, p))
+ {
+ havecond = 1;
+ MAPCLR(&xpctx->todo_condmap, p); /* no longer needed */
+ }
+ }
+ queue_truncate(toinstall, j);
+
+ /* run conditionals first */
+ if (havecond)
+ recheck_conddeps(xpctx);
+
+ if (!xpctx->errors.count)
+ for (i = 0; i < toinstall->count; i++)
+ expander_installed(xpctx, toinstall->elements[i]);
+ queue_empty(toinstall);
+}
+
+static int
+expander_checkconflicts(ExpanderCtx *xpctx, Id p, Id *conflicts, int isobsoletes, int recorderrors)
+{
+ Map *installed = &xpctx->installed;
+ Pool *pool = xpctx->pool;
+ Id con, p2, pp2;
+ int ret = 0;
+
+ if (xpctx->ignoreconflicts)
+ return 0;
+ while ((con = *conflicts++) != 0)
+ {
+ if (!isobsoletes && pool_is_complex_dep(pool, con))
+ {
+ p2 = expander_checkconflicts_complexdep(xpctx, p, con, DEPTYPE_CONFLICTS, recorderrors);
+ ret = ret ? 1 : p2;
+ continue;
+ }
+ FOR_PROVIDES(p2, pp2, con)
+ {
+ if (p == p2)
+ continue;
+ if (isobsoletes && !pool_match_nevr(pool, pool->solvables + p2, con))
+ continue;
+ if (MAPTST(installed, p2))
+ {
+ if (recorderrors)
+ {
+ queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT : ERROR_PROVIDERINFO);
+ queue_push2(&xpctx->errors, p, isobsoletes ? -p2 : p2);
+ }
+ else if (xpctx->xp->debug)
+ {
+ if (isobsoletes)
+ expander_dbg(xpctx->xp, "ignoring provider %s because it obsoletes installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, p2));
+ else
+ expander_dbg(xpctx->xp, "ignoring provider %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, p2));
+ }
+ ret = ret ? 1 : p2;
+ }
+ }
+ }
+ return ret;
+}
+
+static void
+expander_updaterecommendedmap(ExpanderCtx *xpctx)
+{
+ Pool *pool = xpctx->pool;
+ Queue *out = xpctx->out;
+ Map *recommended = &xpctx->recommended;
int i;
Id p, pp, rec, *recp;
- for (i = *recdone; i < out->count; i++)
+ for (i = xpctx->recdone; i < out->count; i++)
{
Solvable *s;
s = pool->solvables + out->elements[i];
if (s->recommends)
- {
+ {
MAPEXP(recommended, pool->nsolvables);
for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; )
- FOR_PROVIDES(p, pp, rec)
- MAPSET(recommended, p);
- }
+ FOR_PROVIDES(p, pp, rec)
+ MAPSET(recommended, p);
+ }
}
- *recdone = out->count;
+ xpctx->recdone = out->count;
}
-static inline int
-findconflictsinfo(Queue *conflictsinfo, Id p)
+static int
+expander_dep_fulfilled(ExpanderCtx *xpctx, Id dep)
{
- int i;
+ Pool *pool = xpctx->pool;
+ Id p, pp;
- for (i = 0; i < conflictsinfo->count; i++)
- if (conflictsinfo->elements[i] == p)
- return conflictsinfo->elements[i + 1];
+ if (ISRELDEP(dep))
+ {
+ Reldep *rd = GETRELDEP(pool, dep);
+ if (rd->flags == REL_COND)
+ {
+ if (ISRELDEP(rd->evr))
+ {
+ Reldep *rd2 = GETRELDEP(pool, rd->evr);
+ if (rd2->flags == REL_ELSE)
+ {
+ if (expander_dep_fulfilled(xpctx, rd2->name))
+ return expander_dep_fulfilled(xpctx, rd->name);
+ return expander_dep_fulfilled(xpctx, rd2->evr);
+ }
+ }
+ if (expander_dep_fulfilled(xpctx, rd->name)) /* A OR ~B */
+ return 1;
+ return !expander_dep_fulfilled(xpctx, rd->evr);
+ }
+ if (rd->flags == REL_UNLESS)
+ {
+ if (ISRELDEP(rd->evr))
+ {
+ Reldep *rd2 = GETRELDEP(pool, rd->evr);
+ if (rd2->flags == REL_ELSE)
+ {
+ if (!expander_dep_fulfilled(xpctx, rd2->name))
+ return expander_dep_fulfilled(xpctx, rd->name);
+ return expander_dep_fulfilled(xpctx, rd2->evr);
+ }
+ }
+ if (!expander_dep_fulfilled(xpctx, rd->name)) /* A AND ~B */
+ return 0;
+ return !expander_dep_fulfilled(xpctx, rd->evr);
+ }
+ if (rd->flags == REL_AND)
+ {
+ if (!expander_dep_fulfilled(xpctx, rd->name))
+ return 0;
+ return expander_dep_fulfilled(xpctx, rd->evr);
+ }
+ if (rd->flags == REL_OR)
+ {
+ if (expander_dep_fulfilled(xpctx, rd->name))
+ return 1;
+ return expander_dep_fulfilled(xpctx, rd->evr);
+ }
+ }
+ FOR_PROVIDES(p, pp, dep)
+ {
+ if (MAPTST(&xpctx->installed, p))
+ return 1;
+ }
return 0;
}
-#define ERROR_NOPROVIDER 1
-#define ERROR_CHOICE 2
-#define ERROR_CONFLICTINGPROVIDER 3
-#define ERROR_CONFLICTINGPROVIDERS 4
-#define ERROR_PROVIDERINFO 5
-#define ERROR_PROVIDERINFO2 6
+static int
+prune_neg_prefers(ExpanderCtx *xpctx, Id who, Id *e, int n)
+{
+ Expander *xp = xpctx->xp;
+ Pool *pool = xpctx->pool;
+ Id whon = who ? pool->solvables[who].name : 0;
+ int i, j;
+ for (i = j = 0; i < n; i++)
+ {
+ Id p = e[i];
+ Id pn = pool->solvables[p].name;
+ if (MAPTST(&xp->preferneg, pn))
+ continue;
+ if (who && MAPTST(&xp->prefernegx, pn))
+ {
+ Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
+ if (xid && MAPTST(&xp->preferneg, xid))
+ continue;
+ }
+ e[j++] = p;
+ }
+ return j ? j : n;
+}
+
+static int
+prune_pos_prefers(ExpanderCtx *xpctx, Id who, Id *e, int n, int domulti)
+{
+ Expander *xp = xpctx->xp;
+ Queue *pruneq = &xpctx->pruneq;
+ Pool *pool = xpctx->pool;
+ Id whon = who ? pool->solvables[who].name : 0;
+ int i, j;
+
+ if (pruneq->count)
+ queue_empty(pruneq);
+ for (i = j = 0; i < n; i++)
+ {
+ Id p = e[i];
+ Id pn = pool->solvables[p].name;
+ if (MAPTST(&xp->preferpos, pn))
+ queue_push2(pruneq, pn, p);
+ else if (who && MAPTST(&xp->preferposx, pn))
+ {
+ Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
+ if (xid && MAPTST(&xp->preferpos, xid))
+ queue_push2(pruneq, xid, p);
+ }
+ }
+ if (!pruneq->count)
+ return n;
+ if (pruneq->count > 2)
+ {
+ if (!domulti)
+ return n;
+ /* pos prefers are ordered, the first one wins */
+ for (i = 0; i < xp->preferposq.count; i++)
+ {
+ Id xid = xp->preferposq.elements[i];
+ for (j = 0; j < pruneq->count; j += 2)
+ if (pruneq->elements[j] == xid)
+ {
+ e[0] = pruneq->elements[j + 1];
+ return 1;
+ }
+ }
+ }
+ e[0] = pruneq->elements[1]; /* simple case, just one prefer */
+ return 1;
+}
+
+static int
+prune_or_dep(ExpanderCtx *xpctx, Id dep, Id *e, int n)
+{
+ Pool *pool = xpctx->pool;
+ int i, j;
+ Id p, pp;
+
+ for (;;)
+ {
+ Reldep *rd = 0;
+ if (ISRELDEP(dep))
+ {
+ rd = GETRELDEP(pool, dep);
+ if (rd->flags != REL_OR)
+ rd = 0;
+ }
+ if (rd)
+ dep = rd->name;
+ i = j = 0;
+ /* both sets are ordered */
+ FOR_PROVIDES(p, pp, dep)
+ {
+ if (p < e[i])
+ continue;
+ while (i < n && p > e[i])
+ i++;
+ if (i == n)
+ break;
+ if (p == e[i])
+ e[j++] = p;
+ }
+ if (j)
+ return j;
+ if (rd)
+ dep = rd->evr;
+ else
+ break;
+ }
+ return n;
+}
+
+static int
+prune_supplemented(ExpanderCtx *xpctx, Id *e, int n)
+{
+ Pool *pool = xpctx->pool;
+ int i, j;
+ Id sup, *supp;
+
+ for (i = j = 0; i < n; i++)
+ {
+ Id p = e[i];
+ Solvable *s = pool->solvables + p;
+ if (!s->supplements)
+ continue;
+ supp = s->repo->idarraydata + s->supplements;
+ while ((sup = *supp++) != 0)
+ if (expander_dep_fulfilled(xpctx, sup))
+ break;
+ if (sup)
+ e[j++] = p;
+ }
+ return j ? j : n;
+}
+
+static void
+add_recommended_packages(ExpanderCtx *xpctx, Solvable *s)
+{
+ Pool *pool = xpctx->pool;
+ Id p, pp, rec, *recp;
+ for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; )
+ {
+ int haveone = 0;
+ if (pool_is_complex_dep(pool, rec))
+ {
+ expander_installed_complexdep(xpctx, s - pool->solvables, rec, DEPTYPE_RECOMMENDS);
+ continue;
+ }
+ FOR_PROVIDES(p, pp, rec)
+ {
+ if (MAPTST(&xpctx->installed, p))
+ break;
+ if (haveone)
+ continue;
+ if (xpctx->conflicts.size && MAPTST(&xpctx->conflicts, p))
+ continue;
+ if (pool->solvables[p].conflicts && expander_checkconflicts(xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 0) != 0)
+ continue;
+ if (pool->solvables[p].obsoletes && expander_checkconflicts(xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 0) != 0)
+ continue;
+ haveone = 1;
+ }
+ if (p)
+ continue; /* already fulfilled */
+ if (haveone)
+ queue_push2(&xpctx->todo, rec, s - pool->solvables);
+ }
+}
+
+static void
+expander_growmaps(Expander *xp)
+{
+ Pool *pool = xp->pool;
+ MAPEXP(&xp->ignored, pool->ss.nstrings);
+ MAPEXP(&xp->ignoredx, pool->ss.nstrings);
+ MAPEXP(&xp->preferpos, pool->ss.nstrings);
+ MAPEXP(&xp->preferposx, pool->ss.nstrings);
+ MAPEXP(&xp->preferneg, pool->ss.nstrings);
+ MAPEXP(&xp->prefernegx, pool->ss.nstrings);
+ MAPEXP(&xp->conflicts, pool->ss.nstrings);
+}
+
+static Id
+str2id_dup(Pool *pool, const char *str)
+{
+ char buf[256];
+ size_t l = strlen(str);
+ if (l < 256) {
+ memcpy(buf, str, l + 1);
+ return pool_str2id(pool, buf, 1);
+ } else {
+ return pool_str2id(pool, pool_tmpjoin(pool, str, 0, 0), 1);
+ }
+}
+
+static void
+add_noproviderinfo(ExpanderCtx *xpctx, Id dep, Id who)
+{
+ Pool *pool = xpctx->pool;
+ Reldep *rd, *prd;
+ Id p, pp, prov, *provp;
+ int nprovinfo;
+ if (xpctx->xp->debug)
+ {
+ if (who)
+ expander_dbg(xpctx->xp, "nothing provides %s needed by %s\n", pool_dep2str(pool, dep), expander_solvid2str(xpctx->xp, who));
+ else
+ expander_dbg(xpctx->xp, "nothing provides %s\n", pool_dep2str(pool, dep));
+ }
+ if (!ISRELDEP(dep))
+ return;
+ rd = GETRELDEP(pool, dep);
+ if (rd->flags >= 8 || ISRELDEP(rd->name) || ISRELDEP(rd->evr))
+ return;
+ nprovinfo = 0;
+ FOR_PROVIDES(p, pp, rd->name)
+ {
+ Solvable *s = pool->solvables + p;
+ if (!s->repo || !s->provides)
+ continue;
+ for (provp = s->repo->idarraydata + s->provides; (prov = *provp++) != 0; )
+ {
+ if (!ISRELDEP(prov))
+ continue;
+ prd = GETRELDEP(pool, prov);
+ if (prd->name != rd->name || ISRELDEP(prd->evr))
+ continue;
+ queue_push(&xpctx->errors, ERROR_NOPROVIDERINFO);
+ if (prd->name == s->name && prd->evr == s->evr)
+ {
+ if (xpctx->xp->debug)
+ expander_dbg(xpctx->xp, "%s has version %s\n", expander_solvid2str(xpctx->xp, p), pool_id2str(pool, prd->evr));
+ queue_push2(&xpctx->errors, prd->evr, 0);
+ }
+ else
+ {
+ if (xpctx->xp->debug)
+ expander_dbg(xpctx->xp, "%s provides version %s\n", expander_solvid2str(xpctx->xp, p), pool_id2str(pool, prd->evr));
+ queue_push2(&xpctx->errors, prd->evr, p);
+ }
+ if (++nprovinfo >= 4)
+ return; /* only show the first 4 providers */
+ }
+ }
+}
-int
-expander_expand(Expander *xp, Queue *in, Queue *out, Queue *inconfl)
+static int
+expander_expand(Expander *xp, Queue *in, Queue *indep, Queue *out, Queue *ignoreq, int options)
{
+ ExpanderCtx xpctx;
Pool *pool = xp->pool;
- Queue todo, errors, cerrors, qq, posfoundq;
- Map installed;
- Map conflicts;
- Map recommended;
- Queue conflictsinfo;
- int cidone;
- int recdone;
+ Queue toinstall;
+ Queue qq, choices;
Solvable *s;
Id q, p, pp;
- int i, j, nerrors, doamb, ambcnt;
- Id id, who, whon, pn;
- Id conflprov, conflprovpc;
- int haverecommended = 0;
- int haverecommended_done = 0;
-
- map_init(&installed, pool->nsolvables);
- map_init(&conflicts, 0);
- map_init(&recommended, 0);
- queue_init(&conflictsinfo);
- queue_init(&todo);
+ int i, j, nerrors;
+ int ti, tj, tc;
+ Id todoid, id, who, whon;
+ Id conflprovpc;
+ int pass;
+ Queue revertignore;
+ int oldignoreignore = xp->ignoreignore;
+ Map oldignored, oldignoredx;
+ int ignoremapssaved = 0;
+ int dorecstart = 0;
+
+ memset(&xpctx, 0, sizeof(xpctx));
+ xpctx.xp = xp;
+ xpctx.pool = pool;
+ xpctx.out = out;
+ xpctx.ignoreignore = options & EXPANDER_OPTION_IGNOREIGNORE ? 1 : xp->ignoreignore;
+ xpctx.ignoreconflicts = options & EXPANDER_OPTION_IGNORECONFLICTS ? 1 : xp->ignoreconflicts;
+ xpctx.userecommendsforchoices = options & EXPANDER_OPTION_USERECOMMENDSFORCHOICES ? 1 : xp->userecommendsforchoices;
+ xpctx.usesupplementsforchoices = options & EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES ? 1 : xp->usesupplementsforchoices;
+ xpctx.dorecommends = options & EXPANDER_OPTION_DORECOMMENDS ? 1 : xp->dorecommends;
+ xpctx.dosupplements = options & EXPANDER_OPTION_DOSUPPLEMENTS ? 1 : xp->dosupplements;
+ map_init(&xpctx.installed, pool->nsolvables);
+ map_init(&xpctx.conflicts, 0);
+ map_init(&xpctx.recommended, 0);
+ queue_init(&xpctx.conflictsinfo);
+ queue_init(&xpctx.todo);
+ queue_init(&xpctx.todo_cond);
+ map_init(&xpctx.todo_condmap, 0);
+ queue_init(&xpctx.errors);
+ queue_init(&xpctx.cplxq);
+ queue_init(&xpctx.cplxblks);
+ queue_init(&xpctx.pruneq);
+
+ queue_init(&toinstall);
queue_init(&qq);
- queue_init(&errors);
- queue_init(&cerrors);
- queue_init(&posfoundq);
+ queue_init(&choices);
+ queue_init(&revertignore);
queue_empty(out);
- cidone = 0;
- recdone = 0;
- if (inconfl)
+
+ /* process ignored. hack: we mess with the ignore config in xp */
+ xp->ignoreignore = 0;
+ if (xpctx.ignoreignore && ignoreq->count)
{
- for (i = 0; i < inconfl->count; i += 2)
+ /* bad: have direct ignores and we need to zero the project config ignores */
+ oldignored = xp->ignored;
+ oldignoredx = xp->ignoredx;
+ ignoremapssaved = 1;
+ /* clear project config maps */
+ memset(&xp->ignored, 0, sizeof(xp->ignored));
+ memset(&xp->ignoredx, 0, sizeof(xp->ignoredx));
+ }
+ if (ignoreq->count)
+ {
+ /* mix direct ignores with ignores from project config */
+ for (i = 0; i < ignoreq->count; i++)
{
- Id con = inconfl->elements[i];
- FOR_PROVIDES(p, pp, con)
+ const char *ss;
+ id = ignoreq->elements[i];
+ MAPEXP(&xp->ignored, id);
+ if (MAPTST(&xp->ignored, id))
+ continue;
+ MAPSET(&xp->ignored, id);
+ queue_push(&revertignore, id);
+ if ((ss = strchr(pool_id2str(pool, id), ':')) != 0)
{
- if (inconfl->elements[i + 1] && !pool_match_nevr(pool, pool->solvables + p, con))
+ id = str2id_dup(pool, ss + 1);
+ MAPEXP(&xp->ignoredx, id);
+ if (MAPTST(&xp->ignoredx, id))
continue;
- MAPEXP(&conflicts, pool->nsolvables);
- MAPSET(&conflicts, p);
+ MAPSET(&xp->ignoredx, id);
+ queue_push(&revertignore, -id);
}
}
}
- /* do direct expands */
+ else if (xpctx.ignoreignore)
+ {
+ /* no direct ignores, ignore project config ignores.
+ * easy: just disable ignore processing */
+ xp->ignoreignore = 1;
+ }
+
+ /* grow maps to make bit tests cheaper */
+ expander_growmaps(xp);
+
+ /* process standard dependencies */
+ if (indep)
+ {
+ for (i = 0; i < indep->count; i += 2)
+ {
+ int deptype = indep->elements[i];
+ Id dep = indep->elements[i + 1];
+ if (ISRELDEP(dep) && GETRELDEP(pool, dep)->flags == REL_ERROR)
+ {
+ queue_push(&xpctx.errors, ERROR_BADDEPENDENCY);
+ queue_push2(&xpctx.errors, GETRELDEP(pool, dep)->evr, 0);
+ continue;
+ }
+ if ((deptype == DEPTYPE_REQUIRES || deptype == DEPTYPE_CONFLICTS) && pool_is_complex_dep(pool, dep))
+ {
+ expander_installed_complexdep(&xpctx, 0, dep, deptype);
+ continue;
+ }
+ if (deptype == DEPTYPE_REQUIRES)
+ {
+ queue_push2(&xpctx.todo, dep, 0);
+ }
+ else if (deptype == DEPTYPE_CONFLICTS || deptype == DEPTYPE_OBSOLETES)
+ {
+ FOR_PROVIDES(p, pp, dep)
+ {
+ if (deptype == DEPTYPE_OBSOLETES && !pool_match_nevr(pool, pool->solvables + p, dep))
+ continue;
+ MAPEXP(&xpctx.conflicts, pool->nsolvables);
+ MAPSET(&xpctx.conflicts, p);
+ }
+ }
+ }
+ }
+ /* process direct dependencies */
for (i = 0; i < in->count; i++)
{
id = in->elements[i];
- if (id == expander_directdepsend)
+ if (ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_ERROR)
{
- for (i = i + 1; i < in->count; i++)
- if (in->elements[i] != expander_directdepsend)
- queue_push2(&todo, in->elements[i], 0);
- break;
+ queue_push(&xpctx.errors, ERROR_BADDEPENDENCY);
+ queue_push2(&xpctx.errors, GETRELDEP(pool, id)->evr, 0);
+ continue;
+ }
+ if (pool_is_complex_dep(pool, id))
+ {
+ expander_installed_complexdep(&xpctx, 0, id, DEPTYPE_REQUIRES);
+ continue;
}
q = 0;
FOR_PROVIDES(p, pp, id)
}
if (!q)
{
- /* unclear, resolve later */
- queue_push2(&todo, id, 0);
+ queue_push2(&xpctx.todo, id, 0); /* unclear, resolve later */
continue;
}
- if (MAPTST(&installed, q))
+ if (xp->debug)
+ expander_dbg(xp, "added %s because of %s (direct dep)\n", expander_solvid2name(xp, q), pool_dep2str(pool, id));
+ queue_push(&toinstall, q);
+ }
+
+ /* unify toinstall, check against conflicts */
+ for (i = 0; i < toinstall.count; i++)
+ {
+ p = toinstall.elements[i];
+ MAPSET(&xpctx.installed, p);
+ }
+ for (i = j = 0; i < toinstall.count; i++)
+ {
+ p = toinstall.elements[i];
+ if (!MAPTST(&xpctx.installed, p))
continue;
- if (conflicts.size && MAPTST(&conflicts, q))
- {
- queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
- queue_push2(&errors, id, 0);
- if (cidone < out->count)
- expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
- queue_push(&errors, ERROR_PROVIDERINFO2);
- queue_push2(&errors, q, findconflictsinfo(&conflictsinfo, q));
- continue;
- }
- if (pool->solvables[q].conflicts && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].conflicts, 0)) != 0)
+ MAPCLR(&xpctx.installed, p);
+ toinstall.elements[j++] = p;
+ }
+ queue_truncate(&toinstall, j);
+ if (xpctx.conflicts.size)
+ {
+ for (i = 0; i < toinstall.count; i++)
{
- queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
- queue_push2(&errors, id, 0);
- queue_push(&errors, ERROR_PROVIDERINFO);
- queue_push2(&errors, q, pp);
- continue;
+ p = toinstall.elements[i];
+ if (MAPTST(&xpctx.conflicts, p))
+ findconflictsinfo(&xpctx, p, 2);
}
- if (pool->solvables[q].obsoletes && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].obsoletes, 1)) != 0)
+ }
+
+ /* here is the big expansion loop */
+ pass = 0;
+ while (!xpctx.errors.count)
+ {
+ if (toinstall.count)
{
- queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
- queue_push2(&errors, id, 0);
- queue_push(&errors, ERROR_PROVIDERINFO);
- queue_push2(&errors, q, -pp);
+ expander_installed_multiple(&xpctx, &toinstall);
+ pass = 0;
continue;
}
- if (xp->debug)
- expander_dbg(xp, "added %s because of %s (direct dep)\n", expander_solvid2name(xp, q), pool_dep2str(pool, id));
- expander_installed(xp, q, &installed, &conflicts, &conflictsinfo, &cidone, out, &todo); /* unique match! */
- }
-
- doamb = 0;
- ambcnt = todo.count;
- while (todo.count)
- {
- id = queue_shift(&todo);
- who = queue_shift(&todo);
- if (ambcnt == 0)
- {
- if (doamb >= 2)
- break; /* amb pass had no progress, stop */
- doamb = xp->userecommendsforchoices ? doamb + 1 : 3;
- if (doamb == 1 && !haverecommended)
- {
- for (i = haverecommended_done; i < out->count; i++)
- if (pool->solvables[out->elements[i]].recommends)
- haverecommended = 1;
- haverecommended_done = out->count;
- if (!haverecommended)
- doamb = 3;
- }
- if (xp->debug)
- {
- if (doamb == 2)
- expander_dbg(xp, "now doing undecided dependencies with recommends\n");
- else
- expander_dbg(xp, "now doing undecided dependencies\n");
- }
- ambcnt = todo.count;
- }
- else
- ambcnt -= 2;
-// printf("todo %s %s ambcnt %d\n", pool_id2str(pool, pool->solvables[who].name), pool_dep2str(pool, id), ambcnt);
-// fflush(stdout);
- whon = who ? pool->solvables[who].name : 0;
- queue_empty(&qq);
- conflprov = 0;
- conflprovpc = 0;
- FOR_PROVIDES(p, pp, id)
+
+ if (!xpctx.todo.count)
{
- Id pc;
- if (MAPTST(&installed, p))
- break;
- if (who && !xp->ignoreignore)
+ /* almost finished. now do weak deps if requested */
+ pass = 0;
+ if (xpctx.dorecommends)
{
- Id pn = pool->solvables[p].name;
- if (MAPTST(&xp->ignored, pn))
- break;
- if (MAPTST(&xp->ignoredx, pn))
+ expander_dbg(xp, "--- now doing recommended packages\n");
+ for (; dorecstart < out->count; dorecstart++)
{
- Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
- if (xid && MAPTST(&xp->ignored, xid))
- break;
+ s = pool->solvables + out->elements[dorecstart];
+ if (s->recommends)
+ add_recommended_packages(&xpctx, s);
}
+ if (xpctx.todo.count)
+ continue;
}
- if (conflicts.size && MAPTST(&conflicts, p))
+ if (xpctx.dosupplements)
{
- if (xp->debug)
+ Id sup, *supp;
+ expander_dbg(xp, "--- now doing supplemented packages\n");
+ for (p = 1; p < pool->nsolvables; p++)
{
- Id pc = findconflictsinfo(&conflictsinfo, p);
- if (pc)
- expander_dbg(xp, "ignoring provider %s of %s because installed %s %s it\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc > 0 ? pc : -pc), pc > 0 ? "conflicts with" : "obsoletes");
- else
- expander_dbg(xp, "ignoring conflicted provider %s of %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id));
+ s = pool->solvables + p;
+ if (!s->supplements || !s->repo)
+ continue;
+ if (MAPTST(&xpctx.installed, p))
+ continue;
+ if (!pool_installable(pool, s))
+ continue;
+ if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p))
+ continue;
+ if (s->conflicts && expander_checkconflicts(&xpctx, p, s->repo->idarraydata + s->conflicts, 0, 0) != 0)
+ continue;
+ if (s->obsoletes && expander_checkconflicts(&xpctx, p, s->repo->idarraydata + s->obsoletes, 1, 0) != 0)
+ continue;
+ supp = s->repo->idarraydata + s->supplements;
+ while ((sup = *supp++) != 0)
+ if (expander_dep_fulfilled(&xpctx, sup))
+ break;
+ if (!sup)
+ continue;
+ expander_dbg(xp, "added %s because it supplements %s\n", expander_solvid2name(xp, p), pool_dep2str(pool, sup));
+ queue_push(&toinstall, p);
}
- conflprov = conflprov ? 1 : p;
- conflprovpc = 0;
- continue;
+ if (toinstall.count)
+ continue;
}
- if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0)
+ /* no new stuff to do, we're finished! */
+ break;
+ }
+
+ expander_dbg(xp, "--- now doing normal dependencies\n");
+
+ if (pass == 1)
+ queue_empty(&choices);
+
+ for (ti = tj = 0; ti < xpctx.todo.count; ti += 2)
+ {
+ int deptype = DEPTYPE_REQUIRES;
+ todoid = id = xpctx.todo.elements[ti];
+ who = xpctx.todo.elements[ti + 1];
+ if (!id) /* deleted entry? */
+ continue;
+ queue_empty(&qq);
+ if (ISCPLX(pool, id))
{
- expander_dbg(xp, "ignoring provider %s of %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc));
- conflprov = conflprov ? 1 : p;
- conflprovpc = pc;
- continue;
+ pp = GETCPLX(pool, id); /* p, dep, deptype, ids... */
+ id = xpctx.cplxblks.elements[pp + 1];
+ deptype = xpctx.cplxblks.elements[pp + 2];
+ pp += 3;
+ while ((p = xpctx.cplxblks.elements[pp++]))
+ if (p > 0)
+ queue_push(&qq, p);
}
- if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0)
+ else
{
- expander_dbg(xp, "ignoring provider %s of %s because it obsoletes installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc));
- conflprov = conflprov ? 1 : p;
- conflprovpc = -pc;
- continue;
+ FOR_PROVIDES(p, pp, id)
+ queue_push(&qq, p);
}
- queue_push(&qq, p);
- }
- if (p)
- continue;
- if (qq.count == 0)
- {
- if (!conflprov)
+
+ if (qq.count == 0)
{
- queue_push(&errors, ERROR_NOPROVIDER);
- queue_push2(&errors, id, who);
+ if (deptype == DEPTYPE_RECOMMENDS)
+ continue;
+ queue_push(&xpctx.errors, ERROR_NOPROVIDER);
+ queue_push2(&xpctx.errors, id, who);
+ add_noproviderinfo(&xpctx, id, who);
continue;
}
- /* more work for conflicts */
- if (conflprov != 1)
+
+ /* check installed and ignores */
+ whon = who ? pool->solvables[who].name : 0;
+ for (i = 0; i < qq.count; i++)
{
- /* nice, just one provider */
- queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
- queue_push2(&errors, id, who);
- if (!conflprovpc)
- {
- if (cidone < out->count)
- expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
- conflprovpc = findconflictsinfo(&conflictsinfo, conflprov);
- queue_push(&errors, ERROR_PROVIDERINFO2);
- queue_push2(&errors, conflprov, conflprovpc);
- }
- else
+ p = qq.elements[i];
+ if (MAPTST(&xpctx.installed, p))
+ break;
+ if (who && deptype == DEPTYPE_REQUIRES && !xp->ignoreignore)
{
- queue_push(&errors, ERROR_PROVIDERINFO);
- queue_push2(&errors, conflprov, conflprovpc);
+ Id pn = pool->solvables[p].name;
+ if (MAPTST(&xp->ignored, pn))
+ break;
+ if (MAPTST(&xp->ignoredx, pn))
+ {
+ Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
+ if (xid && MAPTST(&xp->ignored, xid))
+ break;
+ }
}
+ }
+ if (i < qq.count)
+ continue; /* ignored dependency or fulfilled */
+
+ if (pass == 0 && qq.count > 1)
+ {
+ xpctx.todo.elements[tj++] = todoid;
+ xpctx.todo.elements[tj++] = who;
continue;
}
- /* even more work if all providers conflict */
- queue_push(&errors, ERROR_CONFLICTINGPROVIDERS);
- queue_push2(&errors, id, who);
- if (cidone < out->count)
- expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
- FOR_PROVIDES(p, pp, id)
+
+ /* do conflict pruning */
+ conflprovpc = 0;
+ for (i = j = 0; i < qq.count; i++)
{
Id pc;
- if (conflicts.size && MAPTST(&conflicts, p))
+ p = qq.elements[i];
+ if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p))
{
- pc = findconflictsinfo(&conflictsinfo, p);
- queue_push(&errors, ERROR_PROVIDERINFO2);
- queue_push2(&errors, p, pc);
+ if (xp->debug)
+ findconflictsinfo(&xpctx, p, 0);
+ conflprovpc = 0;
continue;
}
- if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0)
+ if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 0)) != 0)
{
- queue_push(&errors, ERROR_PROVIDERINFO);
- queue_push2(&errors, p, pc);
+ conflprovpc = pc;
continue;
}
- if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0)
+ if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 0)) != 0)
{
- queue_push(&errors, ERROR_PROVIDERINFO);
- queue_push2(&errors, p, -pc);
+ conflprovpc = -pc;
continue;
}
+ qq.elements[j++] = p;
}
- continue;
- }
- if (qq.count > 1 && !doamb)
- {
- /* try again later */
- queue_push2(&todo, id, who);
+ if (j == 0)
+ {
+ if (deptype == DEPTYPE_RECOMMENDS)
+ continue;
+ queue_push(&xpctx.errors, ERROR_CONFLICTINGPROVIDERS);
+ queue_push2(&xpctx.errors, id, who);
+ if (qq.count == 1 && conflprovpc != 1 && conflprovpc != -1)
+ {
+ p = qq.elements[0];
+ if (conflprovpc)
+ {
+ queue_push(&xpctx.errors, ERROR_PROVIDERINFO);
+ queue_push2(&xpctx.errors, p, conflprovpc);
+ continue;
+ }
+ findconflictsinfo(&xpctx, p, 1);
+ continue;
+ }
+ /* even more work if all providers conflict */
+ for (j = 0; j < qq.count; j++)
+ {
+ p = qq.elements[j];
+ if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p))
+ findconflictsinfo(&xpctx, p, 1);
+ if (pool->solvables[p].conflicts)
+ expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 1);
+ if (pool->solvables[p].obsoletes)
+ expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 1);
+ }
+ continue;
+ }
+ queue_truncate(&qq, j);
+ if (qq.count == 1)
+ {
+ p = qq.elements[0];
+ if (xp->debug)
+ expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+ queue_push(&toinstall, p);
+ continue;
+ }
+ /* pass is == 1 and we have multiple choices */
if (xp->debug)
{
expander_dbg(xp, "undecided about %s:%s:", whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
for (i = 0; i < qq.count; i++)
- expander_dbg(xp, " %s", expander_solvid2name(xp, qq.elements[i]));
- expander_dbg(xp, "\n");
+ expander_dbg(xp, " %s", expander_solvid2name(xp, qq.elements[i]));
+ expander_dbg(xp, "\n");
}
+ queue_push2(&choices, qq.count + 3, id);
+ queue_push(&choices, qq.count);
+ queue_insertn(&choices, choices.count, qq.count, qq.elements);
+ xpctx.todo.elements[tj++] = todoid;
+ xpctx.todo.elements[tj++] = who;
+ }
+ queue_truncate(&xpctx.todo, tj);
+
+ if (toinstall.count)
+ continue;
+
+ if (!xpctx.todo.count)
+ continue;
+
+ /* did not find a package to install, only choices left on todo list */
+ if (pass == 0)
+ {
+ pass = 1; /* now do conflict pruning */
continue;
}
- /* prune neg prefers */
- if (qq.count > 1)
+ expander_dbg(xp, "--- now doing undecided dependencies\n");
+
+ /* prune prefers */
+ for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
{
- for (i = j = 0; i < qq.count; i++)
+ Id who = xpctx.todo.elements[ti + 1];
+ Id *qe = choices.elements + tc + 3;
+ Id id = choices.elements[tc + 1];
+ int qn = choices.elements[tc + 2];
+ whon = who ? pool->solvables[who].name : 0;
+ if (qn > 1)
+ qn = prune_neg_prefers(&xpctx, who, qe, qn);
+ if (qn > 1)
+ qn = prune_pos_prefers(&xpctx, who, qe, qn, 0);
+ if (qn == 1)
{
- p = qq.elements[i];
- pn = pool->solvables[p].name;
- if (MAPTST(&xp->preferneg, pn))
- continue;
- if (who && MAPTST(&xp->prefernegx, pn))
- {
- Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
- if (xid && MAPTST(&xp->preferneg, xid))
- continue;
- }
- qq.elements[j++] = p;
+ p = qe[0];
+ if (xp->debug)
+ expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+ queue_push(&toinstall, p);
+ xpctx.todo.elements[ti] = 0; /* kill entry */
}
- if (j)
- queue_truncate(&qq, j);
+ choices.elements[tc + 2] = qn;
+ tc += choices.elements[tc];
}
+ if (toinstall.count)
+ continue;
- /* prune pos prefers */
- if (qq.count > 1)
+ /* prune pos prefers with domulti and debian or */
+ for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
{
- queue_empty(&posfoundq);
- for (i = j = 0; i < qq.count; i++)
+ Id who = xpctx.todo.elements[ti + 1];
+ Id *qe = choices.elements + tc + 3;
+ Id id = choices.elements[tc + 1];
+ int qn = choices.elements[tc + 2];
+ whon = who ? pool->solvables[who].name : 0;
+ if (qn > 1)
+ qn = prune_pos_prefers(&xpctx, who, qe, qn, 1);
+ if (qn > 1 && pool->disttype != DISTTYPE_RPM)
{
- p = qq.elements[i];
- pn = pool->solvables[p].name;
- if (MAPTST(&xp->preferpos, pn))
- {
- queue_push2(&posfoundq, pn, p);
- qq.elements[j++] = p;
- continue;
- }
- if (who && MAPTST(&xp->preferposx, pn))
- {
- Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
- if (xid && MAPTST(&xp->preferpos, xid))
- {
- queue_push2(&posfoundq, xid, p);
- qq.elements[j++] = p;
- continue;
- }
- }
+ if (ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_OR)
+ qn = prune_or_dep(&xpctx, id, qe, qn);
}
- if (posfoundq.count == 2)
+ if (qn == 1)
{
- queue_empty(&qq);
- queue_push(&qq, posfoundq.elements[1]);
+ p = qe[0];
+ if (xp->debug)
+ expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+ queue_push(&toinstall, p);
+ xpctx.todo.elements[ti] = 0; /* kill entry */
}
- else if (posfoundq.count)
+ choices.elements[tc + 2] = qn;
+ tc += choices.elements[tc];
+ }
+ if (toinstall.count)
+ continue;
+
+ /* prune recommended packages */
+ if (xpctx.userecommendsforchoices)
+ expander_updaterecommendedmap(&xpctx);
+ if (xpctx.recommended.size)
+ {
+ expander_dbg(xp, "now doing undecided dependencies with recommends\n");
+ for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
{
- /* found a pos prefer, now find first hit */
- /* (prefers are ordered) */
- for (i = 0; i < xp->preferposq.count; i++)
+ Id who = xpctx.todo.elements[ti + 1];
+ Id *qe = choices.elements + tc + 3;
+ Id id = choices.elements[tc + 1];
+ int qn = choices.elements[tc + 2];
+ whon = who ? pool->solvables[who].name : 0;
+ for (i = j = 0; i < qn; i++)
+ if (MAPTST(&xpctx.recommended, qe[i]))
+ qe[j++] = qe[i];
+ if (j)
+ qn = j;
+ if (qn == 1)
{
- Id xid = xp->preferposq.elements[i];
- for (j = 0; j < posfoundq.count; j += 2)
- if (posfoundq.elements[j] == xid)
- break;
- if (j < posfoundq.count)
- {
- queue_empty(&qq);
- queue_push(&qq, posfoundq.elements[j + 1]);
- break;
- }
+ p = qe[0];
+ if (xp->debug)
+ expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+ queue_push(&toinstall, p);
+ xpctx.todo.elements[ti] = 0; /* kill entry */
}
+ choices.elements[tc + 2] = qn;
+ tc += choices.elements[tc];
}
+ if (toinstall.count)
+ continue;
}
-
- /* prune OR deps */
- if (qq.count > 1 && ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_OR)
+ if (xpctx.usesupplementsforchoices)
{
- Id rid = id;
- for (;;)
+ expander_dbg(xp, "now doing undecided dependencies with supplements\n");
+ for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
{
- Reldep *rd = 0;
- if (ISRELDEP(rid))
+ Id who = xpctx.todo.elements[ti + 1];
+ Id *qe = choices.elements + tc + 3;
+ Id id = choices.elements[tc + 1];
+ int qn = choices.elements[tc + 2];
+ whon = who ? pool->solvables[who].name : 0;
+ qn = prune_supplemented(&xpctx, qe, qn);
+ if (qn == 1)
{
- rd = GETRELDEP(pool, rid);
- if (rd->flags != REL_OR)
- rd = 0;
+ p = qe[0];
+ if (xp->debug)
+ expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+ queue_push(&toinstall, p);
+ xpctx.todo.elements[ti] = 0; /* kill entry */
}
- if (rd)
- rid = rd->name;
- queue_empty(&qq);
- FOR_PROVIDES(p, pp, rid)
- queue_push(&qq, p);
- if (qq.count)
- break;
- if (rd)
- rid = rd->evr;
- else
- break;
+ choices.elements[tc + 2] = qn;
+ tc += choices.elements[tc];
}
+ if (toinstall.count)
+ continue;
}
- if (qq.count > 1 && doamb == 1)
- {
- queue_push2(&todo, id, who);
- continue;
- }
-
- /* prioritize recommended packages. */
- if (qq.count > 1 && doamb == 2)
- {
- expander_updaterecommendedmap(xp, &recommended, &recdone, out);
- if (recommended.size)
- {
- for (i = j = 0; i < qq.count; i++)
- if (MAPTST(&recommended, qq.elements[i]))
- qq.elements[j++] = qq.elements[i];
- if (j)
- queue_truncate(&qq, j);
- }
- }
-
+ /* nothing more to prune. record errors. */
+ for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
+ {
+ Id who = xpctx.todo.elements[ti + 1];
+ Id *qe = choices.elements + tc + 3;
+ Id id = choices.elements[tc + 1];
+ int qn = choices.elements[tc + 2];
+ queue_push(&xpctx.errors, ERROR_CHOICE);
+ queue_push2(&xpctx.errors, id, who);
+ for (i = 0; i < qn; i++)
+ queue_push(&xpctx.errors, qe[i]);
+ queue_push(&xpctx.errors, 0);
+ tc += choices.elements[tc];
+ }
+ }
- if (qq.count > 1)
+ /* free data */
+ map_free(&xpctx.installed);
+ map_free(&xpctx.conflicts);
+ map_free(&xpctx.recommended);
+ map_free(&xpctx.todo_condmap);
+ queue_free(&xpctx.conflictsinfo);
+ queue_free(&xpctx.todo_cond);
+ queue_free(&xpctx.todo);
+ queue_free(&toinstall);
+ queue_free(&qq);
+ queue_free(&choices);
+ queue_free(&xpctx.pruneq);
+ queue_free(&xpctx.cplxq);
+ queue_free(&xpctx.cplxblks);
+
+ /* revert ignores */
+ xp->ignoreignore = oldignoreignore;
+ if (ignoremapssaved)
+ {
+ map_free(&xp->ignored);
+ map_free(&xp->ignoredx);
+ xp->ignored = oldignored;
+ xp->ignoredx = oldignoredx;
+ }
+ else
+ {
+ for (i = 0; i < revertignore.count; i++)
{
- queue_push(&cerrors, ERROR_CHOICE);
- queue_push2(&cerrors, id, who);
- for (i = 0; i < qq.count; i++)
- queue_push(&cerrors, qq.elements[i]);
- queue_push(&cerrors, 0);
- /* try again later */
- queue_push2(&todo, id, who);
- continue;
+ id = revertignore.elements[i];
+ if (id > 0)
+ MAPCLR(&xp->ignored, id);
+ else
+ MAPCLR(&xp->ignoredx, -id);
}
- if (xp->debug)
- expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, qq.elements[0]), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
- expander_installed(xp, qq.elements[0], &installed, &conflicts, &conflictsinfo, &cidone, out, &todo);
- doamb = 0;
- ambcnt = todo.count;
- queue_empty(&cerrors);
- }
- map_free(&installed);
- map_free(&conflicts);
- map_free(&recommended);
- queue_free(&conflictsinfo);
+ }
+ queue_free(&revertignore);
+
+ /* finish return queue, count errors */
nerrors = 0;
- if (errors.count || cerrors.count)
+ if (xpctx.errors.count)
{
queue_empty(out);
- for (i = 0; i < errors.count; i += 3)
+ queue_insertn(out, 0, xpctx.errors.count, xpctx.errors.elements);
+ for (i = 0; i < out->count; i += 3)
{
- queue_push(out, errors.elements[i]);
- queue_push(out, errors.elements[i + 1]);
- queue_push(out, errors.elements[i + 2]);
nerrors++;
- }
- for (i = 0; i < cerrors.count; )
- {
- queue_push(out, cerrors.elements[i]);
- queue_push(out, cerrors.elements[i + 1]);
- queue_push(out, cerrors.elements[i + 2]);
- i += 3;
- while (cerrors.elements[i])
- {
- queue_push(out, cerrors.elements[i]);
+ if (out->elements[i] == ERROR_CHOICE)
+ while (out->elements[i + 3])
i++;
- }
- queue_push(out, 0);
- i++;
- nerrors++;
}
}
- else
+ queue_free(&xpctx.errors);
+ return nerrors;
+}
+
+static Expander *
+expander_create(Pool *pool, Queue *preferpos, Queue *preferneg, Queue *ignore, Queue *conflict, Queue *fileprovides, int debug, int options)
+{
+ Expander *xp;
+ int i, j;
+ Id id, id2;
+ const char *str;
+ Queue q;
+
+ xp = calloc(sizeof(Expander), 1);
+ xp->pool = pool;
+ xp->debug = debug;
+ xp->ignoreignore = options & EXPANDER_OPTION_IGNOREIGNORE ? 1 : 0;
+ xp->ignoreconflicts = options & EXPANDER_OPTION_IGNORECONFLICTS ? 1 : 0;
+ xp->userecommendsforchoices = options & EXPANDER_OPTION_USERECOMMENDSFORCHOICES ? 1 : 0;
+ xp->usesupplementsforchoices = options & EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES ? 1 : 0;
+ xp->dorecommends = options & EXPANDER_OPTION_DORECOMMENDS ? 1 : 0;
+ xp->dosupplements = options & EXPANDER_OPTION_DOSUPPLEMENTS ? 1 : 0;
+
+ queue_init(&xp->preferposq);
+ for (i = 0; i < preferpos->count; i++)
+ {
+ id = preferpos->elements[i];
+ queue_push(&xp->preferposq, id);
+ MAPEXP(&xp->preferpos, id);
+ MAPSET(&xp->preferpos, id);
+ if ((str = strchr(pool_id2str(pool, id), ':')) != 0)
+ {
+ id = str2id_dup(pool, str + 1);
+ MAPEXP(&xp->preferposx, id);
+ MAPSET(&xp->preferposx, id);
+ }
+ }
+ for (i = 0; i < preferneg->count; i++)
+ {
+ id = preferneg->elements[i];
+ MAPEXP(&xp->preferneg, id);
+ MAPSET(&xp->preferneg, id);
+ if ((str = strchr(pool_id2str(pool, id), ':')) != 0)
+ {
+ id = str2id_dup(pool, str + 1);
+ MAPEXP(&xp->prefernegx, id);
+ MAPSET(&xp->prefernegx, id);
+ }
+ }
+
+ for (i = 0; i < ignore->count; i++)
+ {
+ id = ignore->elements[i];
+ MAPEXP(&xp->ignored, id);
+ MAPSET(&xp->ignored, id);
+ if ((str = strchr(pool_id2str(pool, id), ':')) != 0)
+ {
+ id = str2id_dup(pool, str + 1);
+ MAPEXP(&xp->ignoredx, id);
+ MAPSET(&xp->ignoredx, id);
+ }
+ }
+
+ queue_init(&xp->conflictsq);
+ for (i = 0; i < conflict->count; i += 2)
+ {
+ id = conflict->elements[i];
+ id2 = conflict->elements[i + 1];
+ queue_push2(&xp->conflictsq, id, id2);
+ MAPEXP(&xp->conflicts, id);
+ MAPSET(&xp->conflicts, id);
+ MAPEXP(&xp->conflicts, id2);
+ MAPSET(&xp->conflicts, id2);
+ }
+
+ if (fileprovides->count)
+ xp->havefileprovides = 1;
+ queue_init(&q);
+ for (i = 0; i < fileprovides->count; i++)
{
- if (todo.count)
+ Id p, pp;
+ id = fileprovides->elements[i];
+ int havenew = 0;
+
+ /* XXX: this modifies the pool, which is somewhat unclean! */
+ /* get old providers */
+ queue_empty(&q);
+ FOR_PROVIDES(p, pp, id)
+ queue_push(&q, p);
+ for (j = i + 1; j < fileprovides->count && (id2 = fileprovides->elements[j]) != 0; j++)
{
- fprintf(stderr, "Internal expansion error!\n");
- queue_empty(out);
- queue_push(out, ERROR_NOPROVIDER);
- queue_push(out, 0);
- queue_push(out, 0);
+ FOR_PROVIDES(p, pp, id2)
+ {
+ int k;
+ if (pool->solvables[p].name != id2)
+ continue; /* match name only */
+ /* insert sorted */
+ for (k = 0; ; k++)
+ {
+ if (k == q.count || q.elements[k] > p)
+ {
+ queue_insert(&q, k, p);
+ havenew = 1;
+ break;
+ }
+ if (q.elements[k] == p)
+ break;
+ }
+ }
}
+ if (havenew)
+ pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
+ i = j;
}
- queue_free(&todo);
- queue_free(&qq);
- queue_free(&errors);
- queue_free(&cerrors);
- queue_free(&posfoundq);
- return nerrors;
+ queue_free(&q);
+ return xp;
+}
+
+static void
+expander_free(Expander *xp)
+{
+ map_free(&xp->ignored);
+ map_free(&xp->ignoredx);
+ queue_free(&xp->preferposq);
+ map_free(&xp->preferpos);
+ map_free(&xp->preferposx);
+ map_free(&xp->preferneg);
+ map_free(&xp->prefernegx);
+ queue_free(&xp->conflictsq);
+ map_free(&xp->conflicts);
+ solv_free(xp->debugstr);
+ solv_free(xp);
}
+
+
static void
set_disttype(Pool *pool, int disttype)
{
set_disttype(pool, disttype);
}
-void
-create_considered(Pool *pool, Repo *repoonly, Map *considered)
+static inline const char *
+solvid2name(Pool *pool, Id p)
+{
+ return pool_id2str(pool, pool->solvables[p].name);
+}
+
+#define ISNOARCH(arch) (arch == ARCH_NOARCH || arch == ARCH_ALL || arch == ARCH_ANY)
+
+static int
+has_keyname(Repo *repo, Id keyname)
+{
+ Repodata *data;
+ int rdid;
+ FOR_REPODATAS(repo, rdid, data)
+ if (repodata_has_keyname(data, keyname))
+ return 1;
+ return 0;
+}
+
+static inline int
+match_modules_req(Pool *pool, Id id)
+{
+ const char *dep = pool_id2str(pool, id);
+ Id *modules;
+ if (strncmp(dep, "platform", 8) == 0 && (dep[8] == 0 || dep[8] == '-'))
+ return 1;
+ for (modules = pool->appdata; *modules; modules++)
+ {
+ const char *name, *rname;
+ if (*modules == id)
+ return 1;
+ name = pool_id2str(pool, *modules);
+ if ((rname = strrchr(name, '-')) == 0 || rname == name)
+ continue;
+ if (!strncmp(dep, rname, rname - name) && dep[rname - name] == 0)
+ return 1;
+ }
+ return 0;
+}
+
+static void
+create_module_map(Repo *repo, Map *modulemap, Queue *modulemapq)
+{
+ Pool *pool = repo->pool;
+ Id *modules = pool->appdata;
+ int i, have_moduleinfo = 0;
+ Id id, p, *pp;
+ Solvable *s;
+
+ if (!modulemap->size)
+ map_grow(modulemap, pool->ss.nstrings);
+ if (!modules)
+ return;
+ if (!*modules)
+ {
+ map_setall(modulemap);
+ return;
+ }
+ /* clear old bits */
+ if (modulemapq->count)
+ {
+ for (i = 0; i < modulemapq->count; i++)
+ MAPCLR(modulemap, modulemapq->elements[i]);
+ queue_empty(modulemapq);
+ }
+ for (modules = pool->appdata; *modules; modules++)
+ MAPSET(modulemap, *modules);
+ /* look for module information stored in "buildservice:modules" solvables */
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ if (s->name != buildservice_modules || s->arch != ARCH_SRC)
+ continue;
+ have_moduleinfo = 1;
+ if (s->evr >= 1 && s->evr < pool->ss.nstrings && MAPTST(modulemap, s->evr))
+ {
+ queue_push(modulemapq, s->evr); /* directly addressed */
+ continue;
+ }
+ id = s->repo->idarraydata[s->provides];
+ if (id < 1 || id >= pool->ss.nstrings || !MAPTST(modulemap, id))
+ continue; /* not what we're looking for */
+ for (pp = s->repo->idarraydata + s->requires; (id = *pp) != 0; pp++)
+ {
+ /* check if the dep is fulfilled by any module in the list */
+ if (id < 1 || id >= pool->ss.nstrings)
+ break; /* hey! */
+ if (!MAPTST(modulemap, id) && !match_modules_req(pool, id))
+ break; /* could not fulfil requires */
+ }
+ if (id)
+ continue; /* could not fulfil one of the requires, ignore module */
+ queue_push(modulemapq, s->evr);
+ }
+ if (!have_moduleinfo)
+ {
+ /* old style repo with no moduleinfo at all. simple use the unexpanded ids */
+ for (modules = pool->appdata; *modules; modules++)
+ queue_push(modulemapq, *modules);
+ return;
+ }
+ for (modules = pool->appdata; *modules; modules++)
+ MAPCLR(modulemap, *modules);
+ for (i = 0; i < modulemapq->count; i++)
+ MAPSET(modulemap, modulemapq->elements[i]);
+}
+
+static int
+in_module_map(Pool *pool, Map *modulemap, Queue *modules)
+{
+ int i;
+ for (i = 0; i < modules->count; i++)
+ {
+ Id id = modules->elements[i];
+ if (id > 1 && id < pool->ss.nstrings && MAPTST(modulemap, id))
+ return 1;
+ }
+ return 0;
+}
+
+
+static void
+create_considered(Pool *pool, Repo *repoonly, Map *considered, int unorderedrepos)
{
Id p, pb,*best;
Solvable *s, *sb;
Repo *repo;
int olddisttype = -1;
int dodrepo;
+ int mayhave_modules;
+ Queue modules;
+ Map modulemap;
+ Queue modulemapq;
+ int modulemap_uptodate;
map_init(considered, pool->nsolvables);
best = solv_calloc(sizeof(Id), pool->ss.nstrings);
+ queue_init(&modules);
+ map_init(&modulemap, 0);
+ queue_init(&modulemapq);
FOR_REPOS(ridx, repo)
{
if (repoonly && repo != repoonly)
continue;
dodrepo = repo_lookup_str(repo, SOLVID_META, buildservice_dodurl) != 0;
+ mayhave_modules = has_keyname(repo, buildservice_modules) ? 1 : 0;
+ modulemap_uptodate = 0;
FOR_REPO_SOLVABLES(repo, p, s)
{
+ int inmodule = 0;
if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
continue;
pb = best[s->name];
- if (pb)
+ sb = pb ? pool->solvables + pb : 0;
+ if (mayhave_modules)
{
- sb = pool->solvables + pb;
- if (s->repo != sb->repo)
- continue; /* first repo wins */
- if (s->arch != sb->arch)
+ solvable_lookup_idarray(s, buildservice_modules, &modules);
+ inmodule = modules.count ? 1 : 0;
+ if (inmodule)
{
- int r;
- if (s->arch == ARCH_NOARCH || s->arch == ARCH_ALL || s->arch == ARCH_ANY)
- continue;
- if (sb->arch != ARCH_NOARCH && sb->arch != ARCH_ALL && sb->arch != ARCH_ANY)
+ if (!modulemap_uptodate)
{
- /* the strcmp is kind of silly, but works for most archs */
- r = strcmp(pool_id2str(pool, sb->arch), pool_id2str(pool, s->arch));
- if (r >= 0)
- continue;
+ create_module_map(repo, &modulemap, &modulemapq);
+ modulemap_uptodate = 1;
}
+ if (!in_module_map(pool, &modulemap, &modules))
+ continue; /* nope, ignore package */
+ }
+ }
+ if (unorderedrepos && sb && s->repo->priority != sb->repo->priority)
+ {
+ if (s->repo->priority < sb->repo->priority)
+ continue; /* lower prio, ignore */
+ }
+ else if (sb)
+ {
+ int sbinmodule = 0;
+ /* we already have that name. decide which one to take */
+ if (!unorderedrepos && s->repo != sb->repo)
+ continue; /* first repo wins */
+
+ if (s->repo == sb->repo && mayhave_modules)
+ sbinmodule = solvable_lookup_type(sb, buildservice_modules) ? 1 : 0;
+
+ if (inmodule != sbinmodule)
+ {
+ if (inmodule < sbinmodule)
+ continue;
}
else if (s->evr != sb->evr)
{
- /* same repo, check versions */
+ /* check versions */
int r;
if (olddisttype < 0)
{
set_disttype_from_location(pool, s);
}
r = pool_evrcmp(pool, sb->evr, s->evr, EVRCMP_COMPARE);
- if (r > 0)
+ if (r == 0)
+ r = strcmp(pool_id2str(pool, sb->evr), pool_id2str(pool, s->evr));
+ if (r >= 0)
continue;
- else if (r == 0)
+ }
+ else if (s->arch != sb->arch)
+ {
+ /* same versions, check arch */
+ if (ISNOARCH(sb->arch) && !ISNOARCH(s->arch))
+ continue;
+ if (ISNOARCH(sb->arch) || !ISNOARCH(s->arch))
{
- r = strcmp(pool_id2str(pool, sb->evr), pool_id2str(pool, s->evr));
+ int r;
+ /* the strcmp is kind of silly, but works for most archs */
+ r = strcmp(pool_id2str(pool, sb->arch), pool_id2str(pool, s->arch));
if (r >= 0)
continue;
}
}
}
+
if (dodrepo)
{
/* we only consider dod packages */
best[s->name] = p;
MAPSET(considered, p);
}
- /* dodrepos have a second pass: replace dod entries with downloaded ones */
+ /* dodrepos have a second pass: replace dod entries with identical downloaded ones */
if (dodrepo)
{
const char *bsid;
}
}
solv_free(best);
+ queue_free(&modules);
+ map_free(&modulemap);
+ queue_free(&modulemapq);
if (olddisttype >= 0 && pool->disttype != olddisttype)
set_disttype(pool, olddisttype);
}
struct metaline {
- char *l; /* pointer to line */
- int lastoff; /* line offset of last path element */
- int nslash; /* number of slashes */
- int killed; /* 1: line has been killed. 2: because of a cycle package */
+ char *l; /* pointer to line */
+ int lastoff; /* line offset of last path element */
+ int nslash; /* number of slashes */
+ int killed; /* 1: line has been killed. 2: because of a cycle package */
};
static int metacmp(const void *ap, const void *bp)
return a - b;
}
+static char *
+slurp(FILE *fp, int *lenp)
+{
+ int l, ll;
+ char *buf = 0;
+ int bufl = 0;
+
+ for (l = 0; ; l += ll)
+ {
+ if (bufl - l < 4096)
+ {
+ bufl += 4096;
+ if (bufl < 0)
+ {
+ buf = solv_free(buf);
+ l = 0;
+ break;
+ }
+ buf = solv_realloc(buf, bufl);
+ }
+ ll = fread(buf + l, 1, bufl - l, fp);
+ if (ll < 0)
+ {
+ buf = solv_free(buf);
+ l = 0;
+ break;
+ }
+ if (ll == 0)
+ {
+ buf[l] = 0; /* always zero-terminate */
+ break;
+ }
+ }
+ if (lenp)
+ *lenp = l;
+ return buf;
+}
+
+
+Id
+repo_add_obsbinlnk(Repo *repo, const char *path, int flags)
+{
+ Repodata *data;
+ FILE *fp;
+ char *buf;
+ int len;
+ SV *sv;
+ unsigned char *src;
+ STRLEN srcl;
+ Id p;
+
+ if ((fp = fopen(path, "r")) == 0)
+ return 0;
+ buf = slurp(fp, &len);
+ fclose(fp);
+ if (!buf || len <= 0)
+ return 0;
+ src = (unsigned char *)buf;
+ srcl = len;
+ sv = 0;
+ if (srcl >= 7 && src[0] == 'p' && src[1] == 's' && src[2] == 't' && src[3] == '0' && (src[4] & 1) == 1 && src[4] >= 5) {
+ src += 6;
+ srcl -= 6;
+ sv = retrieve(&src, &srcl, 0);
+ }
+ free(buf);
+ if (!sv)
+ return 0;
+ if (SvTYPE(sv) != SVt_PVHV)
+ {
+ SvREFCNT_dec(sv);
+ return 0;
+ }
+ data = repo_add_repodata(repo, flags);
+ p = data2pkg(repo, data, (HV *)sv, 0);
+ SvREFCNT_dec(sv);
+ if (!(flags & REPO_NO_INTERNALIZE))
+ repodata_internalize(data);
+ return p;
+}
+
#ifndef REPO_NO_LOCATION
# define REPO_NO_LOCATION 0
#endif
path = solv_dupjoin(prefix, "/", s);
if (sl >= 4 && !strcmp(s + sl - 4, ".rpm"))
p = repo_add_rpm(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|RPM_ADD_WITH_PKGID|RPM_ADD_NO_FILELIST|RPM_ADD_NO_RPMLIBREQS);
+#if defined(LIBSOLVEXT_FEATURE_DEBIAN)
else if (sl >= 4 && !strcmp(s + sl - 4, ".deb"))
p = repo_add_deb(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|DEBS_ADD_WITH_PKGID);
-#ifdef ARCH_ADD_WITH_PKGID
+#endif
+ else if (sl >= 10 && !strcmp(s + sl - 10, ".obsbinlnk"))
+ {
+ p = repo_add_obsbinlnk(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION);
+ /* do not overwrite location from obsbinlnk file */
+ solv_free(path);
+ if (p)
+ repodata_set_str(data, p, buildservice_id, sid);
+ return p;
+ }
+#if defined(LIBSOLVEXT_FEATURE_ARCHREPO) && defined(ARCH_ADD_WITH_PKGID)
else if (sl >= 12 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz") || !strcmp(s + sl - 12, ".pkg.tar.zst")))
p = repo_add_arch_pkg(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|ARCH_ADD_WITH_PKGID);
#endif
printf("stats file_size %lld\n", (unsigned long long)ftell(fp));
}
+static int
+unifymodules_cmp(const void *ap, const void *bp, void *dp)
+{
+ return *(Id *)ap - *(Id *)bp;
+}
+
+static int
+missingmodules_cmp(const void *ap, const void *bp, void *dp)
+{
+ const Id *a = ap;
+ const Id *b = bp;
+ if (a[0] != b[0])
+ return a[0] - b[0];
+ if (!a[1] && b[1])
+ return -1;
+ if (!b[1] && a[1])
+ return 1;
+ return a[1] - b[1];
+}
+
+static int
+is_dod_package(Solvable *s)
+{
+ const char *str = solvable_lookup_str(s, buildservice_id);
+ return str && !strcmp(str, "dod") ? 1 : 0;
+}
+
+static Solvable *
+find_corresponding_dod(Solvable *s)
+{
+ Repo *repo = s->repo;
+ Id p2;
+ Solvable *s2;
+
+ if (!repo)
+ return 0;
+ FOR_REPO_SOLVABLES(repo, p2, s2)
+ {
+ if (s->name == s2->name && s->evr == s2->evr && s->arch == s2->arch && s != s2 && is_dod_package(s2))
+ return s2;
+ }
+ return 0;
+}
+
+struct scc_data {
+ Id *edata;
+ Id *vedge;
+ Queue *sccs;
+ int *stack;
+ int nstack;
+ int *low;
+ int idx;
+};
+
+static void
+scc_collect(struct scc_data *scc, int node)
+{
+ int *low = scc->low;
+ Id *e;
+ queue_push(scc->sccs, node);
+ low[node] = -1;
+ for (e = scc->edata + scc->vedge[node]; *e; e++)
+ if (*e != -1 && low[*e] > 0)
+ scc_collect(scc, *e);
+}
+
+/* Tarjan's SCC algorithm */
+static int
+scc_visit(struct scc_data *scc, int node)
+{
+ int l, myidx, *low = scc->low, nontrivial = 0;
+ Id *e;
+ low[node] = myidx = scc->idx++;
+ for (e = scc->edata + scc->vedge[node]; *e; e++)
+ {
+ if (*e == -1 || *e == node)
+ continue;
+ if (!(l = low[*e]))
+ l = scc_visit(scc, *e);
+ if (l > 0)
+ nontrivial = 1;
+ if (l > 0 && l < low[node])
+ low[node] = l;
+ }
+ if (low[node] != myidx)
+ return low[node];
+ low[node] = -1;
+ if (nontrivial)
+ {
+ scc_collect(scc, node);
+ queue_push(scc->sccs, 0);
+ }
+ return -1;
+}
+
+static void
+find_sccs(Queue *edata, Queue *vedge, Queue *sccs)
+{
+ struct scc_data scc;
+ int i;
+ scc.edata = edata->elements;
+ scc.vedge = vedge->elements;
+ scc.sccs = sccs;
+ scc.low = solv_calloc(vedge->count, sizeof(int));
+ scc.idx = 1;
+ for (i = 1; i < vedge->count; i++)
+ if (!scc.edata[vedge->elements[i]])
+ scc.low[i] = -1;
+ for (i = 1; i < vedge->count; i++)
+ if (!scc.low[i])
+ scc_visit(&scc, i);
+ solv_free(scc.low);
+}
+
+
MODULE = BSSolv PACKAGE = BSSolv
void
depsort(HV *deps, SV *mapp, SV *cycp, ...)
+ ALIAS:
+ depsort2 = 1
PPCODE:
{
int i, j, k, cy, cycstart, nv;
+ int pkgstart = 3;
SV *sv, **svp;
+ SV *pkg2srcp = 0;
Id id, *e;
Id *mark;
char **names;
+ char **depnames;
Hashtable ht;
Hashval h, hh, hm;
HV *mhv = 0;
+ HV *pkg2srchv = 0;
Queue edata;
Queue vedge;
Queue todo;
Queue cycles;
+ Map edgeunifymap;
+ int didsccs = 0;
- if (items == 3)
+ if (ix)
+ {
+ /* called as depsort2 */
+ if (items < 4)
+ XSRETURN_EMPTY; /* nothing to sort */
+ pkgstart = 4;
+ pkg2srcp = cycp;
+ cycp = ST(3);
+ }
+ if (items == pkgstart)
XSRETURN_EMPTY; /* nothing to sort */
- if (items == 4)
+ if (items == pkgstart + 1)
{
/* only one item */
- char *s = SvPV_nolen(ST(3));
+ char *s = SvPV_nolen(ST(pkgstart));
EXTEND(SP, 1);
sv = newSVpv(s, 0);
PUSHs(sv_2mortal(sv));
XSRETURN(1); /* nothing to sort */
}
+ if (pkg2srcp && SvROK(pkg2srcp) && SvTYPE(SvRV(pkg2srcp)) == SVt_PVHV)
+ pkg2srchv = (HV *)SvRV(pkg2srcp);
+
if (mapp && SvROK(mapp) && SvTYPE(SvRV(mapp)) == SVt_PVHV)
mhv = (HV *)SvRV(mapp);
hm = mkmask(items);
ht = solv_calloc(hm + 1, sizeof(*ht));
- names = solv_calloc(items, sizeof(char *));
+ names = depnames = solv_calloc(items, sizeof(char *));
+
+ /* create pkgname -> edge hash, store edge -> pkgname data */
nv = 1;
- for (i = 3; i < items; i++)
+ for (i = pkgstart; i < items; i++)
{
char *s = SvPV_nolen(ST(i));
h = strhash(s) & hm;
names[id] = s;
}
+ if (pkg2srchv)
+ {
+ /* redo the hash with src names instead of pkg names */
+ depnames = solv_calloc(nv, sizeof(char *));
+ memset(ht, 0, (hm + 1) * sizeof(*ht));
+ for (i = 1; i < nv; i++)
+ {
+ char *s = names[i];
+ svp = hv_fetch(pkg2srchv, s, strlen(s), 0);
+ if (svp)
+ {
+ char *ns = SvPV_nolen(*svp);
+ if (ns)
+ s = ns;
+ }
+ depnames[i] = s;
+ h = strhash(s) & hm;
+ hh = HASHCHAIN_START;
+ while ((id = ht[h]) != 0)
+ h = HASHCHAIN_NEXT(h, hh, hm);
+ ht[h] = i;
+ }
+ }
+
/* we now know all vertices, create edges */
queue_push(&vedge, 0);
queue_push(&edata, 0);
+ map_init(&edgeunifymap, nv);
for (i = 1; i < nv; i++)
{
+ int edgestart = edata.count;
svp = hv_fetch(deps, names[i], strlen(names[i]), 0);
sv = svp ? *svp : 0;
- queue_push(&vedge, edata.count);
+ queue_push(&vedge, edgestart);
if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)
{
AV *av = (AV *)SvRV(sv);
hh = HASHCHAIN_START;
while ((id = ht[h]) != 0)
{
- if (!strcmp(names[id], s))
- break;
+ if (!strcmp(depnames[id], s))
+ {
+ if (id != i && !MAPTST(&edgeunifymap, id))
+ {
+ MAPSET(&edgeunifymap, id);
+ queue_push(&edata, id);
+ }
+ if (names == depnames)
+ break; /* no other entry with same name */
+ }
h = HASHCHAIN_NEXT(h, hh, hm);
}
- if (!id)
- continue; /* not known, ignore */
- if (id == i)
- continue; /* no self edge */
- queue_push(&edata, id);
}
}
- queue_push(&edata, 0);
+ for (j = edgestart; j < edata.count; j++)
+ {
+#ifdef MAPCLR_AT
+ MAPCLR_AT(&edgeunifymap, edata.elements[j]);
+#else
+ MAPCLR(&edgeunifymap, edata.elements[j]);
+#endif
+ }
+ queue_push(&edata, 0); /* terminate edge array */
}
+ /* free no longer needed stuff */
+ map_free(&edgeunifymap);
solv_free(ht);
+ if (depnames != names)
+ depnames = solv_free(depnames);
if (0)
{
continue;
}
/* oh no, we found a cycle, record and break it */
+ if (depsortsccs && !didsccs && cycp)
+ {
+ /* use Tarjan's SCC algorithm */
+ find_sccs(&edata, &vedge, &cycles);
+ queue_push(&cycles, 0);
+ didsccs = cycles.count;
+ }
cy = cycles.count;
for (j = todo.count - 1; j >= 0; j--)
if (todo.elements[j] == -i)
todo.count = cycstart + 1;
}
- /* recored cycles */
+ if (didsccs && depsortsccs != 2)
+ queue_truncate(&cycles, didsccs - 1);
+
+ /* record cycles */
if (cycles.count && cycp && SvROK(cycp) && SvTYPE(SvRV(cycp)) == SVt_PVAV)
{
AV *av = (AV *)SvRV(cycp);
}
int
+setdepsortsccs(int flag)
+ CODE:
+ depsortsccs = flag;
+ RETVAL = flag;
+ OUTPUT:
+ RETVAL
+
+int
setgenmetaalgo(int algo)
CODE:
- if (algo < 0)
- algo = 1;
- if (algo > 1)
- croak("BSSolv::setgenmetaalgo: unsupported algo %d\n", algo);
- genmetaalgo = algo;
- RETVAL = algo;
+ if (algo < 0)
+ algo = 1;
+ if (algo > 1)
+ croak("BSSolv::setgenmetaalgo: unsupported algo %d\n", algo);
+ genmetaalgo = algo;
+ RETVAL = algo;
OUTPUT:
- RETVAL
+ RETVAL
+
void
gen_meta(AV *subp, ...)
}
if (cycle)
{
- lp->killed = 1; /* killed because line includes a subpackage */
+ lp->killed = 1; /* killed because line includes a subpackage */
if (cycle > 1) /* ignore self cycles */
queue_push(&cycles, i);
}
}
if (!id)
{
- int l = strlen(s);
- cycledata = solv_extend(cycledata, cycledatalen, l + 1, 1, 255);
- ht[h] = cycledatalen; /* point to name */
- strcpy(cycledata + cycledatalen, s);
- cycledatalen += l + 1;
+ int l = strlen(s);
+ cycledata = solv_extend(cycledata, cycledatalen, l + 1, 1, 255);
+ ht[h] = cycledatalen; /* point to name */
+ strcpy(cycledata + cycledatalen, s);
+ cycledatalen += l + 1;
}
if (se)
*se = '/';
}
+
for (i = 0, lp = lines; i < nlines; i++, lp++)
{
if (!lp->nslash)
*s2 = '/';
if (id)
{
- lp->killed = 2; /* killed because it containes a cycle package */
+ lp->killed = 2; /* killed because it containes a cycle package */
break;
}
lo = s2 + 1;
h = HASHCHAIN_NEXT(h, hh, hm);
}
if (id)
- {
- lp->killed = 2; /* killed because it containes a cycle package */
- }
+ lp->killed = 2; /* killed because it containes a cycle package */
}
solv_free(ht);
cycledata = solv_free(cycledata);
{
if (lp->killed)
{
- if (genmetaalgo == 0 || lp->killed != 2)
+ if (genmetaalgo == 0 || lp->killed != 2)
continue;
}
s = lp->l;
solv_free(lines);
}
+void
+add_meta(AV *new_meta, SV *sv, const char *bin, const char *packid = 0)
+ PPCODE:
+ {
+ const char *p, *np;
+ char *buf;
+ size_t l, bufl, binl, packidl;
+ int first = 1;
+ if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) {
+ AV *av = (AV *)SvRV(sv);
+ SV **svp = av_fetch(av, 0, 0);
+ sv = svp ? *svp : 0;
+ }
+ if (!sv)
+ XSRETURN_EMPTY;
+ p = SvPV_nolen(sv);
+ binl = strlen(bin);
+ bufl = binl + 256;
+ buf = malloc(bufl);
+ if (!buf) {
+ croak("out of mem\n");
+ XSRETURN_EMPTY;
+ }
+ packidl = packid ? strlen(packid) : 0;
+ for (;;) {
+ np = strchr(p, '\n');
+ l = np ? np - p : strlen(p);
+ if (l > 34) {
+ if (l + binl + 1 + 1 > bufl) {
+ bufl = l + binl + 256;
+ buf = realloc(buf, bufl);
+ if (!buf) {
+ croak("out of mem\n");
+ XSRETURN_EMPTY;
+ }
+ }
+ strncpy(buf, p, 34);
+ strcpy(buf + 34, bin);
+ buf[34 + binl] = '/';
+ strncpy(buf + 34 + binl + 1, p + 34, l - 34);
+ l += binl + 1;
+ buf[l] = 0;
+ if (first) {
+ if (packidl && l > packidl + 1 && buf[l - packidl - 1] == '/' && !strcmp(buf + l - packidl, packid)) {
+ free(buf);
+ XSRETURN_EMPTY;
+ }
+ l = 34 + binl;
+ buf[l] = 0;
+ first = 0;
+ }
+ av_push(new_meta, newSVpvn(buf, l));
+ }
+ if (!np)
+ break;
+ p = np + 1;
+ }
+ free(buf);
+ }
+
SV *
thawcache(SV *sv)
CODE:
buildservice_dodurl = pool_str2id(pool, "buildservice:dodurl", 1);
expander_directdepsend = pool_str2id(pool, "-directdepsend--", 1);
buildservice_dodcookie = pool_str2id(pool, "buildservice:dodcookie", 1);
+ buildservice_dodresources = pool_str2id(pool, "buildservice:dodresources", 1);
+ buildservice_annotation = pool_str2id(pool, "buildservice:annotation", 1);
+ buildservice_modules = pool_str2id(pool, "buildservice:modules", 1);
pool_freeidhashes(pool);
RETVAL = pool;
}
continue;
if (strcmp(s + sl - 4, ".rpm")
&& strcmp(s + sl - 4, ".deb")
+ && (sl < 10 || strcmp(s + sl - 10, ".obsbinlnk"))
#ifdef ARCH_ADD_WITH_PKGID
&& (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz"))
&& (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz"))
RETVAL
BSSolv::repo
-repofromdata(BSSolv::pool pool, char *name, HV *rhv)
+repofromdata(BSSolv::pool pool, char *name, SV *rv)
CODE:
{
Repo *repo;
Repodata *data;
+ if (!SvROK(rv) || (SvTYPE(SvRV(rv)) != SVt_PVHV && SvTYPE(SvRV(rv)) != SVt_PVAV))
+ croak("BSSolv::pool::repofromdata: rv is not a HASH or ARRAY reference");
repo = repo_create(pool, name);
data = repo_add_repodata(repo, 0);
- data2solvables(repo, data, rhv);
+ data2solvables(repo, data, SvRV(rv), 0);
if (name && !strcmp(name, "/external/"))
repodata_set_void(data, SOLVID_META, buildservice_external);
repo_internalize(repo);
RETVAL
void
-createwhatprovides(BSSolv::pool pool)
+createwhatprovides(BSSolv::pool pool, int unorderedrepos = 0)
CODE:
if (pool->considered)
{
solv_free(pool->considered);
}
pool->considered = solv_calloc(sizeof(Map), 1);
- create_considered(pool, 0, pool->considered);
+ create_considered(pool, 0, pool->considered, unorderedrepos);
pool_createwhatprovides(pool);
void
PPCODE:
{
Id p, pp, id;
- id = dep2id(pool, str);
+ id = testcase_str2dep(pool, str);
if (id)
FOR_PROVIDES(p, pp, id)
XPUSHs(sv_2mortal(newSViv((IV)p)));
Id p, id;
Id *pp;
Solvable *s;
- id = dep2id(pool, str);
+ id = testcase_str2dep(pool, str);
if (id)
{
for (p = 2; p < pool->nsolvables; p++)
RETVAL
const char *
+pkg2evr(BSSolv::pool pool, int p)
+ CODE:
+ RETVAL = pool_id2str(pool, pool->solvables[p].evr);
+ OUTPUT:
+ RETVAL
+
+const char *
+pkg2arch(BSSolv::pool pool, int p)
+ CODE:
+ RETVAL = pool_id2str(pool, pool->solvables[p].arch);
+ OUTPUT:
+ RETVAL
+
+const char *
pkg2srcname(BSSolv::pool pool, int p)
CODE:
if (solvable_lookup_void(pool->solvables + p, SOLVABLE_SOURCENAME))
RETVAL
int
+pkg2inmodule(BSSolv::pool pool, int p)
+ CODE:
+ RETVAL = solvable_lookup_type(pool->solvables + p, buildservice_modules) != 0;
+ OUTPUT:
+ RETVAL
+
+void
+pkg2modules(BSSolv::pool pool, int p)
+ PPCODE:
+ {
+ Solvable *s = pool->solvables + p;
+ Queue modules;
+ int i;
+ queue_init(&modules);
+ solvable_lookup_idarray(s, buildservice_modules, &modules);
+ if (!modules.count && !is_dod_package(s))
+ {
+ Solvable *s2 = find_corresponding_dod(s);
+ if (s2)
+ solvable_lookup_idarray(s2, buildservice_modules, &modules);
+ }
+ for (i = 0; i < modules.count; i++)
+ XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, modules.elements[i]), 0)));
+ queue_free(&modules);
+ }
+
+int
verifypkgchecksum(BSSolv::pool pool, int p, char *path)
CODE:
{
ss = solvable_lookup_str(s, buildservice_id);
if (ss)
(void)hv_store(RETVAL, "id", 2, newSVpv(ss, 0), 0);
+ ss = solvable_lookup_str(s, buildservice_annotation);
+ if (ss)
+ (void)hv_store(RETVAL, "annotation", 10, newSVpv(ss, 0), 0);
+ if (solvable_lookup_type(s, buildservice_modules))
+ {
+ Queue modules;
+ int i;
+ queue_init(&modules);
+ solvable_lookup_idarray(s, buildservice_modules, &modules);
+ if (modules.count)
+ {
+ AV *av = newAV();
+ for (i = 0; i < modules.count; i++)
+ av_push(av, newSVpv(pool_id2str(pool, modules.elements[i]), 0));
+ (void)hv_store(RETVAL, "modules", 7, newRV_noinc((SV*)av), 0);
+ }
+ }
}
OUTPUT:
RETVAL
+const char *
+pkg2annotation(BSSolv::pool pool, int p)
+ CODE:
+ RETVAL = solvable_lookup_str(pool->solvables + p, buildservice_annotation);
+ OUTPUT:
+ RETVAL
+
void
repos(BSSolv::pool pool)
PPCODE:
}
void
+setmodules(BSSolv::pool pool, AV *modulesav)
+ CODE:
+ {
+ SSize_t i, n = av_len(modulesav);
+ pool->appdata = solv_free(pool->appdata);
+ if (n >= 0 && n < 1000000)
+ {
+ Id *modules = pool->appdata = solv_calloc(n + 2, sizeof(Id));
+ for (i = 0; i <= n; i++)
+ modules[i] = pool_str2id(pool, avlookupstr(modulesav, i), 1);
+ modules[i] = 0;
+ }
+ }
+
+void
+getmodules(BSSolv::pool pool)
+ PPCODE:
+ if (pool->appdata)
+ {
+ Id *modules = pool->appdata;
+ int i;
+ for (i = 0; modules[i]; i++)
+ XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, modules[i]), 0)));
+ }
+
+void
DESTROY(BSSolv::pool pool)
CODE:
if (pool->considered)
map_free(pool->considered);
pool->considered = solv_free(pool->considered);
}
+ pool->appdata = solv_free(pool->appdata);
pool_free(pool);
MODULE = BSSolv PACKAGE = BSSolv::repo PREFIX = repo
void
+freerepo(BSSolv::repo repo)
+ CODE:
+ {
+ repo_free(repo, 1);
+ }
+
+void
+allpackages(BSSolv::repo repo)
+ PPCODE:
+ {
+ Id p;
+ Solvable *s;
+ EXTEND(SP, repo->nsolvables);
+ FOR_REPO_SOLVABLES(repo, p, s)
+ PUSHs(sv_2mortal(newSViv(p)));
+ }
+
+void
pkgnames(BSSolv::repo repo)
PPCODE:
{
Id p;
Solvable *s;
Map c;
-
- create_considered(pool, repo, &c);
+
+ create_considered(pool, repo, &c, 0);
EXTEND(SP, 2 * repo->nsolvables);
FOR_REPO_SOLVABLES(repo, p, s)
{
const char *str;
unsigned int medianr;
- create_considered(pool, repo, &c);
+ create_considered(pool, repo, &c, 0);
EXTEND(SP, 2 * repo->nsolvables);
FOR_REPO_SOLVABLES(repo, p, s)
{
continue;
h = strhash(str) & hm;
hh = HASHCHAIN_START;
- while ((id = ht[h]) != 0)
+ while (ht[h])
h = HASHCHAIN_NEXT(h, hh, hm);
ht[h] = p;
}
continue;
if (strcmp(s + sl - 4, ".rpm")
&& strcmp(s + sl - 4, ".deb")
+ && (sl < 10 || strcmp(s + sl - 10, ".obsbinlnk"))
#ifdef ARCH_ADD_WITH_PKGID
&& (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz"))
&& (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz"))
&& (sl < 12 || strcmp(s + sl - 12, ".pkg.tar.zst"))
#endif
)
+ continue;
if (sl > 10 && !strcmp(s + sl - 10, ".patch.rpm"))
continue;
if (sl > 10 && !strcmp(s + sl - 10, ".nosrc.rpm"))
const char *str = solvable_lookup_str(pool->solvables + id, buildservice_id);
if (!strcmp(str, sid))
{
- /* check location */
+ /* check location (unless it's a obsbinlnk where the location comes from the content) */
unsigned int medianr;
str = solvable_get_location(pool->solvables + id, &medianr);
if (str[0] == '.' && str[1] == '/')
str += 2;
- if (!strcmp(str, s))
+ if (!strcmp(str, s) || (sl >= 10 && !strcmp(s + sl - 10, ".obsbinlnk")))
break;
}
h = HASHCHAIN_NEXT(h, hh, hm);
OUTPUT:
RETVAL
+void
+modulesfrombins(BSSolv::repo repo, ...)
+ PPCODE:
+ {
+ Pool *pool = repo->pool;
+ Hashtable ht;
+ Hashval h, hh, hm;
+ Queue modules;
+ Queue collectedmodules;
+ Id p, lastid;
+ Solvable *s;
+ int i, j;
+
+ queue_init(&collectedmodules);
+ queue_init(&modules);
+ hm = mkmask(2 * repo->nsolvables + 1);
+ ht = solv_calloc(hm + 1, sizeof(*ht));
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ const char *bsid = solvable_lookup_str(s, buildservice_id);
+ if (!bsid)
+ continue;
+ if (!strcmp(bsid, "dod"))
+ h = s->name + s->evr * 37 + s->arch * 129;
+ else
+ h = strhash(bsid);
+ h &= hm;
+ hh = HASHCHAIN_START;
+ while (ht[h])
+ h = HASHCHAIN_NEXT(h, hh, hm);
+ ht[h] = p;
+ }
+
+ for (i = 1; i + 1 < items; i += 2)
+ {
+ const char *bsid = SvPV_nolen(ST(i + 1));
+ h = strhash(bsid) & hm;
+ hh = HASHCHAIN_START;
+ while ((p = ht[h]) != 0)
+ {
+ const char *bsid2 = solvable_lookup_str(pool->solvables + p, buildservice_id);
+ if (!strcmp(bsid, bsid2))
+ break;
+ h = HASHCHAIN_NEXT(h, hh, hm);
+ }
+ if (!p)
+ continue;
+ s = pool->solvables + p;
+ h = (s->name + s->evr * 37 + s->arch * 129) & hm;
+ hh = HASHCHAIN_START;
+ while ((p = ht[h]) != 0)
+ {
+ Solvable *s2 = pool->solvables + p;
+ if (s->name == s2->name && s->evr == s2->evr && s->arch == s2->arch)
+ {
+ lastid = collectedmodules.count ? collectedmodules.elements[collectedmodules.count - 1] : 0;
+ solvable_lookup_idarray(s2, buildservice_modules, &modules);
+ for (j = 0; j < modules.count; j++)
+ if (modules.elements[j] != lastid)
+ queue_push(&collectedmodules, modules.elements[j]);
+ }
+ h = HASHCHAIN_NEXT(h, hh, hm);
+ }
+ }
+ solv_free(ht);
+ queue_free(&modules);
+ /* sort and unify */
+ solv_sort(collectedmodules.elements, collectedmodules.count, sizeof(Id), unifymodules_cmp, 0);
+ lastid = -1;
+ for (i = 0; i < collectedmodules.count; i++)
+ {
+ if (collectedmodules.elements[i] == lastid)
+ continue;
+ lastid = collectedmodules.elements[i];
+ XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid), 0)));
+ }
+ queue_free(&collectedmodules);
+ }
+
+void
+missingmodules(BSSolv::repo repo, ...)
+ PPCODE:
+ {
+ Pool *pool = repo->pool;
+ Id p, *pp, *modules, id, req, lastid1, lastid2;
+ Solvable *s;
+ Queue missingq;
+ int i, missing;
+
+ queue_init(&missingq);
+ if (pool->appdata && ((Id *)pool->appdata)[0] && has_keyname(repo, buildservice_modules))
+ {
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ if (s->name != buildservice_modules || s->arch != ARCH_SRC || !s->requires)
+ continue;
+ id = s->repo->idarraydata[s->provides];
+ for (modules = pool->appdata; *modules; modules++)
+ if (id == *modules)
+ break;
+ if (!*modules)
+ continue;
+ missing = 0;
+ for (pp = s->repo->idarraydata + s->requires; (req = *pp) != 0; pp++)
+ if (!match_modules_req(pool, req))
+ {
+ missing = 1;
+ queue_push2(&missingq, id, req);
+ }
+ if (!missing) /* we're good */
+ queue_push2(&missingq, id, 0);
+ }
+ /* sort and unify */
+ solv_sort(missingq.elements, missingq.count / 2, sizeof(Id) * 2, missingmodules_cmp, 0);
+ lastid1 = lastid2 = -1;
+ for (i = 0; i < missingq.count; i += 2)
+ {
+ if (missingq.elements[i] == lastid1 && missingq.elements[i + 1] == lastid2)
+ continue;
+ if (missingq.elements[i] != lastid1)
+ {
+ lastid1 = missingq.elements[i];
+ lastid2 = missingq.elements[i + 1];
+ }
+ if (!lastid2)
+ continue;
+ lastid2 = missingq.elements[i + 1];
+ XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid1), 0)));
+ XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid2), 0)));
+ }
+ queue_free(&missingq);
+ }
+ }
void
getpathid(BSSolv::repo repo)
unsigned int medianr;
const char *str;
str = solvable_get_location(s, &medianr);
+ /* We need to special case .obsbinlink here where the location
+ * points back into the package. We currently assume that
+ * the name in the full tree is always <name>.obsbinlnk */
+ if (!strncmp(str, "../", 3))
+ str = pool_tmpjoin(repo->pool, pool_id2str(repo->pool, s->name), ".obsbinlnk", 0);
PUSHs(sv_2mortal(newSVpv(str, 0)));
str = solvable_lookup_str(s, buildservice_id);
PUSHs(sv_2mortal(newSVpv(str, 0)));
RETVAL
void
+dodresources(BSSolv::repo repo)
+ PPCODE:
+ {
+ Pool *pool = repo->pool;
+ Queue dodresources;
+ int i;
+
+ queue_init(&dodresources);
+ repo_lookup_idarray(repo, SOLVID_META, buildservice_dodresources, &dodresources);
+ for (i = 0; i < dodresources.count; i++)
+ XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, dodresources.elements[i]), 0)));
+ queue_free(&dodresources);
+ }
+
+void
updatedoddata(BSSolv::repo repo, HV *rhv = 0)
CODE:
{
data = repo_add_repodata(repo, REPO_REUSE_REPODATA);
repodata_unset(data, SOLVID_META, buildservice_dodurl);
repodata_unset(data, SOLVID_META, buildservice_dodcookie);
+ repodata_unset(data, SOLVID_META, buildservice_dodresources);
/* add new data */
if (rhv)
- data2solvables(repo, data, rhv);
+ data2solvables(repo, data, (SV *)rhv, 1);
repo_internalize(repo);
}
+void
+setpriority(BSSolv::repo repo, int priority)
+ PPCODE:
+ repo->priority = priority;
+
+int
+mayhavemodules(BSSolv::repo repo)
+ CODE:
+ RETVAL = has_keyname(repo, buildservice_modules);
+ OUTPUT:
+ RETVAL
+
+void
+getmodules(BSSolv::repo repo)
+ PPCODE:
+ if (has_keyname(repo, buildservice_modules))
+ {
+ Pool *pool = repo->pool;
+ Id p, lastid = -1;
+ Solvable *s;
+ Queue collectedmodules;
+ int i;
+
+ queue_init(&collectedmodules);
+ FOR_REPO_SOLVABLES(repo, p, s)
+ if (s->name == buildservice_modules && s->arch == ARCH_SRC && s->repo->idarraydata[s->provides])
+ queue_push(&collectedmodules, s->repo->idarraydata[s->provides]);
+ if (!collectedmodules.count)
+ {
+ Queue modules;
+ queue_init(&modules);
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ solvable_lookup_idarray(pool->solvables + p, buildservice_modules, &modules);
+ for (i = 0; i < modules.count; i++)
+ {
+ if (modules.elements[i] == lastid)
+ continue;
+ lastid = modules.elements[i];
+ queue_push(&collectedmodules, modules.elements[i]);
+ }
+ }
+ queue_free(&modules);
+ }
+ /* sort and unify */
+ solv_sort(collectedmodules.elements, collectedmodules.count, sizeof(Id), unifymodules_cmp, 0);
+ lastid = -1;
+ for (i = 0; i < collectedmodules.count; i++)
+ {
+ if (collectedmodules.elements[i] == lastid)
+ continue;
+ lastid = collectedmodules.elements[i];
+ XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid), 0)));
+ }
+ queue_free(&collectedmodules);
+ }
+
+void
+getdodblobs(BSSolv::repo repo)
+ PPCODE:
+ {
+ Pool *pool = repo->pool;
+ int i;
+ Id p;
+ Solvable *s;
+ Stringpool ss;
+ stringpool_init_empty(&ss);
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ const char *str = solvable_lookup_str(s, buildservice_id);
+ unsigned int medianr;
+ const char *s, *se;
+ if (!str || strcmp(str, "dod") != 0)
+ continue;
+ s = solvable_get_location(pool->solvables + p, &medianr);
+ if ((s = strrchr(s, '?')) == 0)
+ continue;
+ for (++s; s; s = se ? se + 1 : 0)
+ {
+ se = strchr(s, ',');
+ if (se)
+ stringpool_strn2id(&ss, s, se - s, 1);
+ else
+ stringpool_str2id(&ss, s, 1);
+ }
+ }
+ for (i = 2; i < ss.nstrings; i++)
+ {
+ XPUSHs(sv_2mortal(newSVpv(stringpool_id2str(&ss, i), 0)));
+ }
+ stringpool_free(&ss);
+ }
-MODULE = BSSolv PACKAGE = BSSolv::expander PREFIX = expander
+MODULE = BSSolv PACKAGE = BSSolv::expander PREFIX = expander
BSSolv::expander
new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
CODE:
{
SV *sv, **svp;
- char *str;
- int i, neg;
- Id id, id2;
+ char *str, *p;
+ int i;
+ Id id;
Expander *xp;
-
- xp = calloc(sizeof(Expander), 1);
- xp->pool = pool;
+ Queue preferpos;
+ Queue preferneg;
+ Queue ignore;
+ Queue conflict;
+ Queue fileprovides;
+ int debug = 0;
+ int options = 0;
+
+ queue_init(&preferpos);
+ queue_init(&preferneg);
+ queue_init(&ignore);
+ queue_init(&conflict);
+ queue_init(&fileprovides);
svp = hv_fetch(config, "prefer", 6, 0);
sv = svp ? *svp : 0;
if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)
str = SvPV_nolen(sv);
if (!str)
continue;
- neg = 0;
if (*str == '-')
- {
- neg = 1;
- str++;
- }
- id = pool_str2id(pool, str, 1);
- id2 = 0;
- if ((str = strchr(str, ':')) != 0)
- id2 = pool_str2id(pool, str + 1, 1);
- if (neg)
- {
- MAPEXP(&xp->preferneg, id);
- MAPSET(&xp->preferneg, id);
- if (id2)
- {
- MAPEXP(&xp->prefernegx, id2);
- MAPSET(&xp->prefernegx, id2);
- }
- }
+ queue_push(&preferneg, pool_str2id(pool, str + 1, 1));
else
- {
- queue_push(&xp->preferposq, id);
- MAPEXP(&xp->preferpos, id);
- MAPSET(&xp->preferpos, id);
- if (id2)
- {
- MAPEXP(&xp->preferposx, id2);
- MAPSET(&xp->preferposx, id2);
- }
- }
+ queue_push(&preferpos, pool_str2id(pool, str, 1));
}
}
svp = hv_fetch(config, "ignoreh", 7, 0);
{
HV *hv = (HV *)SvRV(sv);
HE *he;
-
hv_iterinit(hv);
while ((he = hv_iternext(hv)) != 0)
{
str = hv_iterkey(he, &strl);
if (!str)
continue;
-
- id = pool_str2id(pool, str, 1);
- id2 = 0;
- if ((str = strchr(str, ':')) != 0)
- id2 = pool_str2id(pool, str + 1, 1);
- MAPEXP(&xp->ignored, id);
- MAPSET(&xp->ignored, id);
- if (id2)
- {
- MAPEXP(&xp->ignoredx, id2);
- MAPSET(&xp->ignoredx, id2);
- }
+ queue_push(&ignore, pool_str2id(pool, str, 1));
}
}
svp = hv_fetch(config, "conflict", 8, 0);
AV *av = (AV *)SvRV(sv);
for (i = 0; i <= av_len(av); i++)
{
- char *p;
- Id id2;
-
svp = av_fetch(av, i, 0);
if (!svp)
continue;
str = p + 1;
while ((p = strchr(str, ',')) != 0)
{
- id2 = pool_strn2id(pool, str, p - str, 1);
- queue_push2(&xp->conflictsq, id, id2);
- MAPEXP(&xp->conflicts, id);
- MAPSET(&xp->conflicts, id);
- MAPEXP(&xp->conflicts, id2);
- MAPSET(&xp->conflicts, id2);
+ queue_push2(&conflict, id, pool_strn2id(pool, str, p - str, 1));
str = p + 1;
}
- id2 = pool_str2id(pool, str, 1);
- queue_push2(&xp->conflictsq, id, id2);
- MAPEXP(&xp->conflicts, id);
- MAPSET(&xp->conflicts, id);
- MAPEXP(&xp->conflicts, id2);
- MAPSET(&xp->conflicts, id2);
+ queue_push2(&conflict, id, pool_str2id(pool, str, 1));
}
}
- /* XXX: this modifies the pool, which is a bit unclean! */
svp = hv_fetch(config, "fileprovides", 12, 0);
sv = svp ? *svp : 0;
if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV)
{
HV *hv = (HV *)SvRV(sv);
I32 strl;
- Queue q;
- xp->havefileprovides = 1;
hv_iterinit(hv);
- queue_init(&q);
while ((sv = hv_iternextsv(hv, &str, &strl)) != 0)
{
AV *av;
- Id p, pp;
- int havenew = 0;
+ Id id2;
if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV)
continue;
id = pool_str2id(pool, str, 1);
- queue_empty(&q);
- FOR_PROVIDES(p, pp, id)
- queue_push(&q, p);
av = (AV *)SvRV(sv);
for (i = 0; i <= av_len(av); i++)
{
if (!str)
continue;
id2 = pool_str2id(pool, str, 0);
- FOR_PROVIDES(p, pp, id2)
+ if (!id2)
+ continue;
+ if (id)
{
- int j;
- for (j = 0; j < q.count; j++)
- {
- if (q.elements[j] == p)
- break;
- if (q.elements[j] > p)
- {
- queue_insert(&q, j, p);
- havenew = 1;
- break;
- }
- }
- if (j == q.count)
- {
- queue_push(&q, p);
- havenew = 1;
- }
+ queue_push(&fileprovides, id); /* start name block */
+ id = 0;
}
+ queue_push(&fileprovides, id2);
}
- if (havenew)
- pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
+ if (id == 0)
+ queue_push(&fileprovides, 0); /* had at least one entry, finish name block */
}
- queue_free(&q);
}
+ options |= EXPANDER_OPTION_USERECOMMENDSFORCHOICES;
svp = hv_fetch(config, "expandflags:ignoreconflicts", 27, 0);
sv = svp ? *svp : 0;
if (sv && SvTRUE(sv))
- xp->ignoreconflicts = 1;
- svp = hv_fetch(config, "expand_dbg", 10, 0);
+ options |= EXPANDER_OPTION_IGNORECONFLICTS;
+ svp = hv_fetch(config, "expandflags:dorecommends", 24, 0);
sv = svp ? *svp : 0;
if (sv && SvTRUE(sv))
- xp->debug = 1;
- sv = get_sv("Build::expand_dbg", FALSE);
+ options |= EXPANDER_OPTION_DORECOMMENDS;
+ svp = hv_fetch(config, "expandflags:dosupplements", 25, 0);
+ sv = svp ? *svp : 0;
if (sv && SvTRUE(sv))
- xp->debug = 1;
- xp->userecommendsforchoices = 1;
+ options |= EXPANDER_OPTION_DOSUPPLEMENTS | EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES;
+ svp = hv_fetch(config, "expand_dbg", 10, 0);
+ sv = svp ? *svp : 0;
+ if (sv && SvOK(sv))
+ debug = SvIV(sv);
+ else
+ {
+ sv = get_sv("Build::expand_dbg", FALSE);
+ if (sv && SvOK(sv))
+ debug = SvIV(sv);
+ }
+ xp = expander_create(pool, &preferpos, &preferneg, &ignore, &conflict, &fileprovides, debug, options);
+ queue_free(&preferpos);
+ queue_free(&preferneg);
+ queue_free(&ignore);
+ queue_free(&conflict);
+ queue_free(&fileprovides);
RETVAL = xp;
}
OUTPUT:
{
Pool *pool;
int i, nerrors;
- Id id, who, conflbuf[16];
- Queue revertignore, in, out, confl;
- int oldignoreignore = xp->ignoreignore;
- int ignoreignore = 0;
- Map oldignored, oldignoredx;
- int ignoremapssaved = 0;
-
- queue_init(&revertignore);
+ Id id, who, indepbuf[64];
+ Queue ignoreq, in, out, indep;
+ int directdepsend = 0;
+ int options = 0;
+
+ queue_init(&ignoreq);
queue_init(&in);
queue_init(&out);
- queue_init_buffer(&confl, conflbuf, sizeof(conflbuf)/sizeof(*conflbuf));
+ queue_init_buffer(&indep, indepbuf, sizeof(indepbuf)/sizeof(*indepbuf));
pool = xp->pool;
if (xp->debug)
expander_dbg(xp, "expand args:");
for (i = 1; i < items; i++)
{
char *s = SvPV_nolen(ST(i));
+ int deptype = DEPTYPE_REQUIRES;
+
if (xp->debug)
expander_dbg(xp, " %s", s);
+ if (*s == '-' && s[1] == '-')
+ {
+ /* expand option */
+ if (!strcmp(s, "--ignoreignore--"))
+ options |= EXPANDER_OPTION_IGNOREIGNORE;
+ else if (!strcmp(s, "--directdepsend--"))
+ directdepsend = 1;
+ else if (!strcmp(s, "--dorecommends--"))
+ options |= EXPANDER_OPTION_DORECOMMENDS;
+ else if (!strcmp(s, "--dosupplements--"))
+ options |= EXPANDER_OPTION_DOSUPPLEMENTS | EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES;
+ else if (!strcmp(s, "--ignoreconflicts--"))
+ options |= EXPANDER_OPTION_IGNORECONFLICTS;
+ continue;
+ }
if (*s == '-')
{
- Id id;
- if (s[1] == '-' && !strcmp(s, "--ignoreignore--"))
- {
- ignoreignore = 1;
- continue;
- }
+ /* ignore dependency */
id = pool_str2id(pool, s + 1, 1);
- if (id == expander_directdepsend)
- {
- queue_push(&in, id);
- continue;
- }
- queue_push(&revertignore, id);
+ queue_push(&ignoreq, id);
+ continue;
}
- else if (*s == '!')
+ if (*s == '!')
{
- Id id = dep2id(pool, s + (s[1] == '!' ? 2 : 1));
- queue_push2(&confl, id, s[1] == '!' ? 1 : 0);
+ deptype = DEPTYPE_CONFLICTS;
+ s++;
+ if (*s == '!')
+ {
+ deptype = DEPTYPE_OBSOLETES;
+ s++;
+ }
}
+ id = dep2id(pool, s);
+ if (deptype == DEPTYPE_REQUIRES && !directdepsend)
+ queue_push(&in, id);
else
- {
- Id id = dep2id(pool, s);
- queue_push(&in, id);
- }
+ queue_push2(&indep, deptype, id);
}
if (xp->debug)
expander_dbg(xp, "\n");
- if (ignoreignore && revertignore.count)
- {
- /* bad: have direct ignores and project config ignores */
- oldignored = xp->ignored;
- oldignoredx = xp->ignoredx;
- ignoremapssaved = 1;
- /* clear project config maps */
- memset(&xp->ignored, 0, sizeof(xp->ignored));
- memset(&xp->ignoredx, 0, sizeof(xp->ignoredx));
- }
-
- if (revertignore.count)
- {
- /* mix direct ignores with ignores from project config */
- int revertcnt = revertignore.count;
- for (i = 0; i < revertcnt; i++)
- {
- const char *ss;
- id = revertignore.elements[i];
- MAPEXP(&xp->ignored, id);
- if (MAPTST(&xp->ignored, id))
- continue;
- MAPSET(&xp->ignored, id);
- queue_push(&revertignore, id);
- if ((ss = strchr(pool_id2str(pool, id), ':')) != 0)
- {
- id = pool_str2id(pool, ss + 1, 1);
- MAPEXP(&xp->ignoredx, id);
- if (MAPTST(&xp->ignoredx, id))
- continue;
- MAPSET(&xp->ignoredx, id);
- queue_push(&revertignore, -id);
- }
- }
- queue_deleten(&revertignore, 0, revertcnt);
- }
- else if (ignoreignore)
- {
- /* no direct ignores, disable ignore processing */
- xp->ignoreignore = 1;
- }
-
- MAPEXP(&xp->ignored, pool->ss.nstrings);
- MAPEXP(&xp->ignoredx, pool->ss.nstrings);
- MAPEXP(&xp->preferpos, pool->ss.nstrings);
- MAPEXP(&xp->preferposx, pool->ss.nstrings);
- MAPEXP(&xp->preferneg, pool->ss.nstrings);
- MAPEXP(&xp->prefernegx, pool->ss.nstrings);
- MAPEXP(&xp->conflicts, pool->ss.nstrings);
-
- nerrors = expander_expand(xp, &in, &out, &confl);
-
- /* revert ignores */
- xp->ignoreignore = oldignoreignore;
- if (ignoremapssaved)
- {
- map_free(&xp->ignored);
- map_free(&xp->ignoredx);
- xp->ignored = oldignored;
- xp->ignoredx = oldignoredx;
- }
- else
- {
- for (i = 0; i < revertignore.count; i++)
- {
- id = revertignore.elements[i];
- if (id > 0)
- MAPCLR(&xp->ignored, id);
- else
- MAPCLR(&xp->ignoredx, -id);
- }
- }
- queue_free(&revertignore);
+ nerrors = expander_expand(xp, &in, &indep, &out, &ignoreq, options);
queue_free(&in);
- queue_free(&confl);
+ queue_free(&indep);
+ queue_free(&ignoreq);
if (nerrors)
{
id = out.elements[i + 1];
who = out.elements[i + 2];
if (who)
- sv = newSVpvf("nothing provides %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
+ sv = newSVpvf("nothing provides %s needed by %s", pool_dep2str(pool, id), solvid2name(pool, who));
else
sv = newSVpvf("nothing provides %s", pool_dep2str(pool, id));
i += 3;
}
- else if (type == ERROR_CONFLICTINGPROVIDER)
+ else if (type == ERROR_ALLCONFLICT)
{
id = out.elements[i + 1];
who = out.elements[i + 2];
if (who)
- sv = newSVpvf("conflict for provider of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
+ sv = newSVpvf("%s conflicts with always true %s", solvid2name(pool, who), pool_dep2str(pool, id));
+ else
+ sv = newSVpvf("conflict with always true %s", pool_dep2str(pool, id));
+ i += 3;
+ }
+ else if (type == ERROR_CONFLICT)
+ {
+ Id who2 = out.elements[i + 2];
+ who = out.elements[i + 1];
+ if (!who && who2 >= 0)
+ sv = newSVpvf("conflicts with %s", solvid2name(pool, who2));
+ else if (who2 < 0)
+ sv = newSVpvf("%s obsoletes %s", solvid2name(pool, who), solvid2name(pool, -who2));
+ else
+ sv = newSVpvf("%s conflicts with %s", solvid2name(pool, who), solvid2name(pool, who2));
+ i += 3;
+ }
+ else if (type == ERROR_CONFLICT2)
+ {
+ Id who2 = out.elements[i + 2];
+ who = out.elements[i + 1];
+ if (who2 < 0)
+ sv = newSVpvf("%s is obsoleted by %s", solvid2name(pool, who), solvid2name(pool, -who2));
+ else if (who2 > 0)
+ sv = newSVpvf("%s is in conflict with %s", solvid2name(pool, who), solvid2name(pool, who2));
else
- sv = newSVpvf("conflict for provider of %s", pool_dep2str(pool, id));
+ sv = newSVpvf("%s is in conflict", solvid2name(pool, who));
i += 3;
}
else if (type == ERROR_CONFLICTINGPROVIDERS)
id = out.elements[i + 1];
who = out.elements[i + 2];
if (who)
- sv = newSVpvf("conflict for all providers of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
+ sv = newSVpvf("conflict for providers of %s needed by %s", pool_dep2str(pool, id), solvid2name(pool, who));
else
- sv = newSVpvf("conflict for all providers of %s", pool_dep2str(pool, id));
+ sv = newSVpvf("conflict for providers of %s", pool_dep2str(pool, id));
i += 3;
}
else if (type == ERROR_PROVIDERINFO)
Id who2 = out.elements[i + 2];
who = out.elements[i + 1];
if (who2 < 0)
- sv = newSVpvf("(provider %s obsoletes installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name));
+ sv = newSVpvf("(provider %s obsoletes %s)", solvid2name(pool, who), solvid2name(pool, -who2));
else
- sv = newSVpvf("(provider %s conflicts with installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name));
+ sv = newSVpvf("(provider %s conflicts with %s)", solvid2name(pool, who), solvid2name(pool, who2));
i += 3;
}
else if (type == ERROR_PROVIDERINFO2)
Id who2 = out.elements[i + 2];
who = out.elements[i + 1];
if (who2 < 0)
- sv = newSVpvf("(provider %s is obsoleted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name));
+ sv = newSVpvf("(provider %s is obsoleted by %s)", solvid2name(pool, who), solvid2name(pool, -who2));
else if (who2 > 0)
- sv = newSVpvf("(provider %s is conflicted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name));
+ sv = newSVpvf("(provider %s is in conflict with %s)", solvid2name(pool, who), solvid2name(pool, who2));
else
- sv = newSVpvf("(provider %s is conflicted by the build config)", pool_id2str(pool, pool->solvables[who].name));
+ sv = newSVpvf("(provider %s is in conflict)", solvid2name(pool, who));
i += 3;
}
else if (type == ERROR_CHOICE)
int j;
char *str = "";
for (j = i + 3; out.elements[j]; j++)
+ ;
+ solv_sort(out.elements + i + 3, j - (i + 3), sizeof(Id), pkgname_sort_cmp, pool);
+ for (j = i + 3; out.elements[j]; j++)
{
Solvable *s = pool->solvables + out.elements[j];
str = pool_tmpjoin(pool, str, " ", pool_id2str(pool, s->name));
id = out.elements[i + 1];
who = out.elements[i + 2];
if (who)
- sv = newSVpvf("have choice for %s needed by %s: %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name), str);
+ sv = newSVpvf("have choice for %s needed by %s: %s", pool_dep2str(pool, id), solvid2name(pool, who), str);
else
sv = newSVpvf("have choice for %s: %s", pool_dep2str(pool, id), str);
i = j + 1;
}
+ else if (type == ERROR_BADDEPENDENCY)
+ {
+ id = out.elements[i + 1];
+ who = out.elements[i + 2];
+ if (who)
+ sv = newSVpvf("cannot parse dependency %s from %s", pool_dep2str(pool, id), solvid2name(pool, who));
+ else
+ sv = newSVpvf("cannot parse dependency %s", pool_dep2str(pool, id));
+ i += 3;
+ }
+ else if (type == ERROR_NOPROVIDERINFO)
+ {
+ id = out.elements[i + 1];
+ who = out.elements[i + 2];
+ if (who)
+ sv = newSVpvf("(got version %s provided by %s)", pool_id2str(pool, id), solvid2name(pool, who));
+ else
+ sv = newSVpvf("(got version %s)", pool_id2str(pool, id));
+ i += 3;
+ }
else
croak("expander: bad error type\n");
PUSHs(sv_2mortal(sv));
queue_free(&out);
}
+void
+debug(BSSolv::expander xp, const char *str)
+ CODE:
+ expander_dbg(xp, "%s", str);
+
+
const char *
debugstr(BSSolv::expander xp)
CODE:
- if (!xp->debugstr)
- xp->debugstr = calloc(1, 1);
- RETVAL = xp->debugstr;
+ RETVAL = xp->debugstr ? xp->debugstr : "";
OUTPUT:
RETVAL
+const char *
+debugstrclr(BSSolv::expander xp)
+
+ CODE:
+ RETVAL = xp->debugstr ? xp->debugstr : "";
+ OUTPUT:
+ RETVAL
+ CLEANUP:
+ expander_clrdbg(xp);
void
DESTROY(BSSolv::expander xp)
CODE:
- map_free(&xp->ignored);
- map_free(&xp->ignoredx);
- queue_free(&xp->preferposq);
- map_free(&xp->preferpos);
- map_free(&xp->preferposx);
- map_free(&xp->preferneg);
- map_free(&xp->prefernegx);
- queue_free(&xp->conflictsq);
- map_free(&xp->conflicts);
- solv_free(xp->debugstr);
- solv_free(xp);
+ expander_free(xp);
+