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