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 ("DISTRO"))
295 Id dh = repodata_new_handle(data);
297 /* like with createrepo --distro */
298 if ((p = strchr(value, ',')) != 0)
302 repodata_set_poolstr(data, dh, REPOSITORY_PRODUCT_CPEID, value);
307 repodata_set_str(data, dh, REPOSITORY_PRODUCT_LABEL, p);
308 repodata_add_flexarray(data, SOLVID_META, REPOSITORY_DISTROS, dh);
312 if (istag ("DESCRDIR"))
317 repodata_set_str(data, SOLVID_META, SUSETAGS_DESCRDIR, value);
319 repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, value);
320 descrdir = solv_strdup(value);
323 if (istag ("DATADIR"))
328 repodata_set_str(data, SOLVID_META, SUSETAGS_DATADIR, value);
330 repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, value);
331 datadir = solv_strdup(value);
334 if (istag ("VENDOR"))
339 repodata_set_poolstr(data, SOLVID_META, SUSETAGS_DEFAULTVENDOR, value);
341 s->vendor = pool_str2id(pool, value, 1);
342 defvendor = solv_strdup(value);
346 if (istag ("META") || istag ("HASH") || istag ("KEY"))
348 char *checksumtype, *checksum;
352 if ((checksumtype = splitword(&value)) == 0)
354 if ((checksum = splitword(&value)) == 0)
358 type = solv_chksum_str2type(checksumtype);
361 pool_error(pool, -1, "%s: unknown checksum type '%s'", value, checksumtype);
365 l = solv_chksum_len(type);
366 if (strlen(checksum) != 2 * l)
368 pool_error(pool, -1, "%s: invalid checksum length for %s", value, checksumtype);
372 fh = repodata_new_handle(data);
373 repodata_set_poolstr(data, fh, SUSETAGS_FILE_TYPE, key);
374 repodata_set_str(data, fh, SUSETAGS_FILE_NAME, value);
375 repodata_set_checksum(data, fh, SUSETAGS_FILE_CHECKSUM, type, checksum);
376 repodata_add_flexarray(data, SOLVID_META, SUSETAGS_FILE, fh);
382 if ((code10 && istag ("PRODUCT"))
383 || (code11 && istag ("NAME")))
387 /* this solvable was created without seeing a
388 PRODUCT entry, just set the name and continue */
389 s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
394 /* finish old solvable */
396 s->arch = ARCH_NOARCH;
399 if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
400 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
402 s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0);
404 /* create new solvable */
405 s = pool_id2solvable(pool, repo_add_solvable(repo));
406 repodata_extend(data, s - pool->solvables);
407 handle = s - pool->solvables;
408 s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
410 repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, datadir);
412 repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, descrdir);
414 s->vendor = pool_str2id(pool, defvendor, 1);
418 /* Sometimes PRODUCT/NAME is not the first entry, but we need a solvable
422 s = pool_id2solvable(pool, repo_add_solvable(repo));
423 repodata_extend(data, s - pool->solvables);
424 handle = s - pool->solvables;
427 if (istag ("VERSION"))
428 pd.tmpvers = solv_strdup(value);
429 else if (istag ("RELEASE"))
430 pd.tmprel = solv_strdup(value);
431 else if (code11 && istag ("DISTRIBUTION"))
432 repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_DISTRIBUTION, value);
433 else if (istag ("UPDATEURLS"))
434 add_multiple_urls(data, handle, value, pool_str2id(pool, "update", 1));
435 else if (istag ("EXTRAURLS"))
436 add_multiple_urls(data, handle, value, pool_str2id(pool, "extra", 1));
437 else if (istag ("OPTIONALURLS"))
438 add_multiple_urls(data, handle, value, pool_str2id(pool, "optional", 1));
439 else if (istag ("RELNOTESURL"))
440 add_multiple_urls(data, handle, value, pool_str2id(pool, "releasenotes", 1));
441 else if (istag ("SHORTLABEL"))
442 repodata_set_str(data, s - pool->solvables, PRODUCT_SHORTLABEL, value);
443 else if (istag ("LABEL")) /* LABEL is the products SUMMARY. */
444 repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, value);
445 else if (!strncmp (key, "LABEL.", 6))
446 repodata_set_str(data, s - pool->solvables, pool_id2langid(pool, SOLVABLE_SUMMARY, key + 6, 1), value);
447 else if (istag ("FLAGS"))
448 add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
449 else if (istag ("VENDOR")) /* actually already handled above */
450 s->vendor = pool_str2id(pool, value, 1);
451 else if (istag ("BASEARCHS"))
455 if ((arch = splitword(&value)) != 0)
457 s->arch = pool_str2id(pool, arch, 1);
458 while ((arch = splitword(&value)) != 0)
460 otherarchs = solv_extend(otherarchs, numotherarchs, 1, sizeof(Id), 7);
461 otherarchs[numotherarchs++] = pool_str2id(pool, arch, 1);
469 * Every tag below is Code10 only
474 /* Theoretically we want to have the best arch of the given
475 modifiers which still is compatible with the system
476 arch. We don't know the latter here, though. */
477 s->arch = ARCH_NOARCH;
478 else if (istag ("PREREQUIRES"))
479 s->requires = adddep(pool, &pd, s->requires, value, SOLVABLE_PREREQMARKER);
480 else if (istag ("REQUIRES"))
481 s->requires = adddep(pool, &pd, s->requires, value, -SOLVABLE_PREREQMARKER);
482 else if (istag ("PROVIDES"))
483 s->provides = adddep(pool, &pd, s->provides, value, 0);
484 else if (istag ("CONFLICTS"))
485 s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
486 else if (istag ("OBSOLETES"))
487 s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
488 else if (istag ("RECOMMENDS"))
489 s->recommends = adddep(pool, &pd, s->recommends, value, 0);
490 else if (istag ("SUGGESTS"))
491 s->suggests = adddep(pool, &pd, s->suggests, value, 0);
492 else if (istag ("SUPPLEMENTS"))
493 s->supplements = adddep(pool, &pd, s->supplements, value, 0);
494 else if (istag ("ENHANCES"))
495 s->enhances = adddep(pool, &pd, s->enhances, value, 0);
496 /* FRESHENS doesn't seem to exist. */
497 else if (istag ("TYPE"))
498 repodata_set_str(data, s - pool->solvables, PRODUCT_TYPE, value);
500 /* XXX do something about LINGUAS and ARCH?
501 * <ma>: Don't think so. zypp does not use or propagate them.
506 pool_debug(pool, SOLV_ERROR, "repo_content: malformed line: %s\n", line);
518 pool_debug(pool, SOLV_FATAL, "repo_content: 'content' incomplete, no product solvable created!\n");
519 repo_free_solvable(repo, s - pool->solvables, 1);
525 s->evr = makeevr(pool, join(&pd, pd.tmpvers, "-", pd.tmprel));
527 s->evr = makeevr(pool, pd.tmpvers);
528 pd.tmpvers = solv_free((void *)pd.tmpvers);
529 pd.tmprel = solv_free((void *)pd.tmprel);
532 s->arch = ARCH_NOARCH;
535 if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
536 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
538 s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0);
540 /* now for every other arch, clone the product except the architecture */
541 for (i = 0; i < numotherarchs; ++i)
543 Solvable *p = pool_id2solvable(pool, repo_add_solvable(repo));
544 repodata_extend(data, p - pool->solvables);
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);