2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
21 #include "selection.h"
27 str2archid(Pool *pool, const char *arch)
32 id = pool_str2id(pool, arch, 0);
33 if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
35 if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
41 selection_prune(Pool *pool, Queue *selection)
45 for (i = j = 0; i < selection->count; i += 2)
47 Id select = selection->elements[i] & SOLVER_SELECTMASK;
49 if (select == SOLVER_SOLVABLE_ALL)
51 else if (select == SOLVER_SOLVABLE_REPO)
54 Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
56 FOR_REPO_SOLVABLES(repo, p, s)
61 FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
66 selection->elements[j] = selection->elements[i];
67 selection->elements[j + 1] = selection->elements[i + 1];
70 queue_truncate(selection, j);
75 selection_solvables_sortcmp(const void *ap, const void *bp, void *dp)
77 return *(const Id *)ap - *(const Id *)bp;
81 selection_solvables(Pool *pool, Queue *selection, Queue *pkgs)
86 for (i = 0; i < selection->count; i += 2)
88 Id select = selection->elements[i] & SOLVER_SELECTMASK;
89 if (select == SOLVER_SOLVABLE_ALL)
94 if (select == SOLVER_SOLVABLE_REPO)
97 Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
99 FOR_REPO_SOLVABLES(repo, p, s)
104 FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
111 solv_sort(pkgs->elements, pkgs->count, sizeof(Id), selection_solvables_sortcmp, NULL);
112 lastid = pkgs->elements[0];
113 for (i = j = 1; i < pkgs->count; i++)
114 if (pkgs->elements[i] != lastid)
115 pkgs->elements[j++] = lastid = pkgs->elements[i];
116 queue_truncate(pkgs, j);
120 selection_flatten(Pool *pool, Queue *selection)
124 if (selection->count <= 1)
126 for (i = 0; i < selection->count; i += 2)
127 if ((selection->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
129 selection->elements[0] = selection->elements[i];
130 selection->elements[1] = selection->elements[i + 1];
131 queue_truncate(selection, 2);
135 selection_solvables(pool, selection, &q);
138 queue_empty(selection);
141 queue_truncate(selection, 2);
144 selection->elements[0] = SOLVER_SOLVABLE_ONE_OF;
145 selection->elements[1] = pool_queuetowhatprovides(pool, &q);
149 selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
150 selection->elements[1] = q.elements[0];
155 selection_limit_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
158 for (i = 0; i < selection->count; i += 2)
160 Id select = selection->elements[i] & SOLVER_SELECTMASK;
161 Id id = selection->elements[i + 1];
162 if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF)
164 /* done by selection_addsrc */
167 Id rel = 0, relname = 0;
171 FOR_JOB_SELECT(p, pp, select, id)
173 Solvable *s = pool->solvables + p;
174 if (!rel || s->name != relname)
177 rel = pool_rel2id(pool, relname, relevr, relflags, 1);
179 if (pool_match_nevr(pool, s, rel))
188 selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
189 selection->elements[i + 1] = q.elements[0];
193 selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
194 selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
200 if (select != SOLVER_SOLVABLE_NAME && select != SOLVER_SOLVABLE_PROVIDES)
201 continue; /* actually internal error */
202 if (relflags == REL_ARCH && (relevr == ARCH_SRC || relevr == ARCH_NOSRC) && ISRELDEP(id))
204 Reldep *rd = GETRELDEP(pool, id);
205 if (rd->flags == REL_ARCH && rd->evr == ARCH_SRC)
208 selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1);
209 if (relflags == REL_ARCH)
210 selection->elements[i] |= SOLVER_SETARCH;
211 if (relflags == REL_EQ && select == SOLVER_SOLVABLE_NAME && selection->elements[i])
213 if (pool->disttype == DISTTYPE_DEB)
214 selection->elements[i] |= SOLVER_SETEVR; /* debian can't match version only like rpm */
216 selection->elements[i] |= strchr(pool_id2str(pool, relevr), '-') != 0 ? SOLVER_SETEVR : SOLVER_SETEV;
219 selection_prune(pool, selection);
223 selection_addsrc(Pool *pool, Queue *selection, int flags)
229 if ((flags & SELECTION_INSTALLED_ONLY) != 0)
230 return; /* sources can't be installed */
232 for (i = 0; i < selection->count; i += 2)
234 if (selection->elements[i] != SOLVER_SOLVABLE_NAME)
236 name = selection->elements[i + 1];
239 FOR_POOL_SOLVABLES(p)
241 Solvable *s = pool->solvables + p;
244 if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
246 else if (!pool_installable(pool, s))
250 if (!havesrc || !q.count)
254 selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
255 selection->elements[i + 1] = q.elements[0];
259 selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
260 selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
267 selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
274 if ((flags & SELECTION_SOURCE_ONLY) != 0)
276 flags &= ~SELECTION_PROVIDES; /* sources don't provide anything */
277 flags &= ~SELECTION_WITH_SOURCE;
280 if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
283 if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
286 if (!(flags & SELECTION_NOCASE))
288 id = pool_str2id(pool, name, 0);
291 if ((flags & (SELECTION_SOURCE_ONLY | SELECTION_WITH_SOURCE)) != 0 && (flags & SELECTION_NAME) != 0)
293 /* src rpms don't have provides, so we must check every solvable */
294 FOR_PROVIDES(p, pp, id) /* try fast path first */
296 Solvable *s = pool->solvables + p;
299 if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
301 if ((flags & SELECTION_SOURCE_ONLY) != 0)
302 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
303 queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
304 if ((flags & SELECTION_WITH_SOURCE) != 0)
305 selection_addsrc(pool, selection, flags);
306 return SELECTION_NAME;
309 FOR_POOL_SOLVABLES(p) /* slow path */
311 Solvable *s = pool->solvables + p;
312 if (s->name == id && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
314 if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
315 continue; /* just in case... src rpms can't be installed */
316 if ((flags & SELECTION_SOURCE_ONLY) != 0)
317 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
318 queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
319 if ((flags & SELECTION_WITH_SOURCE) != 0)
320 selection_addsrc(pool, selection, flags);
321 return SELECTION_NAME;
325 FOR_PROVIDES(p, pp, id)
327 Solvable *s = pool->solvables + p;
328 if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
331 if (s->name == id && (flags & SELECTION_NAME) != 0)
333 if ((flags & SELECTION_SOURCE_ONLY) != 0)
334 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
335 queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
336 if ((flags & SELECTION_WITH_SOURCE) != 0)
337 selection_addsrc(pool, selection, flags);
338 return SELECTION_NAME;
341 if (match && (flags & SELECTION_PROVIDES) != 0)
343 queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
344 return SELECTION_PROVIDES;
349 if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
352 if (!doglob && !(flags & SELECTION_NOCASE))
355 if (doglob && (flags & SELECTION_NOCASE) != 0)
356 globflags = FNM_CASEFOLD;
358 #if 0 /* doesn't work with selection_limit_rel yet */
359 if (doglob && !strcmp(name, "*") && (flags & SELECTION_FLAT) != 0)
361 /* can't do this for SELECTION_PROVIDES, as src rpms don't provide anything */
362 if ((flags & SELECTION_NAME) != 0)
364 queue_push2(selection, SOLVER_SOLVABLE_ALL, 0);
365 return SELECTION_NAME;
370 if ((flags & SELECTION_NAME) != 0)
372 /* looks like a name glob. hard work. */
373 FOR_POOL_SOLVABLES(p)
375 Solvable *s = pool->solvables + p;
376 if (!pool_installable(pool, s))
377 if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
379 if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
382 if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
384 if ((flags & SELECTION_SOURCE_ONLY) != 0)
385 id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
386 /* queue_pushunique2 */
387 for (i = 0; i < selection->count; i += 2)
388 if (selection->elements[i] == SOLVER_SOLVABLE_NAME && selection->elements[i + 1] == id)
390 if (i == selection->count)
391 queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
397 if ((flags & SELECTION_WITH_SOURCE) != 0)
398 selection_addsrc(pool, selection, flags);
399 return SELECTION_NAME;
402 if ((flags & SELECTION_PROVIDES))
404 /* looks like a dep glob. really hard work. */
405 for (id = 1; id < pool->ss.nstrings; id++)
407 if (!pool->whatprovides[id])
409 if ((doglob ? fnmatch(name, pool_id2str(pool, id), globflags) : strcasecmp(name, pool_id2str(pool, id))) == 0)
411 if ((flags & SELECTION_INSTALLED_ONLY) != 0)
413 FOR_PROVIDES(p, pp, id)
414 if (pool->solvables[p].repo == pool->installed)
419 queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
424 return SELECTION_PROVIDES;
430 selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
436 if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
438 /* check if theres an .arch suffix */
439 if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
441 char *rname = solv_strdup(name);
443 if (archid == ARCH_SRC || archid == ARCH_NOSRC)
444 flags |= SELECTION_SOURCE_ONLY;
445 if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
447 selection_limit_rel(pool, selection, REL_ARCH, archid);
457 selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
463 type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
464 if ((flags & SELECTION_NOCASE) != 0)
465 type |= SEARCH_NOCASE;
467 dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
468 while (dataiterator_step(&di))
470 Solvable *s = pool->solvables + di.solvid;
473 if (!pool_installable(pool, s))
474 if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
476 if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
478 queue_push(&q, di.solvid);
479 dataiterator_skip_solvable(&di);
481 dataiterator_free(&di);
485 queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
487 queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
489 return SELECTION_FILELIST;
493 selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
498 /* relation case, support:
502 rname = solv_strdup(name);
503 if ((r = strpbrk(rname, "<=>")) != 0)
505 int nend = r - rname;
517 while (*r && *r == ' ' && *r == '\t')
519 while (nend && (rname[nend - 1] == ' ' || rname[nend -1 ] == '\t'))
528 if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
531 selection_limit_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
539 #if defined(MULTI_SEMANTICS)
540 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
541 #elif defined(DEBIAN)
542 # define EVRCMP_DEPCMP EVRCMP_COMPARE
544 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
547 /* magic epoch promotion code, works only for SELECTION_NAME selections */
549 selection_limit_evr(Pool *pool, Queue *selection, char *evr)
552 for (i = j = 0; i < selection->count; i += 2)
554 Id select = selection->elements[i] & SOLVER_SELECTMASK;
555 Id id = selection->elements[i + 1];
559 const char *highest = 0;
562 FOR_JOB_SELECT(p, pp, select, id)
564 Solvable *s = pool->solvables + p;
565 const char *sevr = pool_id2str(pool, s->evr);
567 for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
569 if (sp == sevr || *sp != ':')
571 /* found epoch, compare vr */
572 if (strcmp(sp + 1, evr) != 0)
574 int r = pool_evrcmp_str(pool, sp + 1, evr, EVRCMP_DEPCMP);
575 if (r == -1 || r == 1)
576 continue; /* no match */
580 if (highestlen == sp - sevr && !strncmp(highest, sevr, highestlen))
582 if (pool_evrcmp_str(pool, sevr, highest, EVRCMP_COMPARE) <= 0)
586 highestlen = sp - sevr;
590 /* found epoch, prepend */
591 char *evrx = solv_malloc(strlen(evr) + highestlen + 2);
592 strncpy(evrx, highest, highestlen + 1);
593 strcpy(evrx + highestlen + 1, evr);
594 id = pool_str2id(pool, evrx, 1);
598 id = pool_str2id(pool, evr, 1);
599 queue_init_buffer(&tmpq, tmpqb, sizeof(tmpqb)/sizeof(*tmpqb));
600 queue_push2(&tmpq, selection->elements[i], selection->elements[i + 1]);
601 selection_limit_rel(pool, &tmpq, REL_EQ, id);
605 continue; /* oops, no match */
607 selection->elements[j] = tmpq.elements[0];
608 selection->elements[j + 1] = tmpq.elements[1];
612 queue_truncate(selection, j);
616 selection_nevra(Pool *pool, Queue *selection, const char *name, int flags)
618 char *rname, *r, *r2;
624 * nameglob-version.arch
625 * nameglob-version-release
626 * nameglob-version-release.arch
628 flags |= SELECTION_NAME;
629 flags &= ~SELECTION_PROVIDES;
631 if (pool->disttype == DISTTYPE_DEB)
633 if ((r = strchr(name, '_')) == 0)
635 rname = solv_strdup(name); /* so we can modify it */
636 r = rname + (r - name);
638 if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
643 /* is there a vaild arch? */
644 if ((r2 = strchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
646 *r2 = 0; /* split off */
647 selection_limit_rel(pool, selection, REL_ARCH, archid);
649 selection_limit_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
654 if ((r = strrchr(name, '-')) == 0)
656 rname = solv_strdup(name); /* so we can modify it */
657 r = rname + (r - name);
660 /* split off potential arch part from version */
661 if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
662 *r2 = 0; /* found valid arch, split it off */
663 if (archid == ARCH_SRC || archid == ARCH_NOSRC)
664 flags |= SELECTION_SOURCE_ONLY;
666 /* try with just the version */
667 if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
669 /* no luck, try with version-release */
670 if ((r2 = strrchr(rname, '-')) == 0)
678 if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
685 selection_limit_rel(pool, selection, REL_ARCH, archid);
686 selection_limit_evr(pool, selection, r + 1); /* magic epoch promotion */
692 selection_make(Pool *pool, Queue *selection, const char *name, int flags)
697 queue_empty(selection);
698 if (*name == '/' && (flags & SELECTION_FILELIST))
699 ret = selection_filelist(pool, selection, name, flags);
700 if (!ret && (r = strpbrk(name, "<=>")) != 0)
701 ret = selection_rel(pool, selection, name, flags);
703 ret = selection_depglob_arch(pool, selection, name, flags);
704 if (!ret && (flags & SELECTION_NAME) != 0)
705 ret = selection_nevra(pool, selection, name, flags);
706 if (ret && (flags & SELECTION_FLAT) != 0)
707 selection_flatten(pool, selection);
712 selection_limit(Pool *pool, Queue *sel1, Queue *sel2)
720 if (!sel1->count || !sel2->count)
725 if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
727 /* XXX: not 100% correct, but very useful */
729 queue_init_clone(sel1, sel2);
733 map_init(&m2, pool->nsolvables);
734 for (i = 0; i < sel2->count; i += 2)
736 Id select = sel2->elements[i] & SOLVER_SELECTMASK;
737 if (select == SOLVER_SOLVABLE_ALL)
739 if (select == SOLVER_SOLVABLE_REPO)
742 Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
744 FOR_REPO_SOLVABLES(repo, p, s)
749 FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
753 if (sel2->count == 2) /* XXX: AND all setmasks instead? */
754 setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
755 for (i = j = 0; i < sel1->count; i += 2)
757 Id select = sel1->elements[i] & SOLVER_SELECTMASK;
760 if (select == SOLVER_SOLVABLE_ALL)
762 FOR_POOL_SOLVABLES(p)
770 else if (select == SOLVER_SOLVABLE_REPO)
773 Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
775 FOR_REPO_SOLVABLES(repo, p, s)
785 FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
788 queue_pushunique(&q1, p);
797 sel1->elements[j] = sel1->elements[i] | setflags;
798 sel1->elements[j + 1] = sel1->elements[i + 1];
800 else if (q1.count > 1)
802 sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
803 sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
807 sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
808 sel1->elements[j + 1] = q1.elements[0];
812 queue_truncate(sel1, j);
816 selection_add(Pool *pool, Queue *sel1, Queue *sel2)
819 for (i = 0; i < sel2->count; i++)
820 queue_push(sel1, sel2->elements[i]);