add autoproduct support
[platform/upstream/libsolv.git] / ext / repo_autopattern.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 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <errno.h>
15
16 #include "pool.h"
17 #include "repo.h"
18 #include "util.h"
19 #include "repo_autopattern.h"
20
21 static void
22 unescape(char *p)
23 {
24   char *q = p;
25   while (*p)
26     {
27       if (*p == '%' && p[1] && p[2])
28         {
29           int d1 = p[1], d2 = p[2];
30           if (d1 >= '0' && d1 <= '9')
31             d1 -= '0';
32           else if (d1 >= 'a' && d1 <= 'f')
33             d1 -= 'a' - 10;
34           else if (d1 >= 'A' && d1 <= 'F')
35             d1 -= 'A' - 10;
36           else
37             d1 = -1;
38           if (d2 >= '0' && d2 <= '9')
39             d2 -= '0';
40           else if (d2 >= 'a' && d2 <= 'f')
41             d2 -= 'a' - 10;
42           else if (d2 >= 'A' && d2 <= 'F')
43             d2 -= 'A' - 10;
44           else
45             d2 = -1;
46           if (d1 != -1 && d2 != -1)
47             {
48               *q++ = d1 << 4 | d2;
49               p += 3;
50               continue;
51             }
52         }
53       *q++ = *p++;
54     }
55   *q = 0;
56 }
57
58 int
59 repo_add_autopattern(Repo *repo, int flags)
60 {
61   Pool *pool = repo->pool;
62   Repodata *data = 0;
63   Solvable *s, *s2;
64   Queue patq, patq2;
65   Queue prdq, prdq2;
66   Id p;
67   Id pattern_id, product_id;
68   Id autopattern_id = 0, autoproduct_id = 0;
69   int i, j;
70
71   queue_init(&patq);
72   queue_init(&patq2);
73   queue_init(&prdq);
74   queue_init(&prdq2);
75
76   pattern_id = pool_str2id(pool, "pattern()", 9);
77   product_id = pool_str2id(pool, "product()", 9);
78   FOR_REPO_SOLVABLES(repo, p, s)
79     {
80       const char *n = pool_id2str(pool, s->name);
81       if (*n == 'p')
82         {
83           if (!strncmp("pattern:", n, 8))
84             {
85               queue_push(&patq, p);
86               continue;
87             }
88           else if (!strncmp("product:", n, 8))
89             {
90               queue_push(&prdq, p);
91               continue;
92             }
93         }
94       if (s->provides)
95         {
96           Id prv, *prvp = repo->idarraydata + s->provides;
97           while ((prv = *prvp++) != 0)            /* go through all provides */
98             if (ISRELDEP(prv))
99               {
100                 Reldep *rd = GETRELDEP(pool, prv);
101                 if (rd->flags != REL_EQ)
102                   continue;
103                 if (rd->name == pattern_id)
104                   {
105                     queue_push2(&patq2, p, rd->evr);
106                     break;
107                   }
108                 if (rd->name == product_id)
109                   {
110                     queue_push2(&prdq2, p, rd->evr);
111                     break;
112                   }
113               }
114         }
115     }
116   for (i = 0; i < patq2.count; i += 2)
117     {
118       const char *pn = 0;
119       char *newname;
120       Id name, prv, *prvp;
121       const char *str;
122       unsigned long long num;
123
124       s = pool->solvables + patq2.elements[i];
125       /* construct new name */
126       newname = pool_tmpjoin(pool, "pattern:", pool_id2str(pool, patq2.elements[i + 1]), 0);
127       unescape(newname);
128       name = pool_str2id(pool, newname, 0);
129       if (name)
130         {
131           /* check if we already have that pattern */
132           for (j = 0; j < patq.count; j++)
133             {
134               s2 = pool->solvables + patq.elements[j];
135               if (s2->name == name && s2->arch == s->arch && s2->evr == s->evr)
136                 break;
137             }
138           if (j < patq.count)
139             continue;   /* yes, do not add again */
140         }
141       /* new pattern */
142       if (!name)
143         name = pool_str2id(pool, newname, 1);
144       if (!data)
145         {
146           repo_internalize(repo);       /* to make that the lookups work */
147           data = repo_add_repodata(repo, flags);
148         }
149       s2 = pool_id2solvable(pool, repo_add_solvable(repo));
150       s = pool->solvables + patq2.elements[i];  /* re-calc pointer */
151       s2->name = name;
152       s2->arch = s->arch;
153       s2->evr = s->evr;
154       s2->vendor = s->vendor;
155       /* add link requires */
156       s2->requires = repo_addid_dep(repo, s2->requires, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1) , 0);
157       /* add autopattern provides */
158       if (!autopattern_id)
159         autopattern_id = pool_str2id(pool, "autopattern()", 1);
160       s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autopattern_id, s->name, REL_EQ, 1), 0);
161       /* add self provides */
162       s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
163       if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
164         repodata_set_num(data, s2 - pool->solvables, SOLVABLE_INSTALLTIME, num);
165       if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
166         repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
167       if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
168         repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
169       if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
170         repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
171       /* fill in stuff from provides */
172       prvp = repo->idarraydata + s->provides;
173       while ((prv = *prvp++) != 0)            /* go through all provides */
174         {
175           Id evr = 0;
176           if (ISRELDEP(prv))
177             {
178               Reldep *rd = GETRELDEP(pool, prv);
179               if (rd->flags != REL_EQ)
180                 continue;
181               prv = rd->name;
182               evr = rd->evr;
183             }
184           pn = pool_id2str(pool, prv);
185           if (strncmp("pattern-", pn, 8) != 0)
186             continue;
187           newname = 0;
188           if (evr)
189             {
190               newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
191               unescape(newname);
192             }
193           if (!strncmp(pn, "pattern-category(", 17) && evr)
194             {
195               char lang[9];
196               int l = strlen(pn);
197               Id langtag;
198               if (l > 17 + 9 || pn[l - 1] != ')')
199                 continue;
200               strncpy(lang, pn + 17, l - 17 - 1);
201               lang[l - 17 - 1] = 0;
202               langtag = SOLVABLE_CATEGORY;
203               if (*lang && strcmp(lang, "en") != 0)
204                 langtag = pool_id2langid(pool, SOLVABLE_CATEGORY, lang, 1);
205               if (newname[solv_validutf8(newname)] == 0)
206                 repodata_set_str(data, s2 - pool->solvables, langtag, newname);
207               else
208                 {
209                   char *ustr = solv_latin1toutf8(newname);
210                   repodata_set_str(data, s2 - pool->solvables, langtag, ustr);
211                   solv_free(ustr);
212                 }
213             }
214           else if (!strcmp(pn, "pattern-includes()") && evr)
215             repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_INCLUDES, pool_tmpjoin(pool, "pattern:", newname, 0));
216           else if (!strcmp(pn, "pattern-extends()") && evr)
217             repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_EXTENDS, pool_tmpjoin(pool, "pattern:", newname, 0));
218           else if (!strcmp(pn, "pattern-icon()") && evr)
219             repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ICON, newname);
220           else if (!strcmp(pn, "pattern-order()") && evr)
221             repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ORDER, newname);
222           else if (!strcmp(pn, "pattern-visible()") && !evr)
223             repodata_set_void(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE);
224         }
225     }
226   queue_free(&patq);
227   queue_free(&patq2);
228
229   if (repo == pool->installed)
230     queue_empty(&prdq2);        /* no auto products for installed repos */
231
232   for (i = 0; i < prdq2.count; i += 2)
233     {
234       const char *pn = 0;
235       char *newname;
236       Id name, evr = 0, prv, *prvp;
237       const char *str;
238       unsigned long long num;
239
240       s = pool->solvables + prdq2.elements[i];
241       /* construct new name */
242       newname = pool_tmpjoin(pool, "product(", pool_id2str(pool, prdq2.elements[i + 1]), ")");
243       unescape(newname);
244       name = pool_str2id(pool, newname, 0);
245       if (!name)
246         continue;       /* must have it in provides! */
247       prvp = repo->idarraydata + s->provides;
248       while ((prv = *prvp++) != 0)            /* go through all provides */
249         {
250           if (ISRELDEP(prv))
251             {
252               Reldep *rd = GETRELDEP(pool, prv);
253               if (rd->name == name && rd->flags == REL_EQ)
254                 {
255                   evr = rd->evr;
256                   break;
257                 }
258             }
259         }
260       if (!prv)
261         continue;       /* not found in provides */
262       newname = pool_tmpjoin(pool, "product:", pool_id2str(pool, prdq2.elements[i + 1]), 0);
263       unescape(newname);
264       name = pool_str2id(pool, newname, 0);
265       if (name)
266         {
267           /* check if we already have that product */
268           for (j = 0; j < prdq.count; j++)
269             {
270               s2 = pool->solvables + prdq.elements[j];
271               if (s2->name == name && s2->arch == s->arch && s2->evr == evr)
272                 break;
273             }
274           if (j < prdq.count)
275             continue;   /* yes, do not add again */
276         }
277       /* new product */
278       if (!name)
279         name = pool_str2id(pool, newname, 1);
280       if (!data)
281         {
282           repo_internalize(repo);       /* to make that the lookups work */
283           data = repo_add_repodata(repo, flags);
284         }
285       if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
286         continue;               /* eek, not for installed packages, please! */
287       s2 = pool_id2solvable(pool, repo_add_solvable(repo));
288       s = pool->solvables + prdq2.elements[i];  /* re-calc pointer */
289       s2->name = name;
290       s2->arch = s->arch;
291       s2->evr = evr;
292       s2->vendor = s->vendor;
293       /* add link requires */
294       s2->requires = repo_addid_dep(repo, s2->requires, prv, 0);
295       if (!autoproduct_id)
296         autoproduct_id = pool_str2id(pool, "autoproduct()", 1);
297       s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autoproduct_id, s->name, REL_EQ, 1), 0);
298       /* add self provides */
299       s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
300       if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
301         repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
302       if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
303         repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
304       if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
305         repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
306       if ((str = solvable_lookup_str(s, SOLVABLE_DISTRIBUTION)) != 0)
307         repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DISTRIBUTION, str);
308       /* fill in stuff from provides */
309       prvp = repo->idarraydata + s->provides;
310       while ((prv = *prvp++) != 0)            /* go through all provides */
311         {
312           Id evr = 0;
313           if (ISRELDEP(prv))
314             {
315               Reldep *rd = GETRELDEP(pool, prv);
316               if (rd->flags != REL_EQ)
317                 continue;
318               prv = rd->name;
319               evr = rd->evr;
320             }
321           pn = pool_id2str(pool, prv);
322           if (strncmp("product-", pn, 8) != 0)
323             continue;
324           newname = 0;
325           if (evr)
326             {
327               newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
328               unescape(newname);
329             }
330           if (!strcmp(pn, "product-label()") && evr)
331             repodata_set_str(data, s2 - pool->solvables, PRODUCT_SHORTLABEL, newname);
332           else if (!strcmp(pn, "product-type()") && evr)
333             repodata_set_str(data, s2 - pool->solvables, PRODUCT_TYPE, newname);
334           else if (!strcmp(pn, "product-cpeid()") && evr)
335             repodata_set_str(data, s2 - pool->solvables, SOLVABLE_CPEID, newname);
336           else if (!strcmp(pn, "product-flags()") && evr)
337             repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_FLAGS, newname);
338           else if (!strncmp(pn, "product-url(", 12) && evr && pn[12] && pn[13] && strlen(pn + 12) < 32)
339             {
340               char type[34];
341               strcpy(type, pn + 12);
342               type[strlen(type) - 1] = 0;       /* closing ) */
343               repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL_TYPE, type);
344               repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL, newname);
345             }
346         }
347     }
348   queue_free(&prdq);
349   queue_free(&prdq2);
350
351   if (data && !(flags & REPO_NO_INTERNALIZE))
352     repodata_internalize(data);
353   else if (!data && !(flags & REPO_NO_INTERNALIZE))
354     repo_internalize(repo);
355   return 0;
356 }
357