2 * Copyright (c) 2013, SUSE Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Linked packages are "pseudo" packages that are bound to real packages but
12 * contain different information (name/summary/description). They are normally
13 * somehow generated from the real packages, either when the repositories are
14 * created or automatically from the packages by looking at the provides.
16 * We currently support:
19 * created from AppStream appdata xml in the repository (which is generated
20 * from files in /usr/share/appdata)
23 * created from product data in the repository (which is generated from files
24 * in /etc/products.d). In the future we may switch to using product()
25 * provides of packages.
28 * created from pattern() provides of packages.
41 #include "linkedpkg.h"
43 #ifdef ENABLE_LINKED_PKGS
46 find_application_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
51 Id pkgname = 0, appdataid = 0;
53 /* find appdata requires */
56 Id *reqp = s->repo->idarraydata + s->requires;
57 while ((req = *reqp++) != 0) /* go through all requires */
61 if (!strncmp("appdata(", pool_id2str(pool, req), 8))
67 req = appdataid ? appdataid : pkgname;
70 /* find application-appdata provides */
73 Id *prvp = s->repo->idarraydata + s->provides;
74 const char *reqs = pool_id2str(pool, req);
76 while ((prv = *prvp++) != 0) /* go through all provides */
80 prvs = pool_id2str(pool, prv);
81 if (strncmp("application-appdata(", prvs, 20))
85 if (!strcmp(prvs + 12, reqs))
90 int reqsl = strlen(reqs);
91 if (!strncmp(prvs + 20, reqs, reqsl) && !strcmp(prvs + 20 + reqsl, ")"))
97 return; /* huh, no provides found? */
99 FOR_PROVIDES(p, pp, req)
100 if (pool->solvables[p].repo == s->repo)
101 if (!pkgname || pool->solvables[p].name == pkgname)
103 if (!qr->count && pkgname && appdataid)
105 /* huh, no matching package? try without pkgname filter */
106 FOR_PROVIDES(p, pp, req)
107 if (pool->solvables[p].repo == s->repo)
112 FOR_PROVIDES(p, pp, prv)
113 if (pool->solvables[p].repo == s->repo)
123 find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
127 unsigned int sbt = 0;
129 /* search for project requires */
133 Id req, *reqp = s->repo->idarraydata + s->requires;
134 const char *nn = pool_id2str(pool, s->name);
135 int nnl = strlen(nn);
136 while ((req = *reqp++) != 0) /* go through all requires */
140 Reldep *rd = GETRELDEP(pool, req);
141 if (rd->flags != REL_EQ || rd->evr != s->evr)
143 rn = pool_id2str(pool, rd->name);
144 if (!strncmp(rn, "product(", 8) && !strncmp(rn + 8, nn + 8, nnl - 8) && !strcmp( rn + nnl, ")"))
153 /* too bad. construct from scratch */
154 str = pool_tmpjoin(pool, pool_id2str(pool, s->name), ")", 0);
156 namerelid = pool_rel2id(pool, pool_str2id(pool, str, 1), s->evr, REL_EQ, 1);
158 FOR_PROVIDES(p, pp, namerelid)
160 Solvable *ps = pool->solvables + p;
161 if (ps->repo != s->repo || ps->arch != s->arch)
167 /* multiple providers. try buildtime filter */
168 sbt = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
174 for (i = j = 0; i < qr->count; i++)
176 bt = solvable_lookup_num(pool->solvables + qr->elements[i], SOLVABLE_BUILDTIME, 0);
178 filterqp = 0; /* can't filter */
179 if (!bt || bt == sbt)
180 qr->elements[j++] = qr->elements[i];
185 sbt = 0; /* filter failed */
188 if (!qr->count && s->repo == pool->installed)
190 /* oh no! Look up reference file */
192 const char *refbasename = solvable_lookup_str(s, PRODUCT_REFERENCEFILE);
193 dataiterator_init(&di, pool, s->repo, 0, SOLVABLE_FILELIST, refbasename, SEARCH_STRING);
194 while (dataiterator_step(&di))
195 queue_push(qr, di.solvid);
196 dataiterator_free(&di);
199 dataiterator_init(&di, pool, s->repo, 0, PRODUCT_REFERENCEFILE, refbasename, SEARCH_STRING);
200 while (dataiterator_step(&di))
201 queue_push(qp, di.solvid);
202 dataiterator_free(&di);
208 FOR_PROVIDES(p, pp, s->name)
210 Solvable *ps = pool->solvables + p;
211 if (s->name != ps->name || ps->repo != s->repo || ps->arch != s->arch || s->evr != ps->evr)
213 if (sbt && solvable_lookup_num(ps, SOLVABLE_BUILDTIME, 0) != sbt)
221 *prvidp = solvable_selfprovidedep(s);
225 find_pattern_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
227 Id p, pp, *pr, apevr = 0, aprel = 0;
229 /* check if autopattern */
232 for (pr = s->repo->idarraydata + s->provides; (p = *pr++) != 0; )
235 Reldep *rd = GETRELDEP(pool, p);
236 if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autopattern()"))
245 FOR_PROVIDES(p, pp, apevr)
247 Solvable *s2 = pool->solvables + p;
248 if (s2->repo == s->repo && s2->name == apevr && s2->evr == s->evr && s2->vendor == s->vendor)
253 FOR_PROVIDES(p, pp, aprel)
255 Solvable *s2 = pool->solvables + p;
256 if (s2->repo == s->repo && s2->evr == s->evr && s2->vendor == s->vendor)
266 /* the following two functions are used in solvable_lookup_str_base to do
267 * translated lookups on the product/pattern packages
270 find_autopattern_name(Pool *pool, Solvable *s)
275 for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
278 Reldep *rd = GETRELDEP(pool, prv);
279 if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autopattern()"))
280 return strncmp(pool_id2str(pool, rd->evr), "pattern:", 8) != 0 ? rd->evr : 0;
286 find_autoproduct_name(Pool *pool, Solvable *s)
291 for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
294 Reldep *rd = GETRELDEP(pool, prv);
295 if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autoproduct()"))
296 return strncmp(pool_id2str(pool, rd->evr), "product:", 8) != 0 ? rd->evr : 0;
302 find_package_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
304 const char *name = pool_id2str(pool, s->name);
305 if (name[0] == 'a' && !strncmp("application:", name, 12))
306 find_application_link(pool, s, reqidp, qr, prvidp, qp);
307 else if (name[0] == 'p' && !strncmp("pattern:", name, 7))
308 find_pattern_link(pool, s, reqidp, qr, prvidp, qp);
309 else if (name[0] == 'p' && !strncmp("product:", name, 8))
310 find_product_link(pool, s, reqidp, qr, prvidp, qp);
314 name_min_max(Pool *pool, Solvable *s, Id *namep, Id *minp, Id *maxp)
321 queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
322 find_package_link(pool, s, 0, &q, 0, 0);
328 s = pool->solvables + q.elements[0];
331 for (i = 1; i < q.count; i++)
333 s = pool->solvables + q.elements[i];
339 if (s->evr == min || s->evr == max)
341 if (pool_evrcmp(pool, min, s->evr, EVRCMP_COMPARE) >= 0)
343 else if (min == max || pool_evrcmp(pool, max, s->evr, EVRCMP_COMPARE) <= 0)
354 pool_link_evrcmp(Pool *pool, Solvable *s1, Solvable *s2)
356 Id name1, evrmin1, evrmax1;
357 Id name2, evrmin2, evrmax2;
359 if (s1->name != s2->name)
360 return 0; /* can't compare */
361 if (!name_min_max(pool, s1, &name1, &evrmin1, &evrmax1))
363 if (!name_min_max(pool, s2, &name2, &evrmin2, &evrmax2))
365 /* compare linked names */
368 if (evrmin1 == evrmin2 && evrmax1 == evrmax2)
370 /* now compare evr intervals */
371 if (evrmin1 == evrmax1 && evrmin2 == evrmax2)
372 return pool_evrcmp(pool, evrmin1, evrmax2, EVRCMP_COMPARE);
373 if (evrmin1 != evrmax2 && pool_evrcmp(pool, evrmin1, evrmax2, EVRCMP_COMPARE) > 0)
375 if (evrmax1 != evrmin2 && pool_evrcmp(pool, evrmax1, evrmin2, EVRCMP_COMPARE) < 0)