diff options
-rw-r--r-- | VERSION.cmake | 2 | ||||
-rw-r--r-- | ext/repo_rpmdb.c | 81 | ||||
-rw-r--r-- | ext/repo_rpmmd.c | 283 | ||||
-rw-r--r-- | ext/testcase.c | 17 | ||||
-rw-r--r-- | package/libsolv.changes | 12 | ||||
-rw-r--r-- | src/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/diskusage.c | 348 | ||||
-rw-r--r-- | src/fileprovides.c | 373 | ||||
-rw-r--r-- | src/knownid.h | 2 | ||||
-rw-r--r-- | src/libsolv.ver | 1 | ||||
-rw-r--r-- | src/linkedpkg.c | 27 | ||||
-rw-r--r-- | src/linkedpkg.h | 3 | ||||
-rw-r--r-- | src/pool.c | 715 | ||||
-rw-r--r-- | src/pool.h | 11 | ||||
-rw-r--r-- | src/poolid.c | 19 | ||||
-rw-r--r-- | src/repodata.c | 25 | ||||
-rw-r--r-- | src/repodata.h | 3 | ||||
-rw-r--r-- | src/rules.c | 206 | ||||
-rw-r--r-- | src/rules.h | 3 | ||||
-rw-r--r-- | src/selection.c | 10 | ||||
-rw-r--r-- | src/solver.c | 37 | ||||
-rw-r--r-- | src/util.c | 4 |
22 files changed, 1330 insertions, 855 deletions
diff --git a/VERSION.cmake b/VERSION.cmake index d496f5b..1b3fd7d 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "0") SET(LIBSOLV_MAJOR "0") SET(LIBSOLV_MINOR "6") -SET(LIBSOLV_PATCH "19") +SET(LIBSOLV_PATCH "20") diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c index d49f9d8..308cfe5 100644 --- a/ext/repo_rpmdb.c +++ b/ext/repo_rpmdb.c @@ -407,18 +407,27 @@ setutf8string(Repodata *repodata, Id handle, Id tag, const char *str) repodata_set_str(repodata, handle, tag, str); } +static int +ignq_sortcmp(const void *va, const void *vb, void *dp) +{ + int r = *(Id *)va - *(Id *)vb; + if (!r) + r = ((Id *)va)[1] - ((Id *)vb)[1]; + return r; +} + /* * strong: 0: ignore strongness * 1: filter to strong * 2: filter to weak */ static unsigned int -makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags) +makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags, Queue *ignq) { char **n, **v; unsigned int *f; int i, cc, nc, vc, fc; - int haspre, premask; + int haspre, premask, has_ign; unsigned int olddeps; Id *ida; int strong = 0; @@ -512,6 +521,8 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, cc += haspre; /* add slot for the prereq marker */ olddeps = repo_reserve_ids(repo, 0, cc); ida = repo->idarraydata + olddeps; + + has_ign = 0; for (i = 0; ; i++) { Id id; @@ -564,12 +575,33 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, id = pool_rel2id(pool, id, evr, fl, 1); } *ida++ = id; + if (haspre == 2 && ignq) + { + int is_ign = (f[i] & DEP_PRE_IN) != 0 && (f[i] & DEP_PRE_UN) == 0 ? 1 : 0; + has_ign |= is_ign; + queue_push2(ignq, id, is_ign); + } } *ida++ = 0; repo->idarraysize += cc + 1; solv_free(n); solv_free(v); solv_free(f); + if (has_ign && ignq->count > 2) + { + Id id, lastid = 0; + int j; + + solv_sort(ignq->elements, ignq->count / 2, sizeof(Id) * 2, ignq_sortcmp, 0); + for (i = j = 0; i < ignq->count; i += 2) + { + id = ignq->elements[i]; + if (id != lastid && ignq->elements[i + 1] > 0) + ignq->elements[j++] = id; + lastid = id; + } + queue_truncate(ignq, j); + } return olddeps; } @@ -909,6 +941,8 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, char *name; char *evr; char *sourcerpm; + Queue ignq; + Id ignqbuf[64]; name = headstring(rpmhead, TAG_NAME); if (!name) @@ -935,21 +969,27 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, s->evr = pool_str2id(pool, evr, 1); s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1); - s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0); + queue_init_buffer(&ignq, ignqbuf, sizeof(ignqbuf)/sizeof(*ignqbuf)); + + s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0, 0); if (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); - s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags); - s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0); - s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0); + s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags, &ignq); + s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0, 0); + s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0, 0); - s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0); - s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0); - s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0); - s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0); + s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0, 0); + s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0, 0); + s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0, 0); + s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0, 0); s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0); s->conflicts = repo_fix_conflicts(repo, s->conflicts); + if (data && ignq.count) + repodata_set_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, &ignq); + queue_free(&ignq); + if (data) { Id handle; @@ -1014,24 +1054,11 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, repodata_set_sourcepkg(data, handle, sourcerpm); if ((flags & RPM_ADD_TRIGGERS) != 0) { - Id id, lastid; - unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0); - - lastid = 0; - for (; (id = repo->idarraydata[ida]) != 0; ida++) - { - /* we currently do not support rel ids in incore data, so - * strip off versioning information */ - while (ISRELDEP(id)) - { - Reldep *rd = GETRELDEP(pool, id); - id = rd->name; - } - if (id == lastid) - continue; + unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0, 0); + Id id, lastid = 0; + for (lastid = 0; (id = repo->idarraydata[ida]) != 0; ida++, lastid = id) + if (id != lastid) repodata_add_idarray(data, handle, SOLVABLE_TRIGGERS, id); - lastid = id; - } } if ((flags & RPM_ADD_NO_FILELIST) == 0) addfilelist(data, handle, rpmhead, flags); diff --git a/ext/repo_rpmmd.c b/ext/repo_rpmmd.c index a45d491..78264cc 100644 --- a/ext/repo_rpmmd.c +++ b/ext/repo_rpmmd.c @@ -258,12 +258,15 @@ struct parsedata { Id changelog_handle; - /** Hash to maps checksums to solv */ - Stringpool cspool; - /** Cache of known checksums to solvable id */ - Id *cscache; - /* the current longest index in the table */ - int ncscache; + int extending; /* are we extending an existing solvable? */ + int first; /* first solvable we added */ + int cshash_filled; /* hash is filled with data */ + + Hashtable cshash; /* checksum hash -> offset into csdata */ + Hashval cshashm; /* hash mask */ + int ncshash; /* entries used */ + unsigned char *csdata; /* [len, checksum, id] */ + int ncsdata; /* used bytes */ }; static Id @@ -577,6 +580,156 @@ set_description_author(Repodata *data, Id handle, char *str, struct parsedata *p /*-----------------------------------------------*/ +/* checksum hash functions + * + * used to look up a solvable with the checksum for solvable extension purposes. + * + */ + +static void +init_cshash(struct parsedata *pd) +{ +} + +static void +free_cshash(struct parsedata *pd) +{ + pd->cshash = solv_free(pd->cshash); + pd->ncshash = 0; + pd->cshashm = 0; + pd->csdata = solv_free(pd->csdata); + pd->ncsdata = 0; +} + +static inline Hashval +hashkey(const unsigned char *key, int keyl) +{ + return key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3]; +} + +static void +rebuild_cshash(struct parsedata *pd) +{ + Hashval h, hh, hm; + Hashtable ht; + unsigned char *d, *de; + + hm = pd->cshashm; +#if 0 + fprintf(stderr, "rebuild cshash with mask 0x%x\n", hm); +#endif + solv_free(pd->cshash); + ht = pd->cshash = (Hashtable)solv_calloc(hm + 1, sizeof(Id)); + d = pd->csdata; + de = d + pd->ncsdata; + while (d != de) + { + h = hashkey(d + 1, d[0] + 1) & hm; + hh = HASHCHAIN_START; + while (ht[h]) + h = HASHCHAIN_NEXT(h, hh, hm); + ht[h] = d + 1 - pd->csdata; + d += 2 + d[0] + sizeof(Id); + } +} + +static void +put_in_cshash(struct parsedata *pd, const unsigned char *key, int keyl, Id id) +{ + Hashtable ht; + Hashval h, hh, hm; + unsigned char *d; + + if (keyl < 4 || keyl > 256) + return; + ht = pd->cshash; + hm = pd->cshashm; + h = hashkey(key, keyl) & hm; + hh = HASHCHAIN_START; + if (ht) + { + while (ht[h]) + { + unsigned char *d = pd->csdata + ht[h]; + if (d[-1] == keyl && !memcmp(key, d, keyl)) + return; /* XXX: first id wins... */ + h = HASHCHAIN_NEXT(h, hh, hm); + } + } + /* a new entry. put in csdata */ + pd->csdata = solv_extend(pd->csdata, pd->ncsdata, 1, 1 + keyl + sizeof(Id), 4095); + d = pd->csdata + pd->ncsdata; + d[0] = keyl - 1; + memcpy(d + 1, key, keyl); + memcpy(d + 1 + keyl, &id, sizeof(Id)); + pd->ncsdata += 1 + keyl + sizeof(Id); + if ((Hashval)++pd->ncshash * 2 > hm) + { + pd->cshashm = pd->cshashm ? (2 * pd->cshashm + 1) : 4095; + rebuild_cshash(pd); + } + else + ht[h] = pd->ncsdata - (keyl + sizeof(Id)); +} + +static Id +lookup_cshash(struct parsedata *pd, const unsigned char *key, int keyl) +{ + Hashtable ht; + Hashval h, hh, hm; + + if (keyl < 4 || keyl > 256) + return 0; + ht = pd->cshash; + if (!ht) + return 0; + hm = pd->cshashm; + h = hashkey(key, keyl) & hm; + hh = HASHCHAIN_START; + while (ht[h]) + { + unsigned char *d = pd->csdata + ht[h]; + if (d[-1] == keyl - 1 && !memcmp(key, d, keyl)) + { + Id id; + memcpy(&id, d + keyl, sizeof(Id)); + return id; + } + h = HASHCHAIN_NEXT(h, hh, hm); + } + return 0; +} + +static void +fill_cshash_from_repo(struct parsedata *pd) +{ + Dataiterator di; + /* setup join data */ + dataiterator_init(&di, pd->pool, pd->repo, 0, SOLVABLE_CHECKSUM, 0, 0); + while (dataiterator_step(&di)) + put_in_cshash(pd, (const unsigned char *)di.kv.str, solv_chksum_len(di.key->type), di.solvid); + dataiterator_free(&di); +} + +static void +fill_cshash_from_new_solvables(struct parsedata *pd) +{ + Pool *pool = pd->pool; + Id cstype = 0; + unsigned const char *cs; + int i; + + for (i = pd->first; i < pool->nsolvables; i++) + { + if (pool->solvables[i].repo != pd->repo) + continue; + cs = repodata_lookup_bin_checksum_uninternalized(pd->data, i, SOLVABLE_CHECKSUM, &cstype); + if (cs) + put_in_cshash(pd, cs, solv_chksum_len(cstype), i); + } +} + +/*-----------------------------------------------*/ /* XML callbacks */ /* @@ -664,26 +817,45 @@ startElement(void *userData, const char *name, const char **atts) a new solvable but just append the attributes to the existing one. */ + pd->extending = 0; if ((pkgid = find_attr("pkgid", atts)) != NULL) { + unsigned char chk[256]; + int l; + const char *str = pkgid; + if (!pd->cshash_filled) + { + pd->cshash_filled = 1; + fill_cshash_from_new_solvables(pd); + } + handle = 0; + /* convert into bin checksum */ + l = solv_hex2bin(&str, chk, sizeof(chk)); /* look at the checksum cache */ - Id index = stringpool_str2id(&pd->cspool, pkgid, 0); - if (!index || index >= pd->ncscache || !pd->cscache[index]) + if (l >= 4 && !pkgid[2 * l]) + handle = lookup_cshash(pd, chk, l); +#if 0 + fprintf(stderr, "Lookup %s -> %d\n", pkgid, handle); +#endif + if (!handle) { pool_debug(pool, SOLV_WARN, "the repository specifies extra information about package with checksum '%s', which does not exist in the repository.\n", pkgid); - pd->solvable = 0; pd->handle = 0; + pd->solvable = 0; break; } - pd->solvable = pool_id2solvable(pool, pd->cscache[index]); + pd->extending = 1; } else { /* this is a new package */ - pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo)); + handle = repo_add_solvable(pd->repo); + if (!pd->first) + pd->first = handle; pd->freshens = 0; } - pd->handle = handle = pd->solvable - pool->solvables; + pd->handle = handle; + pd->solvable = pool_id2solvable(pool, handle); if (pd->kind && pd->kind[1] == 'r') { /* products can have a type */ @@ -697,6 +869,8 @@ startElement(void *userData, const char *name, const char **atts) break; case STATE_VERSION: + if (pd->extending && s->evr) + break; /* ignore version tag repetition in extend data */ s->evr = makeevr_atts(pool, pd, atts); break; case STATE_PROVIDES: @@ -840,15 +1014,24 @@ startElement(void *userData, const char *name, const char **atts) { long filesz = 0, filenum = 0; Id dirid; - if ((str = find_attr("name", atts)) != 0) - dirid = repodata_str2dir(pd->data, str, 1); - else - { + if ((str = find_attr("name", atts)) == 0) + { pd->ret = pool_error(pool, -1, "<dir .../> tag without 'name' attribute"); break; - } - if (!dirid) - dirid = repodata_str2dir(pd->data, "/", 1); + } + if (*str != '/') + { + int l = strlen(str) + 2; + if (l > pd->acontent) + { + pd->content = solv_realloc(pd->content, l + 256); + pd->acontent = l + 256; + } + *pd->content = '/'; + strcpy(pd->content + 1, str); + str = pd->content; + } + dirid = repodata_str2dir(pd->data, str, 1); if ((str = find_attr("size", atts)) != 0) filesz = strtol(str, 0, 0); if ((str = find_attr("count", atts)) != 0) @@ -923,6 +1106,11 @@ endElement(void *userData, const char *name) switch (pd->state) { case STATE_SOLVABLE: + if (pd->extending) + { + pd->solvable = 0; + break; + } if (pd->kind && !s->name) /* add namespace in case of NULL name */ s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", 0), 1); if (!s->arch) @@ -935,7 +1123,7 @@ endElement(void *userData, const char *name) s->conflicts = repo_fix_conflicts(repo, s->conflicts); pd->freshens = 0; pd->kind = 0; - pd->solvable = s = 0; + pd->solvable = 0; break; case STATE_NAME: if (pd->kind) @@ -957,26 +1145,20 @@ endElement(void *userData, const char *name) break; case STATE_CHECKSUM: { - Id index; - - if (!pd->chksumtype) + unsigned char chk[256]; + int l = solv_chksum_len(pd->chksumtype); + const char *str = pd->content; + if (!l || l > sizeof(chk)) break; - if (strlen(pd->content) != 2 * solv_chksum_len(pd->chksumtype)) + if (solv_hex2bin(&str, chk, l) != l || pd->content[2 * l]) { - pd->ret = pool_error(pool, -1, "line %d: invalid checksum length for %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype)); + pd->ret = pool_error(pool, -1, "line %u: invalid %s checksum", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype)); break; } - repodata_set_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, pd->content); - /* we save the checksum to solvable id relationship for extended - metadata */ - index = stringpool_str2id(&pd->cspool, pd->content, 1 /* create it */); - if (index >= pd->ncscache) - { - pd->cscache = solv_zextend(pd->cscache, pd->ncscache, index + 1 - pd->ncscache, sizeof(Id), 255); - pd->ncscache = index + 1; - } - /* add the checksum to the cache */ - pd->cscache[index] = s - pool->solvables; + repodata_set_bin_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, chk); + /* we save the checksum to solvable id relationship for extending metadata */ + if (pd->cshash_filled) + put_in_cshash(pd, chk, l, s - pool->solvables); break; } case STATE_FILE: @@ -1165,32 +1347,12 @@ repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags) pd.kind = 0; pd.language = language && *language && strcmp(language, "en") != 0 ? language : 0; - /* initialize the string pool where we will store - the package checksums we know about, to get an Id - we can use in a cache */ - stringpool_init_empty(&pd.cspool); + init_cshash(&pd); if ((flags & REPO_EXTEND_SOLVABLES) != 0) { /* setup join data */ - Dataiterator di; - dataiterator_init(&di, pool, repo, 0, SOLVABLE_CHECKSUM, 0, 0); - while (dataiterator_step(&di)) - { - const char *str; - int index; - - if (!solv_chksum_len(di.key->type)) - continue; - str = repodata_chk2str(di.data, di.key->type, (const unsigned char *)di.kv.str); - index = stringpool_str2id(&pd.cspool, str, 1); - if (index >= pd.ncscache) - { - pd.cscache = solv_zextend(pd.cscache, pd.ncscache, index + 1 - pd.ncscache, sizeof(Id), 255); - pd.ncscache = index + 1; - } - pd.cscache[index] = di.solvid; - } - dataiterator_free(&di); + pd.cshash_filled = 1; + fill_cshash_from_repo(&pd); } parser = XML_ParserCreate(NULL); @@ -1213,8 +1375,7 @@ repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags) solv_free(pd.content); solv_free(pd.lastdirstr); join_freemem(&pd.jd); - stringpool_free(&pd.cspool); - solv_free(pd.cscache); + free_cshash(&pd); repodata_free_dircache(data); if (!(flags & REPO_NO_INTERNALIZE)) diff --git a/ext/testcase.c b/ext/testcase.c index b9fddef..536875c 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -1190,8 +1190,10 @@ testcase_write_testtags(Repo *repo, FILE *fp) const char *release; const char *tmp; unsigned int ti; + Queue q; fprintf(fp, "=Ver: 3.0\n"); + queue_init(&q); FOR_REPO_SOLVABLES(repo, p, s) { name = pool_id2str(pool, s->name); @@ -1212,6 +1214,14 @@ testcase_write_testtags(Repo *repo, FILE *fp) writedeps(repo, fp, "Sup:", SOLVABLE_SUPPLEMENTS, s, s->supplements); writedeps(repo, fp, "Sug:", SOLVABLE_SUGGESTS, s, s->suggests); writedeps(repo, fp, "Enh:", SOLVABLE_ENHANCES, s, s->enhances); + if (solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &q)) + { + int i; + fprintf(fp, "+Ipr:\n"); + for (i = 0; i < q.count; i++) + fprintf(fp, "%s\n", testcase_dep2str(pool, q.elements[i])); + fprintf(fp, "-Ipr:\n"); + } if (s->vendor) fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor)); ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0); @@ -1219,6 +1229,7 @@ testcase_write_testtags(Repo *repo, FILE *fp) fprintf(fp, "=Tim: %u\n", ti); writefilelist(repo, fp, "Fls:", s); } + queue_free(&q); return 0; } @@ -1417,6 +1428,12 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags) case 'E' << 16 | 'n' << 8 | 'h': s->enhances = adddep(repo, s->enhances, line + 6, 0); break; + case 'I' << 16 | 'p' << 8 | 'r': + { + Id id = line[6] == '/' ? pool_str2id(pool, line + 6, 1) : testcase_str2dep(pool, line + 6); + repodata_add_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, id); + break; + } default: break; } diff --git a/package/libsolv.changes b/package/libsolv.changes index f431879..9575327 100644 --- a/package/libsolv.changes +++ b/package/libsolv.changes @@ -1,4 +1,16 @@ ------------------------------------------------------------------- +Fri Apr 8 15:36:21 CEST 2016 - mls@suse.de + +- Better support of complex deps in pool_match_dep and + selection_make_matchdeps +- make SOLVER_REASON_CLEANDEPS_ERASE introspection reason work again +- make dep2str use rpm-like output if disttype is rpm +- implement filtering of Requires(pre,post) for installed packages +- simplify handling of pseudo package updates [bnc#967006] +- improve speed of rpmmd metadata parsing +- bump version to 0.6.20 + +------------------------------------------------------------------- Mon Feb 15 16:46:31 CET 2016 - mls@suse.de - parse media number from baseurl diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a2c0098..241890d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,7 +18,8 @@ SET (libsolv_SRCS solver.c solverdebug.c repo_solv.c repo_write.c evr.c pool.c queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c - chksum.c md5.c sha1.c sha2.c solvversion.c selection.c) + chksum.c md5.c sha1.c sha2.c solvversion.c selection.c + fileprovides.c diskusage.c) SET (libsolv_HEADERS bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h diff --git a/src/diskusage.c b/src/diskusage.c new file mode 100644 index 0000000..b764b98 --- /dev/null +++ b/src/diskusage.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2007-2016, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * diskusage.c + * + * calculate needed space on partitions + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> + +#include "pool.h" +#include "poolarch.h" +#include "repo.h" +#include "util.h" +#include "bitmap.h" + + +struct mptree { + Id sibling; + Id child; + const char *comp; + int compl; + Id mountpoint; +}; + +struct ducbdata { + DUChanges *mps; + struct mptree *mptree; + int addsub; + int hasdu; + + Id *dirmap; + int nmap; + Repodata *olddata; +}; + + +static int +solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) +{ + struct ducbdata *cbd = cbdata; + Id mp; + + if (data != cbd->olddata) + { + Id dn, mp, comp, *dirmap, *dirs; + int i, compl; + const char *compstr; + struct mptree *mptree; + + /* create map from dir to mptree */ + cbd->dirmap = solv_free(cbd->dirmap); + cbd->nmap = 0; + dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id)); + mptree = cbd->mptree; + mp = 0; + for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++) + { + comp = *dirs++; + if (comp <= 0) + { + mp = dirmap[-comp]; + continue; + } + if (mp < 0) + { + /* unconnected */ + dirmap[dn] = mp; + continue; + } + if (!mptree[mp].child) + { + dirmap[dn] = -mp; + continue; + } + if (data->localpool) + compstr = stringpool_id2str(&data->spool, comp); + else + compstr = pool_id2str(data->repo->pool, comp); + compl = strlen(compstr); + for (i = mptree[mp].child; i; i = mptree[i].sibling) + if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) + break; + dirmap[dn] = i ? i : -mp; + } + /* change dirmap to point to mountpoint instead of mptree */ + for (dn = 0; dn < data->dirpool.ndirs; dn++) + { + mp = dirmap[dn]; + dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint; + } + cbd->dirmap = dirmap; + cbd->nmap = data->dirpool.ndirs; + cbd->olddata = data; + } + cbd->hasdu = 1; + if (value->id < 0 || value->id >= cbd->nmap) + return 0; + mp = cbd->dirmap[value->id]; + if (mp < 0) + return 0; + if (cbd->addsub > 0) + { + cbd->mps[mp].kbytes += value->num; + cbd->mps[mp].files += value->num2; + } + else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD)) + { + cbd->mps[mp].kbytes -= value->num; + cbd->mps[mp].files -= value->num2; + } + return 0; +} + +static void +propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint) +{ + int i; + if (mptree[pos].mountpoint == -1) + mptree[pos].mountpoint = mountpoint; + else + mountpoint = mptree[pos].mountpoint; + for (i = mptree[pos].child; i; i = mptree[i].sibling) + propagate_mountpoints(mptree, i, mountpoint); +} + +#define MPTREE_BLOCK 15 + +static struct mptree * +create_mptree(DUChanges *mps, int nmps) +{ + int i, nmptree; + struct mptree *mptree; + int pos, compl; + int mp; + const char *p, *path, *compstr; + + mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK); + + /* our root node */ + mptree[0].sibling = 0; + mptree[0].child = 0; + mptree[0].comp = 0; + mptree[0].compl = 0; + mptree[0].mountpoint = -1; + nmptree = 1; + + /* create component tree */ + for (mp = 0; mp < nmps; mp++) + { + mps[mp].kbytes = 0; + mps[mp].files = 0; + pos = 0; + path = mps[mp].path; + while(*path == '/') + path++; + while (*path) + { + if ((p = strchr(path, '/')) == 0) + { + compstr = path; + compl = strlen(compstr); + path += compl; + } + else + { + compstr = path; + compl = p - path; + path = p + 1; + while(*path == '/') + path++; + } + for (i = mptree[pos].child; i; i = mptree[i].sibling) + if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) + break; + if (!i) + { + /* create new node */ + mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK); + i = nmptree++; + mptree[i].sibling = mptree[pos].child; + mptree[i].child = 0; + mptree[i].comp = compstr; + mptree[i].compl = compl; + mptree[i].mountpoint = -1; + mptree[pos].child = i; + } + pos = i; + } + mptree[pos].mountpoint = mp; + } + + propagate_mountpoints(mptree, 0, mptree[0].mountpoint); + +#if 0 + for (i = 0; i < nmptree; i++) + { + printf("#%d sibling: %d\n", i, mptree[i].sibling); + printf("#%d child: %d\n", i, mptree[i].child); + printf("#%d comp: %s\n", i, mptree[i].comp); + printf("#%d compl: %d\n", i, mptree[i].compl); + printf("#%d mountpont: %d\n", i, mptree[i].mountpoint); + } +#endif + + return mptree; +} + +void +pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps) +{ + struct mptree *mptree; + struct ducbdata cbd; + Solvable *s; + int i, sp; + Map ignoredu; + Repo *oldinstalled = pool->installed; + int haveonlyadd = 0; + + map_init(&ignoredu, 0); + mptree = create_mptree(mps, nmps); + + for (i = 0; i < nmps; i++) + if ((mps[i].flags & DUCHANGES_ONLYADD) != 0) + haveonlyadd = 1; + cbd.mps = mps; + cbd.dirmap = 0; + cbd.nmap = 0; + cbd.olddata = 0; + cbd.mptree = mptree; + cbd.addsub = 1; + for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) + { + if (!s->repo || (oldinstalled && s->repo == oldinstalled)) + continue; + if (!MAPTST(installedmap, sp)) + continue; + cbd.hasdu = 0; + repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + if (!cbd.hasdu && oldinstalled) + { + Id op, opp; + int didonlyadd = 0; + /* no du data available, ignore data of all installed solvables we obsolete */ + if (!ignoredu.size) + map_grow(&ignoredu, oldinstalled->end - oldinstalled->start); + FOR_PROVIDES(op, opp, s->name) + { + Solvable *s2 = pool->solvables + op; + if (!pool->implicitobsoleteusesprovides && s->name != s2->name) + continue; + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2)) + continue; + if (op >= oldinstalled->start && op < oldinstalled->end) + { + MAPSET(&ignoredu, op - oldinstalled->start); + if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) + { + repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + cbd.addsub = -1; + repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + cbd.addsub = 1; + didonlyadd = 1; + } + } + } + if (s->obsoletes) + { + Id obs, *obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + FOR_PROVIDES(op, opp, obs) + { + Solvable *s2 = pool->solvables + op; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) + continue; + if (op >= oldinstalled->start && op < oldinstalled->end) + { + MAPSET(&ignoredu, op - oldinstalled->start); + if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) + { + repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + cbd.addsub = -1; + repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + cbd.addsub = 1; + didonlyadd = 1; + } + } + } + } + } + } + cbd.addsub = -1; + if (oldinstalled) + { + /* assumes we allways have du data for installed solvables */ + FOR_REPO_SOLVABLES(oldinstalled, sp, s) + { + if (MAPTST(installedmap, sp)) + continue; + if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start)) + continue; + repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + } + } + map_free(&ignoredu); + solv_free(cbd.dirmap); + solv_free(mptree); +} + +int +pool_calc_installsizechange(Pool *pool, Map *installedmap) +{ + Id sp; + Solvable *s; + int change = 0; + Repo *oldinstalled = pool->installed; + + for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) + { + if (!s->repo || (oldinstalled && s->repo == oldinstalled)) + continue; + if (!MAPTST(installedmap, sp)) + continue; + change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); + } + if (oldinstalled) + { + FOR_REPO_SOLVABLES(oldinstalled, sp, s) + { + if (MAPTST(installedmap, sp)) + continue; + change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); + } + } + return change; +} + diff --git a/src/fileprovides.c b/src/fileprovides.c new file mode 100644 index 0000000..11ff4f5 --- /dev/null +++ b/src/fileprovides.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2007-2016, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * fileprovides.c + * + * Add missing file dependencies to the package provides + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> + +#include "pool.h" +#include "repo.h" +#include "util.h" +#include "bitmap.h" + +struct searchfiles { + Id *ids; + int nfiles; + Map seen; +}; + +#define SEARCHFILES_BLOCK 127 + +static void +pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf) +{ + Id dep, sid; + const char *s; + struct searchfiles *csf; + + while ((dep = *ida++) != 0) + { + csf = sf; + while (ISRELDEP(dep)) + { + Reldep *rd; + sid = pool->ss.nstrings + GETRELID(dep); + if (MAPTST(&csf->seen, sid)) + { + dep = 0; + break; + } + MAPSET(&csf->seen, sid); + rd = GETRELDEP(pool, dep); + if (rd->flags < 8) + dep = rd->name; + else if (rd->flags == REL_NAMESPACE) + { + if (rd->name == NAMESPACE_SPLITPROVIDES) + { + csf = isf; + if (!csf || MAPTST(&csf->seen, sid)) + { + dep = 0; + break; + } + MAPSET(&csf->seen, sid); + } + dep = rd->evr; + } + else if (rd->flags == REL_FILECONFLICT) + { + dep = 0; + break; + } + else + { + Id ids[2]; + ids[0] = rd->name; + ids[1] = 0; + pool_addfileprovides_dep(pool, ids, csf, isf); + dep = rd->evr; + } + } + if (!dep) + continue; + if (MAPTST(&csf->seen, dep)) + continue; + MAPSET(&csf->seen, dep); + s = pool_id2str(pool, dep); + if (*s != '/') + continue; + if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s)) + continue; /* skip non-standard locations csf == isf: installed case */ + csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); + csf->ids[csf->nfiles++] = dep; + } +} + +struct addfileprovides_cbdata { + int nfiles; + Id *ids; + char **dirs; + char **names; + + Id *dids; + + Map providedids; + + Map useddirs; +}; + +static int +addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) +{ + struct addfileprovides_cbdata *cbd = cbdata; + int i; + + if (!cbd->useddirs.size) + { + map_init(&cbd->useddirs, data->dirpool.ndirs + 1); + if (!cbd->dirs) + { + cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *)); + cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *)); + for (i = 0; i < cbd->nfiles; i++) + { + char *s = solv_strdup(pool_id2str(data->repo->pool, cbd->ids[i])); + cbd->dirs[i] = s; + s = strrchr(s, '/'); + *s = 0; + cbd->names[i] = s + 1; + } + } + for (i = 0; i < cbd->nfiles; i++) + { + Id did; + if (MAPTST(&cbd->providedids, cbd->ids[i])) + { + cbd->dids[i] = 0; + continue; + } + did = repodata_str2dir(data, cbd->dirs[i], 0); + cbd->dids[i] = did; + if (did) + MAPSET(&cbd->useddirs, did); + } + repodata_free_dircache(data); + } + if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id)) + return 0; + for (i = 0; i < cbd->nfiles; i++) + if (cbd->dids[i] == value->id && !strcmp(cbd->names[i], value->str)) + s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER); + return 0; +} + +static void +pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly) +{ + Id p; + Repodata *data; + Repo *repo; + Queue fileprovidesq; + int i, j, repoid, repodataid; + int provstart, provend; + Map donemap; + int ndone, incomplete; + + if (!pool->urepos) + return; + + cbd->nfiles = sf->nfiles; + cbd->ids = sf->ids; + cbd->dirs = 0; + cbd->names = 0; + cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); + map_init(&cbd->providedids, pool->ss.nstrings); + + repoid = 1; + repo = repoonly ? repoonly : pool->repos[repoid]; + map_init(&donemap, pool->nsolvables); + queue_init(&fileprovidesq); + provstart = provend = 0; + for (;;) + { + if (!repo || repo->disabled) + { + if (repoonly || ++repoid == pool->nrepos) + break; + repo = pool->repos[repoid]; + continue; + } + ndone = 0; + FOR_REPODATAS(repo, repodataid, data) + { + if (ndone >= repo->nsolvables) + break; + + if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) + { + map_empty(&cbd->providedids); + for (i = 0; i < fileprovidesq.count; i++) + MAPSET(&cbd->providedids, fileprovidesq.elements[i]); + provstart = data->start; + provend = data->end; + for (i = 0; i < cbd->nfiles; i++) + if (!MAPTST(&cbd->providedids, cbd->ids[i])) + break; + if (i == cbd->nfiles) + { + /* great! no need to search files */ + for (p = data->start; p < data->end; p++) + if (pool->solvables[p].repo == repo) + { + if (MAPTST(&donemap, p)) + continue; + MAPSET(&donemap, p); + ndone++; + } + continue; + } + } + + if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) + continue; + + if (data->start < provstart || data->end > provend) + { + map_empty(&cbd->providedids); + provstart = provend = 0; + } + + /* check if the data is incomplete */ + incomplete = 0; + if (data->state == REPODATA_AVAILABLE) + { + for (j = 1; j < data->nkeys; j++) + if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) + break; + if (j < data->nkeys) + { +#if 0 + for (i = 0; i < cbd->nfiles; i++) + if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) + printf("need complete filelist because of %s\n", pool_id2str(pool, cbd->ids[i])); +#endif + for (i = 0; i < cbd->nfiles; i++) + if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) + break; + if (i < cbd->nfiles) + incomplete = 1; + } + } + + /* do the search */ + map_init(&cbd->useddirs, 0); + for (p = data->start; p < data->end; p++) + if (pool->solvables[p].repo == repo) + { + if (MAPTST(&donemap, p)) + continue; + repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd); + if (!incomplete) + { + MAPSET(&donemap, p); + ndone++; + } + } + map_free(&cbd->useddirs); + } + + if (repoonly || ++repoid == pool->nrepos) + break; + repo = pool->repos[repoid]; + } + map_free(&donemap); + queue_free(&fileprovidesq); + map_free(&cbd->providedids); + if (cbd->dirs) + { + for (i = 0; i < cbd->nfiles; i++) + solv_free(cbd->dirs[i]); + cbd->dirs = solv_free(cbd->dirs); + cbd->names = solv_free(cbd->names); + } +} + +void +pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst) +{ + Solvable *s; + Repo *installed, *repo; + struct searchfiles sf, isf, *isfp; + struct addfileprovides_cbdata cbd; + int i; + unsigned int now; + + installed = pool->installed; + now = solv_timems(0); + memset(&sf, 0, sizeof(sf)); + map_init(&sf.seen, pool->ss.nstrings + pool->nrels); + memset(&isf, 0, sizeof(isf)); + map_init(&isf.seen, pool->ss.nstrings + pool->nrels); + pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2; + + if (idq) + queue_empty(idq); + if (idqinst) + queue_empty(idqinst); + isfp = installed ? &isf : 0; + for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++) + { + repo = s->repo; + if (!repo) + continue; + if (s->obsoletes) + pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp); + if (s->conflicts) + pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp); + if (s->requires) + pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp); + if (s->recommends) + pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp); + if (s->suggests) + pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp); + if (s->supplements) + pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp); + if (s->enhances) + pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp); + } + map_free(&sf.seen); + map_free(&isf.seen); + POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles); + cbd.dids = 0; + if (sf.nfiles) + { +#if 0 + for (i = 0; i < sf.nfiles; i++) + POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i])); +#endif + pool_addfileprovides_search(pool, &cbd, &sf, 0); + if (idq) + for (i = 0; i < sf.nfiles; i++) + queue_push(idq, sf.ids[i]); + if (idqinst) + for (i = 0; i < sf.nfiles; i++) + queue_push(idqinst, sf.ids[i]); + solv_free(sf.ids); + } + if (isf.nfiles) + { +#if 0 + for (i = 0; i < isf.nfiles; i++) + POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i])); +#endif + if (installed) + pool_addfileprovides_search(pool, &cbd, &isf, installed); + if (installed && idqinst) + for (i = 0; i < isf.nfiles; i++) + queue_pushunique(idqinst, isf.ids[i]); + solv_free(isf.ids); + } + solv_free(cbd.dids); + pool_freewhatprovides(pool); /* as we have added provides */ + POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now)); +} + +void +pool_addfileprovides(Pool *pool) +{ + pool_addfileprovides_queue(pool, 0, 0); +} + diff --git a/src/knownid.h b/src/knownid.h index c094bf5..64cc6fc 100644 --- a/src/knownid.h +++ b/src/knownid.h @@ -260,6 +260,8 @@ KNOWNID(PRODUCT_REGISTER_FLAVOR, "product:regflavor"), /* installed and availab KNOWNID(SOLVABLE_INSTALLSTATUS, "solvable:installstatus"), /* debian install status */ +KNOWNID(SOLVABLE_PREREQ_IGNOREINST, "solvable:prereq_ignoreinst"), /* ignore these pre-requires for installed packages */ + KNOWNID(ID_NUM_INTERNAL, 0) #ifdef KNOWNID_INITIALIZE diff --git a/src/libsolv.ver b/src/libsolv.ver index 6508288..cc79704 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -201,6 +201,7 @@ SOLV_1.0 { repodata_key2id; repodata_localize_id; repodata_lookup_bin_checksum; + repodata_lookup_bin_checksum_uninternalized; repodata_lookup_binary; repodata_lookup_dirstrarray_uninternalized; repodata_lookup_id; diff --git a/src/linkedpkg.c b/src/linkedpkg.c index 6387373..635e69b 100644 --- a/src/linkedpkg.c +++ b/src/linkedpkg.c @@ -37,7 +37,9 @@ #include "pool.h" #include "repo.h" +#include "solver.h" #include "evr.h" +#include "bitmap.h" #include "linkedpkg.h" #ifdef ENABLE_LINKED_PKGS @@ -377,5 +379,30 @@ pool_link_evrcmp(Pool *pool, Solvable *s1, Solvable *s2) return 0; } +void +extend_updatemap_to_buddies(Solver *solv) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Solvable *s; + int p, ip; + + if (!installed) + return; + if (!solv->updatemap.size || !solv->instbuddy) + return; + FOR_REPO_SOLVABLES(installed, p, s) + { + if (!MAPTST(&solv->updatemap, p - installed->start)) + continue; + if ((ip = solv->instbuddy[p - installed->start]) <= 1) + continue; + if (!has_package_link(pool, s)) /* only look at pseudo -> real relations */ + continue; + if (ip < installed->start || ip >= installed->end || pool->solvables[ip].repo != installed) + continue; /* just in case... */ + MAPSET(&solv->updatemap, ip - installed->start); + } +} #endif diff --git a/src/linkedpkg.h b/src/linkedpkg.h index 4463280..51b82a5 100644 --- a/src/linkedpkg.h +++ b/src/linkedpkg.h @@ -18,7 +18,7 @@ has_package_link(Pool *pool, Solvable *s) const char *name = pool_id2str(pool, s->name); if (name[0] == 'a' && !strncmp("application:", name, 12)) return 1; - if (name[0] == 'p' && !strncmp("pattern:", name, 7)) + if (name[0] == 'p' && !strncmp("pattern:", name, 8)) return 1; if (name[0] == 'p' && !strncmp("product:", name, 8)) return 1; @@ -35,5 +35,6 @@ extern Id find_autoproduct_name(Pool *pool, Solvable *s); /* generic */ extern void find_package_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp); extern int pool_link_evrcmp(Pool *pool, Solvable *s1, Solvable *s2); +extern void extend_updatemap_to_buddies(Solver *solv); #endif @@ -813,6 +813,45 @@ pool_match_dep(Pool *pool, Id d1, Id d2) if (d1 == d2) return 1; + + if (ISRELDEP(d1)) + { + /* we use potentially matches for complex deps */ + rd1 = GETRELDEP(pool, d1); + if (rd1->flags == REL_AND || rd1->flags == REL_OR || rd1->flags == REL_WITH || rd1->flags == REL_COND) + { + if (pool_match_dep(pool, rd1->name, d2)) + return 1; + if (rd1->flags == REL_COND && ISRELDEP(rd1->evr)) + { + rd1 = GETRELDEP(pool, rd1->evr); + if (rd1->flags != REL_ELSE) + return 0; + } + if (rd1->flags != REL_COND && pool_match_dep(pool, rd1->evr, d2)) + return 1; + return 0; + } + } + if (ISRELDEP(d2)) + { + /* we use potentially matches for complex deps */ + rd2 = GETRELDEP(pool, d2); + if (rd2->flags == REL_AND || rd2->flags == REL_OR || rd2->flags == REL_WITH || rd2->flags == REL_COND) + { + if (pool_match_dep(pool, d1, rd2->name)) + return 1; + if (rd2->flags == REL_COND && ISRELDEP(rd2->evr)) + { + rd2 = GETRELDEP(pool, rd2->evr); + if (rd2->flags != REL_ELSE) + return 0; + } + if (rd2->flags != REL_COND && pool_match_dep(pool, d1, rd2->evr)) + return 1; + return 0; + } + } if (!ISRELDEP(d1)) { if (!ISRELDEP(d2)) @@ -1412,357 +1451,6 @@ void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, pool->nscallbackdata = nscbdata; } -/*************************************************************************/ - -struct searchfiles { - Id *ids; - int nfiles; - Map seen; -}; - -#define SEARCHFILES_BLOCK 127 - -static void -pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf) -{ - Id dep, sid; - const char *s; - struct searchfiles *csf; - - while ((dep = *ida++) != 0) - { - csf = sf; - while (ISRELDEP(dep)) - { - Reldep *rd; - sid = pool->ss.nstrings + GETRELID(dep); - if (MAPTST(&csf->seen, sid)) - { - dep = 0; - break; - } - MAPSET(&csf->seen, sid); - rd = GETRELDEP(pool, dep); - if (rd->flags < 8) - dep = rd->name; - else if (rd->flags == REL_NAMESPACE) - { - if (rd->name == NAMESPACE_SPLITPROVIDES) - { - csf = isf; - if (!csf || MAPTST(&csf->seen, sid)) - { - dep = 0; - break; - } - MAPSET(&csf->seen, sid); - } - dep = rd->evr; - } - else if (rd->flags == REL_FILECONFLICT) - { - dep = 0; - break; - } - else - { - Id ids[2]; - ids[0] = rd->name; - ids[1] = 0; - pool_addfileprovides_dep(pool, ids, csf, isf); - dep = rd->evr; - } - } - if (!dep) - continue; - if (MAPTST(&csf->seen, dep)) - continue; - MAPSET(&csf->seen, dep); - s = pool_id2str(pool, dep); - if (*s != '/') - continue; - if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s)) - continue; /* skip non-standard locations csf == isf: installed case */ - csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); - csf->ids[csf->nfiles++] = dep; - } -} - -struct addfileprovides_cbdata { - int nfiles; - Id *ids; - char **dirs; - char **names; - - Id *dids; - - Map providedids; - - Map useddirs; -}; - -static int -addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) -{ - struct addfileprovides_cbdata *cbd = cbdata; - int i; - - if (!cbd->useddirs.size) - { - map_init(&cbd->useddirs, data->dirpool.ndirs + 1); - if (!cbd->dirs) - { - cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *)); - cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *)); - for (i = 0; i < cbd->nfiles; i++) - { - char *s = solv_strdup(pool_id2str(data->repo->pool, cbd->ids[i])); - cbd->dirs[i] = s; - s = strrchr(s, '/'); - *s = 0; - cbd->names[i] = s + 1; - } - } - for (i = 0; i < cbd->nfiles; i++) - { - Id did; - if (MAPTST(&cbd->providedids, cbd->ids[i])) - { - cbd->dids[i] = 0; - continue; - } - did = repodata_str2dir(data, cbd->dirs[i], 0); - cbd->dids[i] = did; - if (did) - MAPSET(&cbd->useddirs, did); - } - repodata_free_dircache(data); - } - if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id)) - return 0; - for (i = 0; i < cbd->nfiles; i++) - if (cbd->dids[i] == value->id && !strcmp(cbd->names[i], value->str)) - s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER); - return 0; -} - -static void -pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly) -{ - Id p; - Repodata *data; - Repo *repo; - Queue fileprovidesq; - int i, j, repoid, repodataid; - int provstart, provend; - Map donemap; - int ndone, incomplete; - - if (!pool->urepos) - return; - - cbd->nfiles = sf->nfiles; - cbd->ids = sf->ids; - cbd->dirs = 0; - cbd->names = 0; - cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); - map_init(&cbd->providedids, pool->ss.nstrings); - - repoid = 1; - repo = repoonly ? repoonly : pool->repos[repoid]; - map_init(&donemap, pool->nsolvables); - queue_init(&fileprovidesq); - provstart = provend = 0; - for (;;) - { - if (!repo || repo->disabled) - { - if (repoonly || ++repoid == pool->nrepos) - break; - repo = pool->repos[repoid]; - continue; - } - ndone = 0; - FOR_REPODATAS(repo, repodataid, data) - { - if (ndone >= repo->nsolvables) - break; - - if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) - { - map_empty(&cbd->providedids); - for (i = 0; i < fileprovidesq.count; i++) - MAPSET(&cbd->providedids, fileprovidesq.elements[i]); - provstart = data->start; - provend = data->end; - for (i = 0; i < cbd->nfiles; i++) - if (!MAPTST(&cbd->providedids, cbd->ids[i])) - break; - if (i == cbd->nfiles) - { - /* great! no need to search files */ - for (p = data->start; p < data->end; p++) - if (pool->solvables[p].repo == repo) - { - if (MAPTST(&donemap, p)) - continue; - MAPSET(&donemap, p); - ndone++; - } - continue; - } - } - - if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) - continue; - - if (data->start < provstart || data->end > provend) - { - map_empty(&cbd->providedids); - provstart = provend = 0; - } - - /* check if the data is incomplete */ - incomplete = 0; - if (data->state == REPODATA_AVAILABLE) - { - for (j = 1; j < data->nkeys; j++) - if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) - break; - if (j < data->nkeys) - { -#if 0 - for (i = 0; i < cbd->nfiles; i++) - if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) - printf("need complete filelist because of %s\n", pool_id2str(pool, cbd->ids[i])); -#endif - for (i = 0; i < cbd->nfiles; i++) - if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) - break; - if (i < cbd->nfiles) - incomplete = 1; - } - } - - /* do the search */ - map_init(&cbd->useddirs, 0); - for (p = data->start; p < data->end; p++) - if (pool->solvables[p].repo == repo) - { - if (MAPTST(&donemap, p)) - continue; - repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd); - if (!incomplete) - { - MAPSET(&donemap, p); - ndone++; - } - } - map_free(&cbd->useddirs); - } - - if (repoonly || ++repoid == pool->nrepos) - break; - repo = pool->repos[repoid]; - } - map_free(&donemap); - queue_free(&fileprovidesq); - map_free(&cbd->providedids); - if (cbd->dirs) - { - for (i = 0; i < cbd->nfiles; i++) - solv_free(cbd->dirs[i]); - cbd->dirs = solv_free(cbd->dirs); - cbd->names = solv_free(cbd->names); - } -} - -void -pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst) -{ - Solvable *s; - Repo *installed, *repo; - struct searchfiles sf, isf, *isfp; - struct addfileprovides_cbdata cbd; - int i; - unsigned int now; - - installed = pool->installed; - now = solv_timems(0); - memset(&sf, 0, sizeof(sf)); - map_init(&sf.seen, pool->ss.nstrings + pool->nrels); - memset(&isf, 0, sizeof(isf)); - map_init(&isf.seen, pool->ss.nstrings + pool->nrels); - pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2; - - if (idq) - queue_empty(idq); - if (idqinst) - queue_empty(idqinst); - isfp = installed ? &isf : 0; - for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++) - { - repo = s->repo; - if (!repo) - continue; - if (s->obsoletes) - pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp); - if (s->conflicts) - pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp); - if (s->requires) - pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp); - if (s->recommends) - pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp); - if (s->suggests) - pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp); - if (s->supplements) - pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp); - if (s->enhances) - pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp); - } - map_free(&sf.seen); - map_free(&isf.seen); - POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles); - cbd.dids = 0; - if (sf.nfiles) - { -#if 0 - for (i = 0; i < sf.nfiles; i++) - POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i])); -#endif - pool_addfileprovides_search(pool, &cbd, &sf, 0); - if (idq) - for (i = 0; i < sf.nfiles; i++) - queue_push(idq, sf.ids[i]); - if (idqinst) - for (i = 0; i < sf.nfiles; i++) - queue_push(idqinst, sf.ids[i]); - solv_free(sf.ids); - } - if (isf.nfiles) - { -#if 0 - for (i = 0; i < isf.nfiles; i++) - POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i])); -#endif - if (installed) - pool_addfileprovides_search(pool, &cbd, &isf, installed); - if (installed && idqinst) - for (i = 0; i < isf.nfiles; i++) - queue_pushunique(idqinst, isf.ids[i]); - solv_free(isf.ids); - } - solv_free(cbd.dids); - pool_freewhatprovides(pool); /* as we have added provides */ - POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now)); -} - -void -pool_addfileprovides(Pool *pool) -{ - pool_addfileprovides_queue(pool, 0, 0); -} - void pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata) { @@ -1784,7 +1472,6 @@ pool_clear_pos(Pool *pool) memset(&pool->pos, 0, sizeof(pool->pos)); } - void pool_set_languages(Pool *pool, const char **languages, int nlanguages) { @@ -1951,330 +1638,6 @@ pool_bin2hex(Pool *pool, const unsigned char *buf, int len) return s; } -/*******************************************************************/ - -struct mptree { - Id sibling; - Id child; - const char *comp; - int compl; - Id mountpoint; -}; - -struct ducbdata { - DUChanges *mps; - struct mptree *mptree; - int addsub; - int hasdu; - - Id *dirmap; - int nmap; - Repodata *olddata; -}; - - -static int -solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) -{ - struct ducbdata *cbd = cbdata; - Id mp; - - if (data != cbd->olddata) - { - Id dn, mp, comp, *dirmap, *dirs; - int i, compl; - const char *compstr; - struct mptree *mptree; - - /* create map from dir to mptree */ - cbd->dirmap = solv_free(cbd->dirmap); - cbd->nmap = 0; - dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id)); - mptree = cbd->mptree; - mp = 0; - for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++) - { - comp = *dirs++; - if (comp <= 0) - { - mp = dirmap[-comp]; - continue; - } - if (mp < 0) - { - /* unconnected */ - dirmap[dn] = mp; - continue; - } - if (!mptree[mp].child) - { - dirmap[dn] = -mp; - continue; - } - if (data->localpool) - compstr = stringpool_id2str(&data->spool, comp); - else - compstr = pool_id2str(data->repo->pool, comp); - compl = strlen(compstr); - for (i = mptree[mp].child; i; i = mptree[i].sibling) - if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) - break; - dirmap[dn] = i ? i : -mp; - } - /* change dirmap to point to mountpoint instead of mptree */ - for (dn = 0; dn < data->dirpool.ndirs; dn++) - { - mp = dirmap[dn]; - dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint; - } - cbd->dirmap = dirmap; - cbd->nmap = data->dirpool.ndirs; - cbd->olddata = data; - } - cbd->hasdu = 1; - if (value->id < 0 || value->id >= cbd->nmap) - return 0; - mp = cbd->dirmap[value->id]; - if (mp < 0) - return 0; - if (cbd->addsub > 0) - { - cbd->mps[mp].kbytes += value->num; - cbd->mps[mp].files += value->num2; - } - else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD)) - { - cbd->mps[mp].kbytes -= value->num; - cbd->mps[mp].files -= value->num2; - } - return 0; -} - -static void -propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint) -{ - int i; - if (mptree[pos].mountpoint == -1) - mptree[pos].mountpoint = mountpoint; - else - mountpoint = mptree[pos].mountpoint; - for (i = mptree[pos].child; i; i = mptree[i].sibling) - propagate_mountpoints(mptree, i, mountpoint); -} - -#define MPTREE_BLOCK 15 - -static struct mptree * -create_mptree(DUChanges *mps, int nmps) -{ - int i, nmptree; - struct mptree *mptree; - int pos, compl; - int mp; - const char *p, *path, *compstr; - - mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK); - - /* our root node */ - mptree[0].sibling = 0; - mptree[0].child = 0; - mptree[0].comp = 0; - mptree[0].compl = 0; - mptree[0].mountpoint = -1; - nmptree = 1; - - /* create component tree */ - for (mp = 0; mp < nmps; mp++) - { - mps[mp].kbytes = 0; - mps[mp].files = 0; - pos = 0; - path = mps[mp].path; - while(*path == '/') - path++; - while (*path) - { - if ((p = strchr(path, '/')) == 0) - { - compstr = path; - compl = strlen(compstr); - path += compl; - } - else - { - compstr = path; - compl = p - path; - path = p + 1; - while(*path == '/') - path++; - } - for (i = mptree[pos].child; i; i = mptree[i].sibling) - if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) - break; - if (!i) - { - /* create new node */ - mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK); - i = nmptree++; - mptree[i].sibling = mptree[pos].child; - mptree[i].child = 0; - mptree[i].comp = compstr; - mptree[i].compl = compl; - mptree[i].mountpoint = -1; - mptree[pos].child = i; - } - pos = i; - } - mptree[pos].mountpoint = mp; - } - - propagate_mountpoints(mptree, 0, mptree[0].mountpoint); - -#if 0 - for (i = 0; i < nmptree; i++) - { - printf("#%d sibling: %d\n", i, mptree[i].sibling); - printf("#%d child: %d\n", i, mptree[i].child); - printf("#%d comp: %s\n", i, mptree[i].comp); - printf("#%d compl: %d\n", i, mptree[i].compl); - printf("#%d mountpont: %d\n", i, mptree[i].mountpoint); - } -#endif - - return mptree; -} - -void -pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps) -{ - struct mptree *mptree; - struct ducbdata cbd; - Solvable *s; - int i, sp; - Map ignoredu; - Repo *oldinstalled = pool->installed; - int haveonlyadd = 0; - - map_init(&ignoredu, 0); - mptree = create_mptree(mps, nmps); - - for (i = 0; i < nmps; i++) - if ((mps[i].flags & DUCHANGES_ONLYADD) != 0) - haveonlyadd = 1; - cbd.mps = mps; - cbd.dirmap = 0; - cbd.nmap = 0; - cbd.olddata = 0; - cbd.mptree = mptree; - cbd.addsub = 1; - for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) - { - if (!s->repo || (oldinstalled && s->repo == oldinstalled)) - continue; - if (!MAPTST(installedmap, sp)) - continue; - cbd.hasdu = 0; - repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - if (!cbd.hasdu && oldinstalled) - { - Id op, opp; - int didonlyadd = 0; - /* no du data available, ignore data of all installed solvables we obsolete */ - if (!ignoredu.size) - map_grow(&ignoredu, oldinstalled->end - oldinstalled->start); - FOR_PROVIDES(op, opp, s->name) - { - Solvable *s2 = pool->solvables + op; - if (!pool->implicitobsoleteusesprovides && s->name != s2->name) - continue; - if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2)) - continue; - if (op >= oldinstalled->start && op < oldinstalled->end) - { - MAPSET(&ignoredu, op - oldinstalled->start); - if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) - { - repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - cbd.addsub = -1; - repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - cbd.addsub = 1; - didonlyadd = 1; - } - } - } - if (s->obsoletes) - { - Id obs, *obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - FOR_PROVIDES(op, opp, obs) - { - Solvable *s2 = pool->solvables + op; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) - continue; - if (op >= oldinstalled->start && op < oldinstalled->end) - { - MAPSET(&ignoredu, op - oldinstalled->start); - if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) - { - repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - cbd.addsub = -1; - repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - cbd.addsub = 1; - didonlyadd = 1; - } - } - } - } - } - } - cbd.addsub = -1; - if (oldinstalled) - { - /* assumes we allways have du data for installed solvables */ - FOR_REPO_SOLVABLES(oldinstalled, sp, s) - { - if (MAPTST(installedmap, sp)) - continue; - if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start)) - continue; - repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - } - } - map_free(&ignoredu); - solv_free(cbd.dirmap); - solv_free(mptree); -} - -int -pool_calc_installsizechange(Pool *pool, Map *installedmap) -{ - Id sp; - Solvable *s; - int change = 0; - Repo *oldinstalled = pool->installed; - - for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) - { - if (!s->repo || (oldinstalled && s->repo == oldinstalled)) - continue; - if (!MAPTST(installedmap, sp)) - continue; - change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); - } - if (oldinstalled) - { - FOR_REPO_SOLVABLES(oldinstalled, sp, s) - { - if (MAPTST(installedmap, sp)) - continue; - change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); - } - } - return change; -} - /* map: * 1: installed * 2: conflicts with installed @@ -34,9 +34,6 @@ extern "C" { #define SYSTEMSOLVABLE 1 -/* how many strings to maintain (round robin) */ -#define POOL_TMPSPACEBUF 16 - /*----------------------------------------------- */ struct _Repo; @@ -52,12 +49,20 @@ typedef struct _Datapos { Id dp; } Datapos; + +#ifdef LIBSOLV_INTERNAL + +/* how many strings to maintain (round robin) */ +#define POOL_TMPSPACEBUF 16 + struct _Pool_tmpspace { char *buf[POOL_TMPSPACEBUF]; int len[POOL_TMPSPACEBUF]; int n; }; +#endif + struct _Pool { void *appdata; /* application private pointer */ diff --git a/src/poolid.c b/src/poolid.c index 2138c42..91eba34 100644 --- a/src/poolid.c +++ b/src/poolid.c @@ -173,11 +173,11 @@ pool_id2rel(const Pool *pool, Id id) return pool->disttype == DISTTYPE_HAIKU ? " != " : rels[rd->flags]; #endif case REL_AND: - return " & "; + return pool->disttype == DISTTYPE_RPM ? " and " : " & "; case REL_OR: - return " | "; + return pool->disttype == DISTTYPE_RPM ? " or " : " | "; case REL_WITH: - return " + "; + return pool->disttype == DISTTYPE_RPM ? " with " : " + "; case REL_NAMESPACE: return " NAMESPACE "; /* actually not used in dep2str */ case REL_ARCH: @@ -187,13 +187,13 @@ pool_id2rel(const Pool *pool, Id id) case REL_FILECONFLICT: return " FILECONFLICT "; case REL_COND: - return " IF "; + return pool->disttype == DISTTYPE_RPM ? " if " : " IF "; case REL_COMPAT: return " compat >= "; case REL_KIND: return " KIND "; case REL_ELSE: - return " ELSE "; + return pool->disttype == DISTTYPE_RPM ? " else " : " ELSE "; default: break; } @@ -235,9 +235,10 @@ dep2strcpy(const Pool *pool, char *p, Id id, int oldrel) while (ISRELDEP(id)) { Reldep *rd = GETRELDEP(pool, id); - if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH) - if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH) - if (oldrel != rd->flags) + int rel = rd->flags; + if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH || oldrel == REL_COND || oldrel == REL_ELSE || oldrel == -1) + if (rel == REL_AND || rel == REL_OR || rel == REL_WITH || rel == REL_COND || rel == REL_ELSE) + if ((oldrel != rel || rel == REL_COND || rel == REL_ELSE) && !(oldrel == REL_COND && rel == REL_ELSE)) { *p++ = '('; dep2strcpy(pool, p, rd->name, rd->flags); @@ -286,7 +287,7 @@ pool_dep2str(Pool *pool, Id id) if (!ISRELDEP(id)) return pool->ss.stringspace + pool->ss.strings[id]; p = pool_alloctmpspace(pool, dep2strlen(pool, id) + 1); - dep2strcpy(pool, p, id, 0); + dep2strcpy(pool, p, id, pool->disttype == DISTTYPE_RPM ? -1 : 0); return p; } diff --git a/src/repodata.c b/src/repodata.c index ad3e71a..b611afc 100644 --- a/src/repodata.c +++ b/src/repodata.c @@ -881,6 +881,31 @@ repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname return 0; } +const unsigned char * +repodata_lookup_bin_checksum_uninternalized(Repodata *data, Id solvid, Id keyname, Id *typep) +{ + Id *ap; + if (!data->attrs) + return 0; + ap = data->attrs[solvid - data->start]; + if (!ap) + return 0; + for (; *ap; ap += 2) + { + if (data->keys[*ap].name != keyname) + continue; + switch (data->keys[*ap].type) + { + case_CHKSUM_TYPES: + *typep = data->keys[*ap].type; + return (const unsigned char *)data->attrdata + ap[1]; + default: + break; + } + } + return 0; +} + /************************************************************************ * data search */ diff --git a/src/repodata.h b/src/repodata.h index c18c688..d72c60f 100644 --- a/src/repodata.h +++ b/src/repodata.h @@ -300,8 +300,11 @@ const char *repodata_chk2str(Repodata *data, Id type, const unsigned char *buf); void repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file); void repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file); void repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg); + +/* uninternalized data lookup */ Id repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid); const char *repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname, Id *didp, Id *iterp); +const unsigned char *repodata_lookup_bin_checksum_uninternalized(Repodata *data, Id solvid, Id keyname, Id *typep); /* stats */ unsigned int repodata_memused(Repodata *data); diff --git a/src/rules.c b/src/rules.c index 4cd53d3..32855e4 100644 --- a/src/rules.c +++ b/src/rules.c @@ -671,7 +671,7 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w /*------------------------------------------------------------------- * - * add (install) rules for solvable + * add dependency rules for solvable * * s: Solvable for which to add rules * m: m[s] = 1 for solvables which have rules, prevent rule duplication @@ -697,6 +697,8 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) Queue workq; /* list of solvables we still have to work on */ Id workqbuf[64]; + Queue prereqq; /* list of pre-req ids to ignore */ + Id prereqbuf[16]; int i; int dontfix; /* ignore dependency errors for installed solvables */ @@ -712,6 +714,8 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf)); queue_push(&workq, s - pool->solvables); /* push solvable Id to work queue */ + queue_init_buffer(&prereqq, prereqbuf, sizeof(prereqbuf)/sizeof(*prereqbuf)); + /* loop until there's no more work left */ while (workq.count) { @@ -762,11 +766,33 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) if (s->requires) { + int filterpre = 0; reqp = s->repo->idarraydata + s->requires; while ((req = *reqp++) != 0) /* go through all requires */ { if (req == SOLVABLE_PREREQMARKER) /* skip the marker */ - continue; + { + if (installed && s->repo == installed) + { + if (prereqq.count) + queue_empty(&prereqq); + solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &prereqq); + filterpre = prereqq.count; + } + continue; + } + if (filterpre) + { + /* check if this id is filtered. assumes that prereqq.count is small */ + for (i = 0; i < prereqq.count; i++) + if (req == prereqq.elements[i]) + break; + if (i < prereqq.count) + { + POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s: ignoring filtered pre-req dependency %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req)); + continue; + } + } #ifdef ENABLE_COMPLEX_DEPS if (pool_is_complex_dep(pool, req)) @@ -1034,6 +1060,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) } } } + queue_free(&prereqq); queue_free(&workq); } @@ -1170,35 +1197,56 @@ solver_addpkgrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all) *** ***/ +static int +dup_maykeepinstalled(Solver *solv, Solvable *s) +{ + Pool *pool = solv->pool; + Id ip, pp; + + if (solv->dupmap.size && MAPTST(&solv->dupmap, s - pool->solvables)) + return 1; + /* is installed identical to a good one? */ + FOR_PROVIDES(ip, pp, s->name) + { + Solvable *is = pool->solvables + ip; + if (is->evr != s->evr) + continue; + if (solv->dupmap.size) + { + if (!MAPTST(&solv->dupmap, ip)) + continue; + } + else if (is->repo == pool->installed) + continue; + if (solvable_identical(s, is)) + return 1; + } + return 0; +} + + static Id -finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) +finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs) { Pool *pool = solv->pool; - int i; + int i, j; - policy_findupdatepackages(solv, s, qs, allow_all ? allow_all : 2); - if (!qs->count) + policy_findupdatepackages(solv, s, qs, 2); + if (qs->count) { - if (allow_all) - return 0; /* orphaned, don't create feature rule */ - /* check if this is an orphaned package */ - policy_findupdatepackages(solv, s, qs, 1); - if (!qs->count) - return 0; /* orphaned, don't create update rule */ - qs->count = 0; - return -SYSTEMSOLVABLE; /* supported but not installable */ + /* remove installed packages we can't keep */ + for (i = j = 0; i < qs->count; i++) + { + Solvable *ns = pool->solvables + qs->elements[i]; + if (ns->repo == pool->installed && !dup_maykeepinstalled(solv, ns)) + continue; + qs->elements[j++] = qs->elements[i]; + } + queue_truncate(qs, j); } - if (allow_all) - return s - pool->solvables; /* check if it is ok to keep the installed package */ - if (solv->dupmap.size && MAPTST(&solv->dupmap, s - pool->solvables)) + if (dup_maykeepinstalled(solv, s)) return s - pool->solvables; - for (i = 0; i < qs->count; i++) - { - Solvable *ns = pool->solvables + qs->elements[i]; - if (s->evr == ns->evr && solvable_identical(s, ns)) - return s - pool->solvables; - } /* nope, it must be some other package */ return -SYSTEMSOLVABLE; } @@ -1240,6 +1288,73 @@ set_specialupdaters(Solver *solv, Solvable *s, Id d) solv->specialupdaters[s - solv->pool->solvables - installed->start] = d; } +#ifdef ENABLE_LINKED_PKGS +/* Check if this is a linked pseudo package. As it is linked, we do not need an update/feature rule */ +static inline int +is_linked_pseudo_package(Solver *solv, Solvable *s) +{ + Pool *pool = solv->pool; + if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start]) + { + const char *name = pool_id2str(pool, s->name); + if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0) + return 1; + } + return 0; +} +#endif + +void +solver_addfeaturerule(Solver *solv, Solvable *s) +{ + Pool *pool = solv->pool; + int i; + Id p; + Queue qs; + Id qsbuf[64]; + +#ifdef ENABLE_LINKED_PKGS + if (is_linked_pseudo_package(solv, s)) + { + solver_addrule(solv, 0, 0, 0); /* no feature rules for those */ + return; + } +#endif + queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); + p = s - pool->solvables; + policy_findupdatepackages(solv, s, &qs, 1); + if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) + { + if (!dup_maykeepinstalled(solv, s)) + { + for (i = 0; i < qs.count; i++) + { + Solvable *ns = pool->solvables + qs.elements[i]; + if (ns->repo != pool->installed || dup_maykeepinstalled(solv, ns)) + break; + } + if (i == qs.count) + { + solver_addrule(solv, 0, 0, 0); /* this is an orphan */ + queue_free(&qs); + return; + } + } + } + if (qs.count > 1) + { + Id d = pool_queuetowhatprovides(pool, &qs); + queue_free(&qs); + solver_addrule(solv, p, 0, d); /* allow update of s */ + } + else + { + Id d = qs.count ? qs.elements[0] : 0; + queue_free(&qs); + solver_addrule(solv, p, d, 0); /* allow update of s */ + } +} + /*------------------------------------------------------------------- * * add rule for update @@ -1249,7 +1364,7 @@ set_specialupdaters(Solver *solv, Solvable *s, Id d) */ void -solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) +solver_addupdaterule(Solver *solv, Solvable *s) { /* installed packages get a special upgrade allowed rule */ Pool *pool = solv->pool; @@ -1257,48 +1372,37 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) Queue qs; Id qsbuf[64]; int isorphaned = 0; + Rule *r; - queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); p = s - pool->solvables; - /* find update candidates for 's' */ - if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) - p = finddistupgradepackages(solv, s, &qs, allow_all); - else - policy_findupdatepackages(solv, s, &qs, allow_all); - -#ifdef ENABLE_LINKED_PKGS - if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start]) + /* Orphan detection. We cheat by looking at the feature rule, which + * we already calculated */ + r = solv->rules + solv->featurerules + (p - solv->installed->start); + if (!r->p) { - const char *name = pool_id2str(pool, s->name); - if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0) +#ifdef ENABLE_LINKED_PKGS + if (is_linked_pseudo_package(solv, s)) { - /* a linked pseudo package. As it is linked, we do not need an update/feature rule */ - /* nevertheless we set specialupdaters so we can update */ solver_addrule(solv, 0, 0, 0); - if (!allow_all && qs.count) - { - if (p != -SYSTEMSOLVABLE) - queue_unshift(&qs, p); - if (qs.count) - set_specialupdaters(solv, s, pool_queuetowhatprovides(pool, &qs)); - } - queue_free(&qs); return; } - } #endif - - if (!allow_all && !p) /* !p implies qs.count == 0 */ - { + p = 0; queue_push(&solv->orphaned, s - pool->solvables); /* an orphaned package */ if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start)))) p = s - pool->solvables; /* keep this orphaned package installed */ - queue_free(&qs); solver_addrule(solv, p, 0, 0); return; } - if (!allow_all && qs.count && solv->multiversion.size) + queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); + /* find update candidates for 's' */ + if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) + p = finddistupgradepackages(solv, s, &qs); + else + policy_findupdatepackages(solv, s, &qs, 0); + + if (qs.count && solv->multiversion.size) { int i, j; diff --git a/src/rules.h b/src/rules.h index 606819b..29325ea 100644 --- a/src/rules.h +++ b/src/rules.h @@ -111,7 +111,8 @@ extern void solver_addpkgrulesforlinked(struct _Solver *solv, Map *m); extern void solver_addpkgrulesforupdaters(struct _Solver *solv, Solvable *s, Map *m, int allow_all); /* update/feature rules */ -extern void solver_addupdaterule(struct _Solver *solv, Solvable *s, int allow_all); +extern void solver_addfeaturerule(struct _Solver *solv, Solvable *s); +extern void solver_addupdaterule(struct _Solver *solv, Solvable *s); /* infarch rules */ extern void solver_addinfarchrules(struct _Solver *solv, Map *addedmap); diff --git a/src/selection.c b/src/selection.c index 8856436..7d9a918 100644 --- a/src/selection.c +++ b/src/selection.c @@ -873,11 +873,17 @@ matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags) if (ISRELDEP(id)) { Reldep *rd = GETRELDEP(pool, id); - if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH) + if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH || rd->flags == REL_COND) { if (matchdep(pool, rd->name, rname, rflags, revr, flags)) return 1; - if (matchdep(pool, rd->evr, rname, rflags, revr, flags)) + if (rd->flags == REL_COND && ISRELDEP(rd->evr)) + { + rd = GETRELDEP(pool, rd->evr); + if (rd->flags != REL_ELSE) + return 0; + } + if (rd->flags != REL_COND && matchdep(pool, rd->evr, rname, rflags, revr, flags)) return 1; return 0; } diff --git a/src/solver.c b/src/solver.c index 261f367..d5989cc 100644 --- a/src/solver.c +++ b/src/solver.c @@ -2193,8 +2193,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) rr -= solv->installed->end - solv->installed->start; if (!rr->p) /* identical to update rule? */ rr = r; - if (!rr->p && !(specialupdaters && specialupdaters[i - installed->start])) - continue; /* orpaned package */ + if (!rr->p) + continue; /* orpaned package or pseudo package */ /* check if we should update this package to the latest version * noupdate is set for erase jobs, in that case we want to deinstall @@ -2203,21 +2203,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) queue_empty(&dq); if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i))) { - if (!rr->p) - { - /* specialupdater with no update/feature rule */ - for (d = specialupdaters[i - installed->start]; (p = pool->whatprovidesdata[d++]) != 0; ) - { - if (solv->decisionmap[p] > 0) - { - dq.count = 0; - break; - } - if (!solv->decisionmap[p]) - queue_push(&dq, p); - } - } - else if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0) + if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0) { /* special multiversion handling, make sure best version is chosen */ if (rr->p == i && solv->decisionmap[i] >= 0) @@ -3716,7 +3702,7 @@ solver_solve(Solver *solv, Queue *job) solver_addrule(solv, 0, 0, 0); /* create dummy rule */ continue; } - solver_addupdaterule(solv, s, 1); /* allow s to be updated */ + solver_addfeaturerule(solv, s); } /* make sure we accounted for all rules */ assert(solv->nrules - solv->featurerules == installed->end - installed->start); @@ -3744,7 +3730,7 @@ solver_solve(Solver *solv, Queue *job) solver_addrule(solv, 0, 0, 0); /* create dummy rule */ continue; } - solver_addupdaterule(solv, s, 0); /* allowall = 0: downgrades not allowed */ + solver_addupdaterule(solv, s); /* * check for and remove duplicate */ @@ -3759,9 +3745,10 @@ solver_solve(Solver *solv, Queue *job) /* it's also orphaned if the feature rule consists just of the installed package */ if (!solv->dupmap_all && sr->p == i && !sr->d && !sr->w2) queue_push(&solv->orphaned, i); + if (!solver_rulecmp(solv, r, sr)) memset(sr, 0, sizeof(*sr)); /* delete unneeded feature rule */ - else + else if (sr->p) solver_disablerule(solv, sr); /* disable feature rule for now */ } /* consistency check: we added a rule for _every_ installed solvable */ @@ -3990,6 +3977,11 @@ solver_solve(Solver *solv, Queue *job) else solv->duprules = solv->duprules_end = solv->nrules; +#ifdef ENABLE_LINKED_PKGS + if (solv->instbuddy && solv->updatemap.size) + extend_updatemap_to_buddies(solv); +#endif + if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob) solver_addbestrules(solv, hasbestinstalljob); else @@ -4485,6 +4477,11 @@ solver_describe_decision(Solver *solv, Id p, Id *infop) return SOLVER_REASON_CLEANDEPS_ERASE; return SOLVER_REASON_KEEP_INSTALLED; } + if (i < solv->decisioncnt_weak) + { + if (why == 0 && pp < 0) + return SOLVER_REASON_CLEANDEPS_ERASE; + } if (why > 0) return SOLVER_REASON_RESOLVE; /* weak or orphaned */ @@ -235,7 +235,7 @@ solv_hex2bin(const char **strp, unsigned char *buf, int bufl) d = c - ('A' - 10); else break; - c = *++str; + c = str[1]; d <<= 4; if (c >= '0' && c <= '9') d |= c - '0'; @@ -246,7 +246,7 @@ solv_hex2bin(const char **strp, unsigned char *buf, int bufl) else break; buf[i] = d; - ++str; + str += 2; } *strp = str; return i; |