Imported Upstream version 0.6.10
[platform/upstream/libsolv.git] / src / linkedpkg.c
1 /*
2  * Copyright (c) 2013, SUSE Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * linkedpkg.c
10  *
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.
15  *
16  * We currently support:
17  *
18  * application:
19  *   created from AppStream appdata xml in the repository (which is generated
20  *   from files in /usr/share/appdata)
21  *
22  * product:
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.
26  *
27  * pattern:
28  *   created from pattern() provides of packages.
29  *
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <assert.h>
37
38 #include "pool.h"
39 #include "repo.h"
40 #include "linkedpkg.h"
41
42 #ifdef ENABLE_LINKED_PKGS
43
44 void
45 find_application_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
46 {
47   Id req = 0;
48   Id prv = 0;
49   Id p, pp;
50   Id pkgname = 0;
51
52   /* find appdata requires */
53   if (s->requires)
54     {
55       Id appdataid = 0;
56       Id *reqp = s->repo->idarraydata + s->requires;
57       while ((req = *reqp++) != 0)            /* go through all requires */
58         {
59           if (ISRELDEP(req))
60             continue;
61           if (!strncmp("appdata(", pool_id2str(pool, req), 8))
62             appdataid = req;
63           else
64             pkgname = req;
65         }
66       req = appdataid;
67     }
68   if (!req)
69     return;
70   /* find application-appdata provides */
71   if (s->provides)
72     {
73       Id *prvp = s->repo->idarraydata + s->provides;
74       while ((prv = *prvp++) != 0)            /* go through all provides */
75         {
76           if (ISRELDEP(prv))
77             continue;
78           if (strncmp("application-appdata(", pool_id2str(pool, prv), 20))
79             continue;
80           if (!strcmp(pool_id2str(pool, prv) + 12, pool_id2str(pool, req)))
81             break;
82         }
83     }
84   if (!prv)
85     return;     /* huh, no provides found? */
86   /* now link em */
87   FOR_PROVIDES(p, pp, req)
88     if (pool->solvables[p].repo == s->repo)
89       if (!pkgname || pool->solvables[p].name == pkgname)
90         queue_push(qr, p);
91   if (!qr->count && pkgname)
92     {
93       /* huh, no matching package? try without pkgname filter */
94       FOR_PROVIDES(p, pp, req)
95         if (pool->solvables[p].repo == s->repo)
96           queue_push(qr, p);
97     }
98   if (qp)
99     {
100       FOR_PROVIDES(p, pp, prv)
101         if (pool->solvables[p].repo == s->repo)
102           queue_push(qp, p);
103     }
104   if (reqidp)
105     *reqidp = req;
106   if (prvidp)
107     *prvidp = prv;
108 }
109
110 void
111 find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
112 {
113   Id p, pp, namerelid;
114   char *str;
115
116   /* search for project requires */
117   namerelid = 0;
118   if (s->requires)
119     {
120       Id req, *reqp = s->repo->idarraydata + s->requires;
121       const char *nn = pool_id2str(pool, s->name);
122       int nnl = strlen(nn);
123       while ((req = *reqp++) != 0)            /* go through all requires */
124         if (ISRELDEP(req))
125           {
126             const char *rn;
127             Reldep *rd = GETRELDEP(pool, req);
128             if (rd->flags != REL_EQ || rd->evr != s->evr)
129               continue;
130             rn = pool_id2str(pool, rd->name);
131             if (!strncmp(rn, "product(", 8) && !strncmp(rn + 8, nn + 8, nnl - 8) && !strcmp( rn + nnl, ")"))
132               {
133                 namerelid = req;
134                 break;
135               }
136           }
137     }
138   if (!namerelid)
139     {
140       /* too bad. construct from scratch */
141       str = pool_tmpjoin(pool, pool_id2str(pool, s->name), ")", 0);
142       str[7] = '(';
143       namerelid = pool_rel2id(pool, pool_str2id(pool, str, 1), s->evr, REL_EQ, 1);
144     }
145   FOR_PROVIDES(p, pp, namerelid)
146     {
147       Solvable *ps = pool->solvables + p;
148       if (ps->repo != s->repo || ps->arch != s->arch)
149         continue;
150       queue_push(qr, p);
151     }
152   if (!qr->count && s->repo == pool->installed)
153     {
154       /* oh no! Look up reference file */
155       Dataiterator di;
156       const char *refbasename = solvable_lookup_str(s, PRODUCT_REFERENCEFILE);
157       dataiterator_init(&di, pool, s->repo, 0, SOLVABLE_FILELIST, refbasename, SEARCH_STRING);
158       while (dataiterator_step(&di))
159         queue_push(qr, di.solvid);
160       dataiterator_free(&di);
161       if (qp)
162         {
163           dataiterator_init(&di, pool, s->repo, 0, PRODUCT_REFERENCEFILE, refbasename, SEARCH_STRING);
164           while (dataiterator_step(&di))
165             queue_push(qp, di.solvid);
166           dataiterator_free(&di);
167         }
168     }
169   else if (qp)
170     {
171       /* find qp */
172       FOR_PROVIDES(p, pp, s->name)
173         {
174           Solvable *ps = pool->solvables + p;
175           if (s->name != ps->name || ps->repo != s->repo || ps->arch != s->arch || s->evr != ps->evr)
176             continue;
177           queue_push(qp, p);
178         }
179     }
180   if (reqidp)
181     *reqidp = namerelid;
182   if (prvidp)
183     *prvidp = solvable_selfprovidedep(s);
184 }
185
186 void
187 find_pattern_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
188 {
189   Id p, pp, *pr, apevr = 0, aprel = 0;
190
191   /* check if autopattern */
192   if (!s->provides)
193     return;
194   for (pr = s->repo->idarraydata + s->provides; (p = *pr++) != 0; )
195     if (ISRELDEP(p))
196       {
197         Reldep *rd = GETRELDEP(pool, p);
198         if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autopattern()"))
199           {
200             aprel = p;
201             apevr = rd->evr;
202             break;
203           }
204       }
205   if (!apevr)
206     return;
207   FOR_PROVIDES(p, pp, apevr)
208     {
209       Solvable *s2 = pool->solvables + p;
210       if (s2->repo == s->repo && s2->name == apevr && s2->evr == s->evr && s2->vendor == s->vendor)
211         queue_push(qr, p);
212     }
213   if (qp)
214     {
215       FOR_PROVIDES(p, pp, aprel)
216         {
217           Solvable *s2 = pool->solvables + p;
218           if (s2->repo == s->repo && s2->evr == s->evr && s2->vendor == s->vendor)
219             queue_push(qp, p);
220         }
221     }
222   if (reqidp)
223     *reqidp = apevr;
224   if (prvidp)
225     *prvidp = aprel;
226 }
227
228 /* the following two functions are used in solvable_lookup_str_base to do
229  * translated lookups on the product/pattern packages
230  */
231 Id
232 find_autopattern_name(Pool *pool, Solvable *s)
233 {
234   Id prv, *prvp;
235   if (!s->provides)
236     return 0;
237   for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
238     if (ISRELDEP(prv))
239       {
240         Reldep *rd = GETRELDEP(pool, prv);
241         if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autopattern()"))
242           return strncmp(pool_id2str(pool, rd->evr), "pattern:", 8) != 0 ? rd->evr : 0;
243       }
244   return 0;
245 }
246
247 Id
248 find_autoproduct_name(Pool *pool, Solvable *s)
249 {
250   Id prv, *prvp;
251   if (!s->provides)
252     return 0;
253   for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
254     if (ISRELDEP(prv))
255       {
256         Reldep *rd = GETRELDEP(pool, prv);
257         if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autoproduct()"))
258           return strncmp(pool_id2str(pool, rd->evr), "product:", 8) != 0 ? rd->evr : 0;
259       }
260   return 0;
261 }
262
263 void
264 find_package_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
265 {
266   const char *name = pool_id2str(pool, s->name);
267   if (name[0] == 'a' && !strncmp("application:", name, 12))
268     find_application_link(pool, s, reqidp, qr, prvidp, qp);
269   else if (name[0] == 'p' && !strncmp("pattern:", name, 7))
270     find_pattern_link(pool, s, reqidp, qr, prvidp, qp);
271   else if (name[0] == 'p' && !strncmp("product:", name, 8))
272     find_product_link(pool, s, reqidp, qr, prvidp, qp);
273 }
274
275 #endif