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>
27 #include "repo_content.h"
30 #include "tools_util.h"
32 /* split off a word, return null terminated pointer to it.
33 * return NULL if there is no word left. */
39 while (*l == ' ' || *l == '\t')
42 while (*l && *l != ' ' && *l != '\t')
45 *l++ = 0; /* terminate word */
46 while (*l == ' ' || *l == '\t')
47 l++; /* convenience: advance to next word */
62 * dependency relations
65 static char *flagtab[] = {
76 * join up to three strings into one
80 join(struct parsedata *pd, const char *s1, const char *s2, const char *s3)
94 pd->tmp = solv_realloc(pd->tmp, pd->tmpl);
118 * add dependency to pool
119 * OBSOLETES product:SUSE_LINUX product:openSUSE < 11.0 package:openSUSE < 11.0
123 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker)
128 while ((name = splitword(&line)) != 0)
130 /* Hack, as the content file adds 'package:' for package
131 dependencies sometimes. */
132 if (!strncmp (name, "package:", 8))
134 id = pool_str2id(pool, name, 1);
135 if (*line == '<' || *line == '>' || *line == '=') /* rel follows */
137 char *rel = splitword(&line);
138 char *evr = splitword(&line);
143 pool_debug(pool, SOLV_ERROR, "repo_content: bad relation '%s %s'\n", name, rel);
146 for (flags = 0; flags < 6; flags++)
147 if (!strcmp(rel, flagtab[flags]))
151 pool_debug(pool, SOLV_ERROR, "repo_content: unknown relation '%s'\n", rel);
154 id = pool_rel2id(pool, id, pool_str2id(pool, evr, 1), flags + 1, 1);
156 olddeps = repo_addid_dep(pd->repo, olddeps, id, marker);
163 * split value and add to pool
167 add_multiple_strings(Repodata *data, Id handle, Id name, char *value)
171 while ((str = splitword(&value)) != 0)
172 repodata_add_poolstr_array(data, handle, name, str);
176 * split value and add to pool
180 add_multiple_urls(Repodata *data, Id handle, char *value, Id type)
184 while ((url = splitword(&value)) != 0)
186 repodata_add_poolstr_array(data, handle, PRODUCT_URL, url);
187 repodata_add_idarray(data, handle, PRODUCT_URL_TYPE, type);
194 * add 'content' to repo
199 repo_add_content(Repo *repo, FILE *fp, int flags)
201 Pool *pool = repo->pool;
208 int contentstyle = 0;
217 we use the first architecture in BASEARCHS or noarch
218 for the product. At the end we create (clone) the product
219 for each one of the remaining architectures
222 unsigned int numotherarchs = 0;
225 memset(&pd, 0, sizeof(pd));
226 line = solv_malloc(1024);
233 data = repo_add_repodata(repo, flags);
239 /* read line into big-enough buffer */
240 if (linep - line + 16 > aline)
242 aline = linep - line;
243 line = solv_realloc(line, aline + 512);
244 linep = line + aline;
247 if (!fgets(linep, aline - (linep - line), fp))
249 linep += strlen(linep);
250 if (linep == line || linep[-1] != '\n')
252 while ( --linep > line && ( linep[-1] == ' ' || linep[-1] == '\t' ) )
253 ; /* skip trailing ws */
257 /* expect "key value" lines */
259 key = splitword(&value);
264 fprintf (stderr, "key %s, value %s\n", key, value);
267 #define istag(x) (!strcmp (key, x))
268 #define code10 (contentstyle == 10)
269 #define code11 (contentstyle == 11)
272 if (istag ("CONTENTSTYLE"))
275 pool_debug(pool, SOLV_ERROR, "repo_content: 'CONTENTSTYLE' must be first line of 'content'\n");
276 contentstyle = atoi(value);
282 /* repository tags */
283 /* we also replicate some of them into the product solvables
284 * to be backward compatible */
286 if (istag ("REPOID"))
288 repodata_add_poolstr_array(data, SOLVID_META, REPOSITORY_REPOID, value);
291 if (istag ("REPOKEYWORDS"))
293 add_multiple_strings(data, SOLVID_META, REPOSITORY_KEYWORDS, value);
296 if (istag ("DISTRO"))
298 Id dh = repodata_new_handle(data);
300 /* like with createrepo --distro */
301 if ((p = strchr(value, ',')) != 0)
305 repodata_set_poolstr(data, dh, REPOSITORY_PRODUCT_CPEID, value);
310 repodata_set_str(data, dh, REPOSITORY_PRODUCT_LABEL, p);
311 repodata_add_flexarray(data, SOLVID_META, REPOSITORY_DISTROS, dh);
315 if (istag ("DESCRDIR"))
320 repodata_set_str(data, SOLVID_META, SUSETAGS_DESCRDIR, value);
322 repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, value);
323 descrdir = solv_strdup(value);
326 if (istag ("DATADIR"))
331 repodata_set_str(data, SOLVID_META, SUSETAGS_DATADIR, value);
333 repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, value);
334 datadir = solv_strdup(value);
337 if (istag ("VENDOR"))
342 repodata_set_poolstr(data, SOLVID_META, SUSETAGS_DEFAULTVENDOR, value);
344 s->vendor = pool_str2id(pool, value, 1);
345 defvendor = solv_strdup(value);
349 if (istag ("META") || istag ("HASH") || istag ("KEY"))
351 char *checksumtype, *checksum;
355 if ((checksumtype = splitword(&value)) == 0)
357 if ((checksum = splitword(&value)) == 0)
361 type = solv_chksum_str2type(checksumtype);
364 pool_error(pool, -1, "%s: unknown checksum type '%s'", value, checksumtype);
368 l = solv_chksum_len(type);
369 if (strlen(checksum) != 2 * l)
371 pool_error(pool, -1, "%s: invalid checksum length for %s", value, checksumtype);
375 fh = repodata_new_handle(data);
376 repodata_set_poolstr(data, fh, SUSETAGS_FILE_TYPE, key);
377 repodata_set_str(data, fh, SUSETAGS_FILE_NAME, value);
378 repodata_set_checksum(data, fh, SUSETAGS_FILE_CHECKSUM, type, checksum);
379 repodata_add_flexarray(data, SOLVID_META, SUSETAGS_FILE, fh);
385 if ((code10 && istag ("PRODUCT"))
386 || (code11 && istag ("NAME")))
390 /* this solvable was created without seeing a
391 PRODUCT entry, just set the name and continue */
392 s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
397 /* finish old solvable */
399 s->arch = ARCH_NOARCH;
402 if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
403 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
405 repo_rewrite_suse_deps(s, 0);
407 /* create new solvable */
408 s = pool_id2solvable(pool, repo_add_solvable(repo));
409 handle = s - pool->solvables;
410 s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
412 repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, datadir);
414 repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, descrdir);
416 s->vendor = pool_str2id(pool, defvendor, 1);
420 /* Sometimes PRODUCT/NAME is not the first entry, but we need a solvable
424 s = pool_id2solvable(pool, repo_add_solvable(repo));
425 handle = s - pool->solvables;
428 if (istag ("VERSION"))
429 pd.tmpvers = solv_strdup(value);
430 else if (istag ("RELEASE"))
431 pd.tmprel = solv_strdup(value);
432 else if (code11 && istag ("DISTRIBUTION"))
433 repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_DISTRIBUTION, value);
434 else if (istag ("UPDATEURLS"))
435 add_multiple_urls(data, handle, value, pool_str2id(pool, "update", 1));
436 else if (istag ("EXTRAURLS"))
437 add_multiple_urls(data, handle, value, pool_str2id(pool, "extra", 1));
438 else if (istag ("OPTIONALURLS"))
439 add_multiple_urls(data, handle, value, pool_str2id(pool, "optional", 1));
440 else if (istag ("RELNOTESURL"))
441 add_multiple_urls(data, handle, value, pool_str2id(pool, "releasenotes", 1));
442 else if (istag ("SHORTLABEL"))
443 repodata_set_str(data, s - pool->solvables, PRODUCT_SHORTLABEL, value);
444 else if (istag ("LABEL")) /* LABEL is the products SUMMARY. */
445 repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, value);
446 else if (!strncmp (key, "LABEL.", 6))
447 repodata_set_str(data, s - pool->solvables, pool_id2langid(pool, SOLVABLE_SUMMARY, key + 6, 1), value);
448 else if (istag ("FLAGS"))
449 add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
450 else if (istag ("VENDOR")) /* actually already handled above */
451 s->vendor = pool_str2id(pool, value, 1);
452 else if (istag ("BASEARCHS"))
456 if ((arch = splitword(&value)) != 0)
458 s->arch = pool_str2id(pool, arch, 1);
459 while ((arch = splitword(&value)) != 0)
461 otherarchs = solv_extend(otherarchs, numotherarchs, 1, sizeof(Id), 7);
462 otherarchs[numotherarchs++] = pool_str2id(pool, arch, 1);
470 * Every tag below is Code10 only
475 /* Theoretically we want to have the best arch of the given
476 modifiers which still is compatible with the system
477 arch. We don't know the latter here, though. */
478 s->arch = ARCH_NOARCH;
479 else if (istag ("PREREQUIRES"))
480 s->requires = adddep(pool, &pd, s->requires, value, SOLVABLE_PREREQMARKER);
481 else if (istag ("REQUIRES"))
482 s->requires = adddep(pool, &pd, s->requires, value, -SOLVABLE_PREREQMARKER);
483 else if (istag ("PROVIDES"))
484 s->provides = adddep(pool, &pd, s->provides, value, 0);
485 else if (istag ("CONFLICTS"))
486 s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
487 else if (istag ("OBSOLETES"))
488 s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
489 else if (istag ("RECOMMENDS"))
490 s->recommends = adddep(pool, &pd, s->recommends, value, 0);
491 else if (istag ("SUGGESTS"))
492 s->suggests = adddep(pool, &pd, s->suggests, value, 0);
493 else if (istag ("SUPPLEMENTS"))
494 s->supplements = adddep(pool, &pd, s->supplements, value, 0);
495 else if (istag ("ENHANCES"))
496 s->enhances = adddep(pool, &pd, s->enhances, value, 0);
497 /* FRESHENS doesn't seem to exist. */
498 else if (istag ("TYPE"))
499 repodata_set_str(data, s - pool->solvables, PRODUCT_TYPE, value);
501 /* XXX do something about LINGUAS and ARCH?
502 * <ma>: Don't think so. zypp does not use or propagate them.
507 pool_debug(pool, SOLV_ERROR, "repo_content: malformed line: %s\n", line);
519 pool_debug(pool, SOLV_ERROR, "repo_content: 'content' incomplete, no product solvable created!\n");
520 repo_free_solvable(repo, s - pool->solvables, 1);
526 s->evr = makeevr(pool, join(&pd, pd.tmpvers, "-", pd.tmprel));
528 s->evr = makeevr(pool, pd.tmpvers);
529 pd.tmpvers = solv_free((void *)pd.tmpvers);
530 pd.tmprel = solv_free((void *)pd.tmprel);
533 s->arch = ARCH_NOARCH;
536 if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
537 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
539 repo_rewrite_suse_deps(s, 0);
541 /* now for every other arch, clone the product except the architecture */
542 for (i = 0; i < numotherarchs; ++i)
544 Solvable *p = pool_id2solvable(pool, repo_add_solvable(repo));
547 p->vendor = s->vendor;
548 p->arch = otherarchs[i];
551 if (s->name && p->arch != ARCH_SRC && p->arch != ARCH_NOSRC)
552 p->provides = repo_addid_dep(repo, p->provides, pool_rel2id(pool, p->name, p->evr, REL_EQ, 1), 0);
554 /* now merge the attributes */
555 repodata_merge_attrs(data, p - pool->solvables, s - pool->solvables);
562 solv_free(otherarchs);
563 if (!(flags & REPO_NO_INTERNALIZE))
564 repodata_internalize(data);