From 813ed1da5594e3fcde37f9f23120f70791e7a596 Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Wed, 4 Sep 2013 18:54:57 +0200 Subject: add pool_whatmatchesdep and selection_make_deps to query for packages intersecting a dependency --- examples/solv.c | 21 ++++++-- src/libsolv.ver | 2 + src/pool.c | 19 +++++++ src/pool.h | 2 + src/selection.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++--------- src/selection.h | 2 + src/solvable.c | 17 ++++++ src/solvable.h | 1 + 8 files changed, 194 insertions(+), 28 deletions(-) diff --git a/examples/solv.c b/examples/solv.c index 7d6de97..d4a6b6c 100644 --- a/examples/solv.c +++ b/examples/solv.c @@ -2598,6 +2598,7 @@ main(int argc, char **argv) int cleandeps = 0; int forcebest = 0; char *rootdir = 0; + char *keyname = 0; argc--; argv++; @@ -2669,7 +2670,6 @@ main(int argc, char **argv) argc -= 2; argv += 2; } - else if (argc > 1 && !strcmp(argv[1], "--clean")) { cleandeps = 1; @@ -2682,6 +2682,12 @@ main(int argc, char **argv) argc--; argv++; } + if (argc > 2 && !strcmp(argv[1], "--keyname")) + { + keyname = argv[2]; + argc -= 2; + argv += 2; + } else break; } @@ -2851,6 +2857,8 @@ main(int argc, char **argv) #endif pool_createwhatprovides(pool); + if (keyname) + keyname = solv_dupjoin("solvable:", keyname, 0); queue_init(&job); for (i = 1; i < argc; i++) { @@ -2869,13 +2877,19 @@ main(int argc, char **argv) flags |= SELECTION_WITH_SOURCE; if (argv[i][0] == '/') flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0); - rflags = selection_make(pool, &job2, argv[i], flags); + if (!keyname) + rflags = selection_make(pool, &job2, argv[i], flags); + else + rflags = selection_make_deps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1)); if (repofilter.count) selection_filter(pool, &job2, &repofilter); if (!job2.count) { flags |= SELECTION_NOCASE; - rflags = selection_make(pool, &job2, argv[i], flags); + if (!keyname) + rflags = selection_make(pool, &job2, argv[i], flags); + else + rflags = selection_make_deps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1)); if (repofilter.count) selection_filter(pool, &job2, &repofilter); if (job2.count) @@ -2894,6 +2908,7 @@ main(int argc, char **argv) queue_push(&job, job2.elements[j]); queue_free(&job2); } + keyname = solv_free(keyname); if (!job.count && (mainmode == MODE_UPDATE || mainmode == MODE_DISTUPGRADE || mainmode == MODE_VERIFY || repofilter.count)) { diff --git a/src/libsolv.ver b/src/libsolv.ver index 0fd6993..86ca660 100644 --- a/src/libsolv.ver +++ b/src/libsolv.ver @@ -116,6 +116,7 @@ SOLV_1.0 { pool_trivial_installable; pool_trivial_installable_multiversionmap; pool_vendor2mask; + pool_whatmatchesdep; queue_alloc_one; queue_alloc_one_head; queue_delete; @@ -239,6 +240,7 @@ SOLV_1.0 { selection_add; selection_filter; selection_make; + selection_make_deps; selection_solvables; solv_bin2hex; solv_calloc; diff --git a/src/pool.c b/src/pool.c index d5a86ec..437e53d 100644 --- a/src/pool.c +++ b/src/pool.c @@ -1065,6 +1065,25 @@ pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr) } } +/* intersect dependencies in keyname with dep, return list of matching packages */ +void +pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q) +{ + Id p; + + queue_empty(q); + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + if (s->repo->disabled) + continue; + if (s->repo != pool->installed && !pool_installable(pool, s)) + continue; + if (solvable_matchesdep(s, keyname, dep)) + queue_push(q, p); + } +} + /*************************************************************************/ void diff --git a/src/pool.h b/src/pool.h index 5527bfa..c0fdc3a 100644 --- a/src/pool.h +++ b/src/pool.h @@ -329,6 +329,8 @@ static inline Id *pool_whatprovides_ptr(Pool *pool, Id d) return pool->whatprovidesdata + off; } +void pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q); + /* search the pool. the following filters are available: * p - search just this solvable * key - search only this key diff --git a/src/selection.c b/src/selection.c index b4dcadf..2e6e82d 100644 --- a/src/selection.c +++ b/src/selection.c @@ -573,6 +573,39 @@ selection_filelist(Pool *pool, Queue *selection, const char *name, int flags) return SELECTION_FILELIST; } +static char * +splitrel(char *rname, char *r, int *rflagsp) +{ + int nend = r - rname; + int rflags = 0; + if (nend && *r == '=' && r[-1] == '!') + { + nend--; + r++; + rflags = REL_LT|REL_GT; + } + for (; *r; r++) + { + if (*r == '<') + rflags |= REL_LT; + else if (*r == '=') + rflags |= REL_EQ; + else if (*r == '>') + rflags |= REL_GT; + else + break; + } + while (*r && (*r == ' ' || *r == '\t')) + r++; + while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t')) + nend--; + if (!*rname || !*r) + return 0; + *rflagsp = rflags; + rname[nend] = 0; + return r; +} + static int selection_rel(Pool *pool, Queue *selection, const char *name, int flags) { @@ -586,34 +619,11 @@ selection_rel(Pool *pool, Queue *selection, const char *name, int flags) rname = solv_strdup(name); if ((r = strpbrk(rname, "<=>")) != 0) { - int nend = r - rname; - if (nend && *r == '=' && r[-1] == '!') + if ((r = splitrel(rname, r, &rflags)) == 0) { - nend--; - r++; - rflags = REL_LT|REL_GT; - } - for (; *r; r++) - { - if (*r == '<') - rflags |= REL_LT; - else if (*r == '=') - rflags |= REL_EQ; - else if (*r == '>') - rflags |= REL_GT; - else - break; - } - while (*r && (*r == ' ' || *r == '\t')) - r++; - while (nend && (rname[nend - 1] == ' ' || rname[nend -1 ] == '\t')) - nend--; - if (!*rname || !*r) - { solv_free(rname); return 0; - } - rname[nend] = 0; + } } if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0) { @@ -839,6 +849,104 @@ selection_make(Pool *pool, Queue *selection, const char *name, int flags) return ret; } +static int +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 (matchdep(pool, rd->name, rname, rflags, revr, flags)) + return 1; + if (matchdep(pool, rd->evr, rname, rflags, revr, flags)) + return 1; + return 0; + } + if (rd->flags == REL_ARCH) + return matchdep(pool, rd->name, rname, rflags, revr, flags); + if (!matchdep(pool, rd->name, rname, rflags, revr, flags)) + return 0; + if (rflags) + { + /* XXX: need pool_match_flags_evr here */ + if (!pool_match_dep(pool, pool_rel2id(pool, rd->name, pool_str2id(pool, revr, 1), rflags, 1), id)) + return 0; + } + return 1; + } + if (flags & SELECTION_GLOB) + { + int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0; + return fnmatch(rname, pool_id2str(pool, id), globflags) == 0 ? 1 : 0; + } + if (flags & SELECTION_NOCASE) + return strcasecmp(rname, pool_id2str(pool, id)) == 0 ? 1 : 0; + return strcmp(rname, pool_id2str(pool, id)) == 0 ? 1 : 0; +} + +/* + * select against the dependencies in keyname + * like SELECTION_REL and SELECTION_PROVIDES, but with the + * deps in keyname instead of provides. + */ +int +selection_make_deps(Pool *pool, Queue *selection, const char *name, int flags, int keyname) +{ + char *rname, *r; + int rflags = 0; + Id p; + Queue q; + + queue_empty(selection); + rname = solv_strdup(name); + if ((r = strpbrk(rname, "<=>")) != 0) + { + if ((r = splitrel(rname, r, &rflags)) == 0) + { + solv_free(rname); + return 0; + } + } + if ((flags & SELECTION_GLOB) != 0 && !strpbrk(name, "[*?") != 0) + flags &= ~SELECTION_GLOB; + + queue_init(&q); + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + int i; + + if (s->repo != pool->installed && !pool_installable(pool, s)) + { + if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)) + continue; + if (pool_disabled_solvable(pool, s)) + continue; + } + if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) + continue; + if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE)) + continue; + queue_empty(&q); + repo_lookup_idarray(s->repo, p, keyname, &q); + for (i = 0; i < q.count; i++) + { + Id id = q.elements[i]; + if (matchdep(pool, id, rname, rflags, r, flags)) + break; + } + if (i < q.count) + queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p); + } + queue_free(&q); + if (!selection->count) + return 0; + if ((flags & SELECTION_FLAT) != 0) + selection_flatten(pool, selection); + return SELECTION_PROVIDES; +} + void selection_filter(Pool *pool, Queue *sel1, Queue *sel2) { diff --git a/src/selection.h b/src/selection.h index 705768b..e1da169 100644 --- a/src/selection.h +++ b/src/selection.h @@ -34,6 +34,8 @@ extern "C" { #define SELECTION_WITH_SOURCE (1 << 13) extern int selection_make(Pool *pool, Queue *selection, const char *name, int flags); +extern int selection_make_deps(Pool *pool, Queue *selection, const char *name, int flags, int keyname); + extern void selection_filter(Pool *pool, Queue *sel1, Queue *sel2); extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2); extern void selection_solvables(Pool *pool, Queue *selection, Queue *pkgs); diff --git a/src/solvable.c b/src/solvable.c index 1633b73..b822784 100644 --- a/src/solvable.c +++ b/src/solvable.c @@ -856,3 +856,20 @@ solvable_unset(Solvable *s, Id keyname) { repo_unset(s->repo, s - s->repo->pool->solvables, keyname); } + +/* return true if a dependency intersects dep in the keyname array */ +int +solvable_matchesdep(Solvable *s, Id keyname, Id dep) +{ + int i; + Pool *pool = s->repo->pool; + Queue q; + queue_init(&q); + solvable_lookup_idarray(s, keyname, &q); + for (i = 0; i < q.count; i++) + if (pool_match_dep(pool, q.elements[i], dep)) + break; + i = i == q.count ? 0 : 1; + queue_free(&q); + return i; +} diff --git a/src/solvable.h b/src/solvable.h index ad06533..356e7d6 100644 --- a/src/solvable.h +++ b/src/solvable.h @@ -78,6 +78,7 @@ void solvable_unset(Solvable *s, Id keyname); int solvable_identical(Solvable *s1, Solvable *s2); Id solvable_selfprovidedep(Solvable *s); +int solvable_matchesdep(Solvable *s, Id keyname, Id dep); #ifdef __cplusplus } -- cgit v1.2.3