4 * Parses 'content' file into .solv
5 * A 'content' file is the repomd.xml of the susetags format
7 * See http://en.opensuse.org/Standards/YaST2_Repository_Metadata/content for a description
11 * Copyright (c) 2007, Novell Inc.
13 * This program is licensed under the BSD license, read LICENSE.BSD
14 * for further information
17 #include <sys/types.h>
29 #include "repo_content.h"
32 #include "tools_util.h"
34 /* split off a word, return null terminated pointer to it.
35 * return NULL if there is no word left. */
41 while (*l == ' ' || *l == '\t')
44 while (*l && *l != ' ' && *l != '\t')
47 *l++ = 0; /* terminate word */
48 while (*l == ' ' || *l == '\t')
49 l++; /* convenience: advance to next word */
64 * dependency relations
67 static char *flagtab[] = {
78 * join up to three strings into one
82 join(struct parsedata *pd, const char *s1, const char *s2, const char *s3)
96 pd->tmp = solv_realloc(pd->tmp, pd->tmpl);
120 * add dependency to pool
121 * OBSOLETES product:SUSE_LINUX product:openSUSE < 11.0 package:openSUSE < 11.0
125 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker)
130 while ((name = splitword(&line)) != 0)
132 /* Hack, as the content file adds 'package:' for package
133 dependencies sometimes. */
134 if (!strncmp (name, "package:", 8))
136 id = pool_str2id(pool, name, 1);
137 if (*line == '<' || *line == '>' || *line == '=') /* rel follows */
139 char *rel = splitword(&line);
140 char *evr = splitword(&line);
145 pool_debug(pool, SOLV_FATAL, "repo_content: bad relation '%s %s'\n", name, rel);
148 for (flags = 0; flags < 6; flags++)
149 if (!strcmp(rel, flagtab[flags]))
153 pool_debug(pool, SOLV_FATAL, "repo_content: unknown relation '%s'\n", rel);
156 id = pool_rel2id(pool, id, pool_str2id(pool, evr, 1), flags + 1, 1);
158 olddeps = repo_addid_dep(pd->repo, olddeps, id, marker);
165 * split value and add to pool
169 add_multiple_strings(Repodata *data, Id handle, Id name, char *value)
173 while ((str = splitword(&value)) != 0)
174 repodata_add_poolstr_array(data, handle, name, str);
178 * split value and add to pool
182 add_multiple_urls(Repodata *data, Id handle, char *value, Id type)
186 while ((url = splitword(&value)) != 0)
188 repodata_add_poolstr_array(data, handle, PRODUCT_URL, url);
189 repodata_add_idarray(data, handle, PRODUCT_URL_TYPE, type);
196 * add 'content' to repo
201 repo_add_content(Repo *repo, FILE *fp, int flags)
203 Pool *pool = repo->pool;
210 int contentstyle = 0;
219 we use the first architecture in BASEARCHS or noarch
220 for the product. At the end we create (clone) the product
221 for each one of the remaining architectures
224 unsigned int numotherarchs = 0;
227 memset(&pd, 0, sizeof(pd));
228 line = solv_malloc(1024);
235 data = repo_add_repodata(repo, flags);
241 /* read line into big-enough buffer */
242 if (linep - line + 16 > aline)
244 aline = linep - line;
245 line = solv_realloc(line, aline + 512);
246 linep = line + aline;
249 if (!fgets(linep, aline - (linep - line), fp))
251 linep += strlen(linep);
252 if (linep == line || linep[-1] != '\n')
254 while ( --linep > line && ( linep[-1] == ' ' || linep[-1] == '\t' ) )
255 ; /* skip trailing ws */
259 /* expect "key value" lines */
261 key = splitword(&value);
266 fprintf (stderr, "key %s, value %s\n", key, value);
269 #define istag(x) (!strcmp (key, x))
270 #define code10 (contentstyle == 10)
271 #define code11 (contentstyle == 11)
274 if (istag ("CONTENTSTYLE"))
277 pool_debug(pool, SOLV_ERROR, "repo_content: 'CONTENTSTYLE' must be first line of 'content'\n");
278 contentstyle = atoi(value);
284 /* repository tags */
285 /* we also replicate some of them into the product solvables
286 * to be backward compatible */
288 if (istag ("REPOID"))
290 repodata_add_poolstr_array(data, SOLVID_META, REPOSITORY_REPOID, value);
293 if (istag ("REPOKEYWORDS"))
295 add_multiple_strings(data, SOLVID_META, REPOSITORY_KEYWORDS, value);
298 if (istag ("DISTRO"))
300 Id dh = repodata_new_handle(data);
302 /* like with createrepo --distro */
303 if ((p = strchr(value, ',')) != 0)
307 repodata_set_poolstr(data, dh, REPOSITORY_PRODUCT_CPEID, value);
312 repodata_set_str(data, dh, REPOSITORY_PRODUCT_LABEL, p);
313 repodata_add_flexarray(data, SOLVID_META, REPOSITORY_DISTROS, dh);
317 if (istag ("DESCRDIR"))
322 repodata_set_str(data, SOLVID_META, SUSETAGS_DESCRDIR, value);
324 repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, value);
325 descrdir = solv_strdup(value);
328 if (istag ("DATADIR"))
333 repodata_set_str(data, SOLVID_META, SUSETAGS_DATADIR, value);
335 repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, value);
336 datadir = solv_strdup(value);
339 if (istag ("VENDOR"))
344 repodata_set_poolstr(data, SOLVID_META, SUSETAGS_DEFAULTVENDOR, value);
346 s->vendor = pool_str2id(pool, value, 1);
347 defvendor = solv_strdup(value);
351 if (istag ("META") || istag ("HASH") || istag ("KEY"))
353 char *checksumtype, *checksum;
357 if ((checksumtype = splitword(&value)) == 0)
359 if ((checksum = splitword(&value)) == 0)
363 type = solv_chksum_str2type(checksumtype);
366 pool_error(pool, -1, "%s: unknown checksum type '%s'", value, checksumtype);
370 l = solv_chksum_len(type);
371 if (strlen(checksum) != 2 * l)
373 pool_error(pool, -1, "%s: invalid checksum length for %s", value, checksumtype);
377 fh = repodata_new_handle(data);
378 repodata_set_poolstr(data, fh, SUSETAGS_FILE_TYPE, key);
379 repodata_set_str(data, fh, SUSETAGS_FILE_NAME, value);
380 repodata_set_checksum(data, fh, SUSETAGS_FILE_CHECKSUM, type, checksum);
381 repodata_add_flexarray(data, SOLVID_META, SUSETAGS_FILE, fh);
387 if ((code10 && istag ("PRODUCT"))
388 || (code11 && istag ("NAME")))
392 /* this solvable was created without seeing a
393 PRODUCT entry, just set the name and continue */
394 s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
399 /* finish old solvable */
401 s->arch = ARCH_NOARCH;
404 if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
405 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
407 s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0);
409 /* create new solvable */
410 s = pool_id2solvable(pool, repo_add_solvable(repo));
411 repodata_extend(data, s - pool->solvables);
412 handle = s - pool->solvables;
413 s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
415 repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, datadir);
417 repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, descrdir);
419 s->vendor = pool_str2id(pool, defvendor, 1);
423 /* Sometimes PRODUCT/NAME is not the first entry, but we need a solvable
427 s = pool_id2solvable(pool, repo_add_solvable(repo));
428 repodata_extend(data, s - pool->solvables);
429 handle = s - pool->solvables;
432 if (istag ("VERSION"))
433 pd.tmpvers = solv_strdup(value);
434 else if (istag ("RELEASE"))
435 pd.tmprel = solv_strdup(value);
436 else if (code11 && istag ("DISTRIBUTION"))
437 repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_DISTRIBUTION, value);
438 else if (istag ("UPDATEURLS"))
439 add_multiple_urls(data, handle, value, pool_str2id(pool, "update", 1));
440 else if (istag ("EXTRAURLS"))
441 add_multiple_urls(data, handle, value, pool_str2id(pool, "extra", 1));
442 else if (istag ("OPTIONALURLS"))
443 add_multiple_urls(data, handle, value, pool_str2id(pool, "optional", 1));
444 else if (istag ("RELNOTESURL"))
445 add_multiple_urls(data, handle, value, pool_str2id(pool, "releasenotes", 1));
446 else if (istag ("SHORTLABEL"))
447 repodata_set_str(data, s - pool->solvables, PRODUCT_SHORTLABEL, value);
448 else if (istag ("LABEL")) /* LABEL is the products SUMMARY. */
449 repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, value);
450 else if (!strncmp (key, "LABEL.", 6))
451 repodata_set_str(data, s - pool->solvables, pool_id2langid(pool, SOLVABLE_SUMMARY, key + 6, 1), value);
452 else if (istag ("FLAGS"))
453 add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
454 else if (istag ("VENDOR")) /* actually already handled above */
455 s->vendor = pool_str2id(pool, value, 1);
456 else if (istag ("BASEARCHS"))
460 if ((arch = splitword(&value)) != 0)
462 s->arch = pool_str2id(pool, arch, 1);
463 while ((arch = splitword(&value)) != 0)
465 otherarchs = solv_extend(otherarchs, numotherarchs, 1, sizeof(Id), 7);
466 otherarchs[numotherarchs++] = pool_str2id(pool, arch, 1);
474 * Every tag below is Code10 only
479 /* Theoretically we want to have the best arch of the given
480 modifiers which still is compatible with the system
481 arch. We don't know the latter here, though. */
482 s->arch = ARCH_NOARCH;
483 else if (istag ("PREREQUIRES"))
484 s->requires = adddep(pool, &pd, s->requires, value, SOLVABLE_PREREQMARKER);
485 else if (istag ("REQUIRES"))
486 s->requires = adddep(pool, &pd, s->requires, value, -SOLVABLE_PREREQMARKER);
487 else if (istag ("PROVIDES"))
488 s->provides = adddep(pool, &pd, s->provides, value, 0);
489 else if (istag ("CONFLICTS"))
490 s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
491 else if (istag ("OBSOLETES"))
492 s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
493 else if (istag ("RECOMMENDS"))
494 s->recommends = adddep(pool, &pd, s->recommends, value, 0);
495 else if (istag ("SUGGESTS"))
496 s->suggests = adddep(pool, &pd, s->suggests, value, 0);
497 else if (istag ("SUPPLEMENTS"))
498 s->supplements = adddep(pool, &pd, s->supplements, value, 0);
499 else if (istag ("ENHANCES"))
500 s->enhances = adddep(pool, &pd, s->enhances, value, 0);
501 /* FRESHENS doesn't seem to exist. */
502 else if (istag ("TYPE"))
503 repodata_set_str(data, s - pool->solvables, PRODUCT_TYPE, value);
505 /* XXX do something about LINGUAS and ARCH?
506 * <ma>: Don't think so. zypp does not use or propagate them.
511 pool_debug(pool, SOLV_ERROR, "repo_content: malformed line: %s\n", line);
523 pool_debug(pool, SOLV_FATAL, "repo_content: 'content' incomplete, no product solvable created!\n");
524 repo_free_solvable(repo, s - pool->solvables, 1);
530 s->evr = makeevr(pool, join(&pd, pd.tmpvers, "-", pd.tmprel));
532 s->evr = makeevr(pool, pd.tmpvers);
533 pd.tmpvers = solv_free((void *)pd.tmpvers);
534 pd.tmprel = solv_free((void *)pd.tmprel);
537 s->arch = ARCH_NOARCH;
540 if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
541 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
543 s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0);
545 /* now for every other arch, clone the product except the architecture */
546 for (i = 0; i < numotherarchs; ++i)
548 Solvable *p = pool_id2solvable(pool, repo_add_solvable(repo));
549 repodata_extend(data, p - pool->solvables);
552 p->vendor = s->vendor;
553 p->arch = otherarchs[i];
556 if (s->name && p->arch != ARCH_SRC && p->arch != ARCH_NOSRC)
557 p->provides = repo_addid_dep(repo, p->provides, pool_rel2id(pool, p->name, p->evr, REL_EQ, 1), 0);
559 /* now merge the attributes */
560 repodata_merge_attrs(data, p - pool->solvables, s - pool->solvables);
567 solv_free(otherarchs);
568 if (!(flags & REPO_NO_INTERNALIZE))
569 repodata_internalize(data);