2 * Copyright (c) 2013, SUSE Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 #include <sys/types.h>
22 #include "repo_autopattern.h"
30 if (*p == '%' && p[1] && p[2])
32 int d1 = p[1], d2 = p[2];
33 if (d1 >= '0' && d1 <= '9')
35 else if (d1 >= 'a' && d1 <= 'f')
37 else if (d1 >= 'A' && d1 <= 'F')
41 if (d2 >= '0' && d2 <= '9')
43 else if (d2 >= 'a' && d2 <= 'f')
45 else if (d2 >= 'A' && d2 <= 'F')
49 if (d1 != -1 && d2 != -1)
62 datestr2timestamp(const char *date)
69 for (p = date; *p >= '0' && *p <= '9'; p++)
73 memset(&tm, 0, sizeof(tm));
74 p = strptime(date, "%F%T", &tm);
77 memset(&tm, 0, sizeof(tm));
78 p = strptime(date, "%F", &tm);
85 /* we just look at the repodata keys and do not iterate
86 * over the solvables, because iterating would mean a
87 * load of stub repodata areas */
89 find_langkeys(Repo *repo, Id keyname, Queue *q)
91 Pool *pool = repo->pool;
94 const char *keyname_str;
97 keyname_str = pool_id2str(pool, keyname);
98 keyname_len = strlen(keyname_str);
100 for (rid = 1; rid < repo->nrepodata; rid++)
102 Repodata *data = repo_id2repodata(repo, rid);
103 for (i = 1; i < data->nkeys; i++)
105 const char *s = pool_id2str(pool, data->keys[i].name);
106 if (!strncmp(s, keyname_str, keyname_len) && s[keyname_len] == ':')
107 queue_pushunique(q, data->keys[i].name);
113 repo_add_autopattern(Repo *repo, int flags)
115 Pool *pool = repo->pool;
121 Id pattern_id, product_id;
122 Id autopattern_id = 0, autoproduct_id = 0;
131 if (repo == pool->installed)
132 flags |= ADD_NO_AUTOPRODUCTS; /* no auto products for installed repos */
134 pattern_id = pool_str2id(pool, "pattern()", 1);
135 product_id = pool_str2id(pool, "product()", 1);
137 queue_init(&categorykeys);
138 FOR_REPO_SOLVABLES(repo, p, s)
140 const char *n = pool_id2str(pool, s->name);
143 if (!strncmp("pattern:", n, 8))
145 queue_push(&patq, p);
148 else if (!strncmp("product:", n, 8))
150 queue_push(&prdq, p);
156 Id prv, *prvp = repo->idarraydata + s->provides;
157 while ((prv = *prvp++) != 0) /* go through all provides */
160 Reldep *rd = GETRELDEP(pool, prv);
161 if (rd->flags != REL_EQ)
163 if (rd->name == pattern_id)
165 const char *evrstr = pool_id2str(pool, rd->evr);
166 if (evrstr[0] == '.') /* hack to allow provides that do not create a pattern */
168 if (patq2.count && patq2.elements[patq2.count - 2] == p)
170 /* hmm, two provides. choose by evrstr */
171 if (strcmp(evrstr, pool_id2str(pool, patq2.elements[patq2.count - 1])) >= 0)
175 queue_push2(&patq2, p, rd->evr);
177 if (rd->name == product_id)
179 const char *evrstr = pool_id2str(pool, rd->evr);
180 if (prdq2.count && prdq2.elements[prdq2.count - 2] == p)
182 /* hmm, two provides. choose by evrstr */
183 if (strcmp(evrstr, pool_id2str(pool, prdq2.elements[prdq2.count - 1])) >= 0)
187 queue_push2(&prdq2, p, rd->evr);
194 find_langkeys(repo, SOLVABLE_CATEGORY, &categorykeys);
195 queue_unshift(&categorykeys, SOLVABLE_CATEGORY);
197 for (i = 0; i < patq2.count; i += 2)
203 unsigned long long num;
205 s = pool->solvables + patq2.elements[i];
206 /* construct new name */
207 newname = pool_tmpjoin(pool, "pattern:", pool_id2str(pool, patq2.elements[i + 1]), 0);
209 name = pool_str2id(pool, newname, 0);
212 /* check if we already have that pattern */
213 for (j = 0; j < patq.count; j++)
215 s2 = pool->solvables + patq.elements[j];
216 if (s2->name == name && s2->arch == s->arch && s2->evr == s->evr)
220 continue; /* yes, do not add again */
224 name = pool_str2id(pool, newname, 1);
227 repo_internalize(repo); /* to make that the lookups work */
228 data = repo_add_repodata(repo, flags);
230 s2 = pool_id2solvable(pool, repo_add_solvable(repo));
231 s = pool->solvables + patq2.elements[i]; /* re-calc pointer */
235 s2->vendor = s->vendor;
236 /* add link requires */
237 s2->requires = repo_addid_dep(repo, s2->requires, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1) , 0);
238 /* add autopattern provides */
240 autopattern_id = pool_str2id(pool, "autopattern()", 1);
241 s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autopattern_id, s->name, REL_EQ, 1), 0);
242 /* add self provides */
243 s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
244 if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
245 repodata_set_num(data, s2 - pool->solvables, SOLVABLE_INSTALLTIME, num);
246 if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
247 repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
248 if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
249 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
250 if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
251 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
252 /* fill in stuff from provides */
253 prvp = repo->idarraydata + s->provides;
254 while ((prv = *prvp++) != 0) /* go through all provides */
259 Reldep *rd = GETRELDEP(pool, prv);
260 if (rd->flags != REL_EQ)
265 pn = pool_id2str(pool, prv);
266 if (strncmp("pattern-", pn, 8) != 0)
271 newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
274 if (!strncmp(pn, "pattern-category(", 17) && evr)
279 if (l > 17 + 9 || pn[l - 1] != ')')
281 strncpy(lang, pn + 17, l - 17 - 1);
282 lang[l - 17 - 1] = 0;
283 langtag = SOLVABLE_CATEGORY;
284 if (*lang && strcmp(lang, "en") != 0)
285 langtag = pool_id2langid(pool, SOLVABLE_CATEGORY, lang, 1);
286 if (newname[solv_validutf8(newname)] == 0)
287 repodata_set_str(data, s2 - pool->solvables, langtag, newname);
290 char *ustr = solv_latin1toutf8(newname);
291 repodata_set_str(data, s2 - pool->solvables, langtag, ustr);
295 else if (!strcmp(pn, "pattern-includes()") && evr)
296 repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_INCLUDES, pool_tmpjoin(pool, "pattern:", newname, 0));
297 else if (!strcmp(pn, "pattern-extends()") && evr)
298 repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_EXTENDS, pool_tmpjoin(pool, "pattern:", newname, 0));
299 else if (!strcmp(pn, "pattern-icon()") && evr)
300 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ICON, newname);
301 else if (!strcmp(pn, "pattern-order()") && evr)
302 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ORDER, newname);
303 else if (!strcmp(pn, "pattern-visible()"))
306 repodata_set_void(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE);
308 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE, newname);
311 /* also try to copy the pattern category from the solvable */
312 for (j = 0; j < categorykeys.count; j++)
314 Id catkey = categorykeys.elements[j];
315 if ((str = solvable_lookup_str(s, catkey)) != 0)
316 repodata_set_str(data, s2 - pool->solvables, catkey, str);
321 queue_free(&categorykeys);
323 if ((flags & ADD_NO_AUTOPRODUCTS) != 0)
326 for (i = 0; i < prdq2.count; i += 2)
330 Id name, evr = 0, prv, *prvp;
332 unsigned long long num;
334 s = pool->solvables + prdq2.elements[i];
335 /* construct new name */
336 newname = pool_tmpjoin(pool, "product(", pool_id2str(pool, prdq2.elements[i + 1]), ")");
338 name = pool_str2id(pool, newname, 0);
340 continue; /* must have it in provides! */
341 prvp = repo->idarraydata + s->provides;
342 while ((prv = *prvp++) != 0) /* go through all provides */
346 Reldep *rd = GETRELDEP(pool, prv);
347 if (rd->name == name && rd->flags == REL_EQ)
355 continue; /* not found in provides */
356 newname = pool_tmpjoin(pool, "product:", pool_id2str(pool, prdq2.elements[i + 1]), 0);
358 name = pool_str2id(pool, newname, 0);
361 /* check if we already have that product */
362 for (j = 0; j < prdq.count; j++)
364 s2 = pool->solvables + prdq.elements[j];
365 if (s2->name == name && s2->arch == s->arch && s2->evr == evr)
369 continue; /* yes, do not add again */
373 name = pool_str2id(pool, newname, 1);
376 repo_internalize(repo); /* to make that the lookups work */
377 data = repo_add_repodata(repo, flags);
379 if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
380 continue; /* eek, not for installed packages, please! */
381 s2 = pool_id2solvable(pool, repo_add_solvable(repo));
382 s = pool->solvables + prdq2.elements[i]; /* re-calc pointer */
386 s2->vendor = s->vendor;
387 /* add link requires */
388 s2->requires = repo_addid_dep(repo, s2->requires, prv, 0);
390 autoproduct_id = pool_str2id(pool, "autoproduct()", 1);
391 s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autoproduct_id, s->name, REL_EQ, 1), 0);
392 /* add self provides */
393 s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
394 if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
395 repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
396 if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
397 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
398 if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
399 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
400 if ((str = solvable_lookup_str(s, SOLVABLE_DISTRIBUTION)) != 0)
401 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DISTRIBUTION, str);
402 /* fill in stuff from provides */
403 prvp = repo->idarraydata + s->provides;
404 while ((prv = *prvp++) != 0) /* go through all provides */
409 Reldep *rd = GETRELDEP(pool, prv);
410 if (rd->flags != REL_EQ)
415 pn = pool_id2str(pool, prv);
416 if (strncmp("product-", pn, 8) != 0)
421 newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
424 if (!strcmp(pn, "product-label()") && evr)
425 repodata_set_str(data, s2 - pool->solvables, PRODUCT_SHORTLABEL, newname);
426 else if (!strcmp(pn, "product-register-target()") && evr)
427 repodata_set_str(data, s2 - pool->solvables, PRODUCT_REGISTER_TARGET, newname);
428 else if (!strcmp(pn, "product-register-flavor()") && evr)
429 repodata_set_str(data, s2 - pool->solvables, PRODUCT_REGISTER_FLAVOR, newname);
430 else if (!strcmp(pn, "product-type()") && evr)
431 repodata_set_str(data, s2 - pool->solvables, PRODUCT_TYPE, newname);
432 else if (!strcmp(pn, "product-cpeid()") && evr)
433 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_CPEID, newname);
434 else if (!strcmp(pn, "product-flags()") && evr)
435 repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_FLAGS, newname);
436 else if (!strcmp(pn, "product-updates-repoid()") && evr)
438 Id h = repodata_new_handle(data);
439 repodata_set_str(data, h, PRODUCT_UPDATES_REPOID, newname);
440 repodata_add_flexarray(data, s2 - pool->solvables, PRODUCT_UPDATES, h);
442 else if (!strcmp(pn, "product-endoflife()"))
444 /* FATE#320699: Support tri-state product-endoflife (tag absent, present but nodate(0), present + date) */
445 repodata_set_num(data, s2 - pool->solvables, PRODUCT_ENDOFLIFE,(evr ? datestr2timestamp(newname) : 0) );
447 else if (!strncmp(pn, "product-url(", 12) && evr && pn[12] && pn[13] && strlen(pn + 12) < 32)
450 strcpy(type, pn + 12);
451 type[strlen(type) - 1] = 0; /* closing ) */
452 repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL_TYPE, type);
453 repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL, newname);
460 if (data && !(flags & REPO_NO_INTERNALIZE))
461 repodata_internalize(data);
462 else if (!data && !(flags & REPO_NO_INTERNALIZE))
463 repo_internalize(repo);