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);
86 repo_add_autopattern(Repo *repo, int flags)
88 Pool *pool = repo->pool;
94 Id pattern_id, product_id;
95 Id autopattern_id = 0, autoproduct_id = 0;
103 if (repo == pool->installed)
104 flags |= ADD_NO_AUTOPRODUCTS; /* no auto products for installed repos */
106 pattern_id = pool_str2id(pool, "pattern()", 9);
107 product_id = pool_str2id(pool, "product()", 9);
108 FOR_REPO_SOLVABLES(repo, p, s)
110 const char *n = pool_id2str(pool, s->name);
113 if (!strncmp("pattern:", n, 8))
115 queue_push(&patq, p);
118 else if (!strncmp("product:", n, 8))
120 queue_push(&prdq, p);
126 Id prv, *prvp = repo->idarraydata + s->provides;
127 while ((prv = *prvp++) != 0) /* go through all provides */
130 Reldep *rd = GETRELDEP(pool, prv);
131 if (rd->flags != REL_EQ)
133 if (rd->name == pattern_id)
135 const char *evrstr = pool_id2str(pool, rd->evr);
136 if (evrstr[0] == '.') /* hack to allow provides that do not create a pattern */
138 if (patq2.count && patq2.elements[patq2.count - 2] == p)
140 /* hmm, two provides. choose by evrstr */
141 if (strcmp(evrstr, pool_id2str(pool, patq2.elements[patq2.count - 1])) >= 0)
145 queue_push2(&patq2, p, rd->evr);
147 if (rd->name == product_id)
149 const char *evrstr = pool_id2str(pool, rd->evr);
150 if (prdq2.count && prdq2.elements[prdq2.count - 2] == p)
152 /* hmm, two provides. choose by evrstr */
153 if (strcmp(evrstr, pool_id2str(pool, prdq2.elements[prdq2.count - 1])) >= 0)
157 queue_push2(&prdq2, p, rd->evr);
162 for (i = 0; i < patq2.count; i += 2)
168 unsigned long long num;
170 s = pool->solvables + patq2.elements[i];
171 /* construct new name */
172 newname = pool_tmpjoin(pool, "pattern:", pool_id2str(pool, patq2.elements[i + 1]), 0);
174 name = pool_str2id(pool, newname, 0);
177 /* check if we already have that pattern */
178 for (j = 0; j < patq.count; j++)
180 s2 = pool->solvables + patq.elements[j];
181 if (s2->name == name && s2->arch == s->arch && s2->evr == s->evr)
185 continue; /* yes, do not add again */
189 name = pool_str2id(pool, newname, 1);
192 repo_internalize(repo); /* to make that the lookups work */
193 data = repo_add_repodata(repo, flags);
195 s2 = pool_id2solvable(pool, repo_add_solvable(repo));
196 s = pool->solvables + patq2.elements[i]; /* re-calc pointer */
200 s2->vendor = s->vendor;
201 /* add link requires */
202 s2->requires = repo_addid_dep(repo, s2->requires, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1) , 0);
203 /* add autopattern provides */
205 autopattern_id = pool_str2id(pool, "autopattern()", 1);
206 s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autopattern_id, s->name, REL_EQ, 1), 0);
207 /* add self provides */
208 s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
209 if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
210 repodata_set_num(data, s2 - pool->solvables, SOLVABLE_INSTALLTIME, num);
211 if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
212 repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
213 if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
214 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
215 if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
216 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
217 /* fill in stuff from provides */
218 prvp = repo->idarraydata + s->provides;
219 while ((prv = *prvp++) != 0) /* go through all provides */
224 Reldep *rd = GETRELDEP(pool, prv);
225 if (rd->flags != REL_EQ)
230 pn = pool_id2str(pool, prv);
231 if (strncmp("pattern-", pn, 8) != 0)
236 newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
239 if (!strncmp(pn, "pattern-category(", 17) && evr)
244 if (l > 17 + 9 || pn[l - 1] != ')')
246 strncpy(lang, pn + 17, l - 17 - 1);
247 lang[l - 17 - 1] = 0;
248 langtag = SOLVABLE_CATEGORY;
249 if (*lang && strcmp(lang, "en") != 0)
250 langtag = pool_id2langid(pool, SOLVABLE_CATEGORY, lang, 1);
251 if (newname[solv_validutf8(newname)] == 0)
252 repodata_set_str(data, s2 - pool->solvables, langtag, newname);
255 char *ustr = solv_latin1toutf8(newname);
256 repodata_set_str(data, s2 - pool->solvables, langtag, ustr);
260 else if (!strcmp(pn, "pattern-includes()") && evr)
261 repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_INCLUDES, pool_tmpjoin(pool, "pattern:", newname, 0));
262 else if (!strcmp(pn, "pattern-extends()") && evr)
263 repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_EXTENDS, pool_tmpjoin(pool, "pattern:", newname, 0));
264 else if (!strcmp(pn, "pattern-icon()") && evr)
265 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ICON, newname);
266 else if (!strcmp(pn, "pattern-order()") && evr)
267 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ORDER, newname);
268 else if (!strcmp(pn, "pattern-visible()"))
271 repodata_set_void(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE);
273 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE, newname);
280 if ((flags & ADD_NO_AUTOPRODUCTS) != 0)
283 for (i = 0; i < prdq2.count; i += 2)
287 Id name, evr = 0, prv, *prvp;
289 unsigned long long num;
291 s = pool->solvables + prdq2.elements[i];
292 /* construct new name */
293 newname = pool_tmpjoin(pool, "product(", pool_id2str(pool, prdq2.elements[i + 1]), ")");
295 name = pool_str2id(pool, newname, 0);
297 continue; /* must have it in provides! */
298 prvp = repo->idarraydata + s->provides;
299 while ((prv = *prvp++) != 0) /* go through all provides */
303 Reldep *rd = GETRELDEP(pool, prv);
304 if (rd->name == name && rd->flags == REL_EQ)
312 continue; /* not found in provides */
313 newname = pool_tmpjoin(pool, "product:", pool_id2str(pool, prdq2.elements[i + 1]), 0);
315 name = pool_str2id(pool, newname, 0);
318 /* check if we already have that product */
319 for (j = 0; j < prdq.count; j++)
321 s2 = pool->solvables + prdq.elements[j];
322 if (s2->name == name && s2->arch == s->arch && s2->evr == evr)
326 continue; /* yes, do not add again */
330 name = pool_str2id(pool, newname, 1);
333 repo_internalize(repo); /* to make that the lookups work */
334 data = repo_add_repodata(repo, flags);
336 if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
337 continue; /* eek, not for installed packages, please! */
338 s2 = pool_id2solvable(pool, repo_add_solvable(repo));
339 s = pool->solvables + prdq2.elements[i]; /* re-calc pointer */
343 s2->vendor = s->vendor;
344 /* add link requires */
345 s2->requires = repo_addid_dep(repo, s2->requires, prv, 0);
347 autoproduct_id = pool_str2id(pool, "autoproduct()", 1);
348 s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autoproduct_id, s->name, REL_EQ, 1), 0);
349 /* add self provides */
350 s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
351 if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
352 repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
353 if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
354 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
355 if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
356 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
357 if ((str = solvable_lookup_str(s, SOLVABLE_DISTRIBUTION)) != 0)
358 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DISTRIBUTION, str);
359 /* fill in stuff from provides */
360 prvp = repo->idarraydata + s->provides;
361 while ((prv = *prvp++) != 0) /* go through all provides */
366 Reldep *rd = GETRELDEP(pool, prv);
367 if (rd->flags != REL_EQ)
372 pn = pool_id2str(pool, prv);
373 if (strncmp("product-", pn, 8) != 0)
378 newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
381 if (!strcmp(pn, "product-label()") && evr)
382 repodata_set_str(data, s2 - pool->solvables, PRODUCT_SHORTLABEL, newname);
383 else if (!strcmp(pn, "product-register-target()") && evr)
384 repodata_set_str(data, s2 - pool->solvables, PRODUCT_REGISTER_TARGET, newname);
385 else if (!strcmp(pn, "product-register-flavor()") && evr)
386 repodata_set_str(data, s2 - pool->solvables, PRODUCT_REGISTER_FLAVOR, newname);
387 else if (!strcmp(pn, "product-type()") && evr)
388 repodata_set_str(data, s2 - pool->solvables, PRODUCT_TYPE, newname);
389 else if (!strcmp(pn, "product-cpeid()") && evr)
390 repodata_set_str(data, s2 - pool->solvables, SOLVABLE_CPEID, newname);
391 else if (!strcmp(pn, "product-flags()") && evr)
392 repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_FLAGS, newname);
393 else if (!strcmp(pn, "product-updates-repoid()") && evr)
395 Id h = repodata_new_handle(data);
396 repodata_set_str(data, h, PRODUCT_UPDATES_REPOID, newname);
397 repodata_add_flexarray(data, s2 - pool->solvables, PRODUCT_UPDATES, h);
399 else if (!strcmp(pn, "product-endoflife()"))
401 /* FATE#320699: Support tri-state product-endoflife (tag absent, present but nodate(0), present + date) */
402 repodata_set_num(data, s2 - pool->solvables, PRODUCT_ENDOFLIFE,(evr ? datestr2timestamp(newname) : 0) );
404 else if (!strncmp(pn, "product-url(", 12) && evr && pn[12] && pn[13] && strlen(pn + 12) < 32)
407 strcpy(type, pn + 12);
408 type[strlen(type) - 1] = 0; /* closing ) */
409 repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL_TYPE, type);
410 repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL, newname);
417 if (data && !(flags & REPO_NO_INTERNALIZE))
418 repodata_internalize(data);
419 else if (!data && !(flags & REPO_NO_INTERNALIZE))
420 repo_internalize(repo);