- add susetags:defaultvendor support
[platform/upstream/libsolv.git] / ext / repo_content.c
1 /*
2  * repo_content.c
3  *
4  * Parses 'content' file into .solv
5  * See http://en.opensuse.org/Standards/YaST2_Repository_Metadata/content for a description
6  * of the syntax
7  *
8  *
9  * Copyright (c) 2007, Novell Inc.
10  *
11  * This program is licensed under the BSD license, read LICENSE.BSD
12  * for further information
13  */
14
15 #include <sys/types.h>
16 #include <limits.h>
17 #include <fcntl.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <assert.h>
22
23 #include "pool.h"
24 #include "repo.h"
25 #include "util.h"
26 #include "repo_content.h"
27 #define DISABLE_SPLIT
28 #include "tools_util.h"
29
30 /* split off a word, return null terminated pointer to it.
31  * return NULL if there is no word left. */
32 static char *
33 splitword(char **lp)
34 {
35   char *w, *l = *lp;
36
37   while (*l == ' ' || *l == '\t')
38     l++;
39   w = *l ? l : 0;
40   while (*l && *l != ' ' && *l != '\t')
41     l++;
42   if (*l)
43     *l++ = 0;           /* terminate word */
44   while (*l == ' ' || *l == '\t')
45     l++;                /* convenience: advance to next word */
46   *lp = l;
47   return w;
48 }
49
50 struct parsedata {
51   Repo *repo;
52   char *tmp;
53   int tmpl;
54
55   const char *tmpvers;
56   const char *tmprel;
57 };
58
59 /*
60  * dependency relations
61  */
62
63 static char *flagtab[] = {
64   ">",
65   "=",
66   ">=",
67   "<",
68   "!=",
69   "<="
70 };
71
72
73 /*
74  * join up to three strings into one
75  */
76
77 static char *
78 join(struct parsedata *pd, const char *s1, const char *s2, const char *s3)
79 {
80   int l = 1;
81   char *p;
82
83   if (s1)
84     l += strlen(s1);
85   if (s2)
86     l += strlen(s2);
87   if (s3)
88     l += strlen(s3);
89   if (l > pd->tmpl)
90     {
91       pd->tmpl = l + 256;
92       pd->tmp = sat_realloc(pd->tmp, pd->tmpl);
93     }
94   p = pd->tmp;
95   if (s1)
96     {
97       strcpy(p, s1);
98       p += strlen(s1);
99     }
100   if (s2)
101     {
102       strcpy(p, s2);
103       p += strlen(s2);
104     }
105   if (s3)
106     {
107       strcpy(p, s3);
108       p += strlen(s3);
109     }
110   return pd->tmp;
111 }
112
113
114 /*
115  * add dependency to pool
116  * OBSOLETES product:SUSE_LINUX product:openSUSE < 11.0 package:openSUSE < 11.0
117  */
118
119 static unsigned int
120 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker)
121 {
122   char *name;
123   Id id;
124
125   while ((name = splitword(&line)) != 0)
126     {
127       /* Hack, as the content file adds 'package:' for package
128          dependencies sometimes.  */
129       if (!strncmp (name, "package:", 8))
130         name += 8;
131       id = str2id(pool, name, 1);
132       if (*line == '<' || *line == '>' || *line == '=') /* rel follows */
133         {
134           char *rel = splitword(&line);
135           char *evr = splitword(&line);
136           int flags;
137
138           if (!rel || !evr)
139             {
140               pool_debug(pool, SAT_FATAL, "repo_content: bad relation '%s %s'\n", name, rel);
141               exit(1);
142             }
143           for (flags = 0; flags < 6; flags++)
144             if (!strcmp(rel, flagtab[flags]))
145               break;
146           if (flags == 6)
147             {
148               pool_debug(pool, SAT_FATAL, "repo_content: unknown relation '%s'\n", rel);
149               exit(1);
150             }
151           id = rel2id(pool, id, str2id(pool, evr, 1), flags + 1, 1);
152         }
153       olddeps = repo_addid_dep(pd->repo, olddeps, id, marker);
154     }
155   return olddeps;
156 }
157
158
159 /*
160  * split value and add to pool
161  */
162
163 static void
164 add_multiple_strings(Repodata *data, Id handle, Id name, char *value)
165 {
166   char *str;
167
168   while ((str = splitword(&value)) != 0)
169     repodata_add_poolstr_array(data, handle, name, str);
170 }
171
172 /*
173  * split value and add to pool
174  */
175
176 static void
177 add_multiple_urls(Repodata *data, Id handle, char *value, Id type)
178 {
179   char *url;
180
181   while ((url = splitword(&value)) != 0)
182     {
183       repodata_add_poolstr_array(data, handle, PRODUCT_URL, url);
184       repodata_add_idarray(data, handle, PRODUCT_URL_TYPE, type);
185     }
186 }
187
188
189
190 /*
191  * add 'content' to repo
192  *
193  */
194
195 void
196 repo_add_content(Repo *repo, FILE *fp, int flags)
197 {
198   Pool *pool = repo->pool;
199   char *line, *linep;
200   int aline;
201   Solvable *s;
202   struct parsedata pd;
203   Repodata *data;
204   Id handle = 0;
205   int contentstyle = 0;
206   char *descrdir = 0;
207   char *datadir = 0;
208   char *defvendor = 0;
209
210   int i = 0;
211
212   /* architectures
213      we use the first architecture in BASEARCHS or noarch
214      for the product. At the end we create (clone) the product
215      for each one of the remaining architectures
216      we allow max 4 archs
217   */
218   unsigned int numotherarchs = 0;
219   Id *otherarchs = 0;
220
221   if (!(flags & REPO_REUSE_REPODATA))
222     data = repo_add_repodata(repo, 0);
223   else
224     data = repo_last_repodata(repo);
225
226   memset(&pd, 0, sizeof(pd));
227   line = sat_malloc(1024);
228   aline = 1024;
229
230   if (repo->nrepodata)
231     /* use last repodata */
232     data = repo->repodata + repo->nrepodata - 1;
233   else
234     data = repo_add_repodata(repo, 0);
235
236   pd.repo = repo;
237   linep = line;
238   s = 0;
239
240   for (;;)
241     {
242       char *key, *value;
243
244       /* read line into big-enough buffer */
245       if (linep - line + 16 > aline)
246         {
247           aline = linep - line;
248           line = sat_realloc(line, aline + 512);
249           linep = line + aline;
250           aline += 512;
251         }
252       if (!fgets(linep, aline - (linep - line), fp))
253         break;
254       linep += strlen(linep);
255       if (linep == line || linep[-1] != '\n')
256         continue;
257       while ( --linep > line && ( linep[-1] == ' ' ||  linep[-1] == '\t' ) )
258         ; /* skip trailing ws */
259       *linep = 0;
260       linep = line;
261
262       /* expect "key value" lines */
263       value = line;
264       key = splitword(&value);
265
266       if (key)
267         {
268 #if 0
269           fprintf (stderr, "key %s, value %s\n", key, value);
270 #endif
271
272 #define istag(x) (!strcmp (key, x))
273 #define code10 (contentstyle == 10)
274 #define code11 (contentstyle == 11)
275
276
277           if (istag ("CONTENTSTYLE"))
278             {
279               if (contentstyle)
280                 pool_debug(pool, SAT_ERROR, "repo_content: 'CONTENTSTYLE' must be first line of 'content'\n");
281               contentstyle = atoi(value);
282               continue;
283             }
284           if (!contentstyle)
285             contentstyle = 10;
286
287           /* repository tags */
288           /* we also replicate some of them into the product solvables
289            * to be backward compatible */
290
291           if (istag ("DESCRDIR"))
292             {
293               if (descrdir)
294                 free(descrdir);
295               else
296                 repo_set_str(repo, SOLVID_META, SUSETAGS_DESCRDIR, value);
297               if (s)
298                 repo_set_str(repo, s - pool->solvables, SUSETAGS_DESCRDIR, value);
299               descrdir = strdup(value);
300               continue;
301             }
302           if (istag ("DATADIR"))
303             {
304               if (datadir)
305                 free(datadir);
306               else
307                 repo_set_str(repo, SOLVID_META, SUSETAGS_DATADIR, value);
308               if (s)
309                 repo_set_str(repo, s - pool->solvables, SUSETAGS_DATADIR, value);
310               datadir = strdup(value);
311               continue;
312             }
313           if (istag ("VENDOR"))
314             {
315               if (defvendor)
316                 free(defvendor);
317               else
318                 repo_set_poolstr(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR, value);
319               if (s)
320                 s->vendor = str2id(pool, value, 1);
321               defvendor = strdup(value);
322               continue;
323             }
324
325           if (istag ("META") || istag ("HASH") || istag ("KEY"))
326             {
327               char *checksumtype, *checksum;
328               Id fh, type;
329               int l;
330
331               if ((checksumtype = splitword(&value)) == 0)
332                 continue;
333               if ((checksum = splitword(&value)) == 0)
334                 continue;
335               if (!*value)
336                 continue;
337               if (!strcasecmp(checksumtype, "sha") || !strcasecmp(checksumtype, "sha1"))
338                 l = SIZEOF_SHA1 * 2, type = REPOKEY_TYPE_SHA1;
339               else if (!strcasecmp(checksumtype, "sha256"))
340                 l = SIZEOF_SHA256 * 2, type = REPOKEY_TYPE_SHA256;
341               else if (!strcasecmp(checksumtype, "md5"))
342                 l = SIZEOF_MD5 * 2, type = REPOKEY_TYPE_MD5;
343               else
344                 {
345                   fprintf(stderr, "Unknown checksum type: %s: %s\n", value, checksumtype);
346                   exit(1);
347                 }
348               if (strlen(checksum) != l)
349                 {
350                   fprintf(stderr, "Invalid checksum length: %s: for %s\n", value, checksum);
351                   exit(1);
352                 }
353               fh = repodata_new_handle(data);
354               repodata_set_poolstr(data, fh, SUSETAGS_FILE_TYPE, key);
355               repodata_set_str(data, fh, SUSETAGS_FILE_NAME, value);
356               repodata_set_checksum(data, fh, SUSETAGS_FILE_CHECKSUM, type, checksum);
357               repodata_add_flexarray(data, SOLVID_META, SUSETAGS_FILE, fh);
358               continue;
359             }
360
361           /* product tags */
362
363           if ((code10 && istag ("PRODUCT"))
364               || (code11 && istag ("NAME")))
365             {
366               if (s && !s->name)
367                 {
368                   /* this solvable was created without seeing a
369                      PRODUCT entry, just set the name and continue */
370                   s->name = str2id(pool, join(&pd, "product", ":", value), 1);
371                   continue;
372                 }
373               if (s)
374                 {
375                   /* finish old solvable */
376                   if (!s->arch)
377                     s->arch = ARCH_NOARCH;
378                   if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
379                     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
380                   if (code10)
381                     s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0);
382                 }
383               /* create new solvable */
384               s = pool_id2solvable(pool, repo_add_solvable(repo));
385               repodata_extend(data, s - pool->solvables);
386               handle = s - pool->solvables;
387               s->name = str2id(pool, join(&pd, "product", ":", value), 1);
388               if (datadir)
389                 repo_set_str(repo, s - pool->solvables, SUSETAGS_DATADIR, datadir);
390               if (descrdir)
391                 repo_set_str(repo, s - pool->solvables, SUSETAGS_DESCRDIR, descrdir);
392               if (defvendor)
393                 s->vendor = str2id(pool, defvendor, 1);
394               continue;
395             }
396
397           /* Sometimes PRODUCT/NAME is not the first entry, but we need a solvable
398              from here on.  */
399           if (!s)
400             {
401               s = pool_id2solvable(pool, repo_add_solvable(repo));
402               repodata_extend(data, s - pool->solvables);
403               handle = s - pool->solvables;
404             }
405
406           if (istag ("VERSION"))
407             pd.tmpvers = strdup(value);
408           else if (istag ("RELEASE"))
409             pd.tmprel = strdup(value);
410           else if (code11 && istag ("DISTRIBUTION"))
411             repo_set_str(repo, s - pool->solvables, SOLVABLE_DISTRIBUTION, value);
412           else if (istag ("UPDATEURLS"))
413             add_multiple_urls(data, handle, value, str2id(pool, "update", 1));
414           else if (istag ("EXTRAURLS"))
415             add_multiple_urls(data, handle, value, str2id(pool, "extra", 1));
416           else if (istag ("OPTIONALURLS"))
417             add_multiple_urls(data, handle, value, str2id(pool, "optional", 1));
418           else if (istag ("RELNOTESURL"))
419             add_multiple_urls(data, handle, value, str2id(pool, "releasenotes", 1));
420           else if (istag ("SHORTLABEL"))
421             repo_set_str(repo, s - pool->solvables, PRODUCT_SHORTLABEL, value);
422           else if (istag ("LABEL")) /* LABEL is the products SUMMARY. */
423             repo_set_str(repo, s - pool->solvables, SOLVABLE_SUMMARY, value);
424           else if (!strncmp (key, "LABEL.", 6))
425             repo_set_str(repo, s - pool->solvables, pool_id2langid(pool, SOLVABLE_SUMMARY, key + 6, 1), value);
426           else if (istag ("FLAGS"))
427             add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
428           else if (istag ("VENDOR"))    /* actually already handled above */
429             s->vendor = str2id(pool, value, 1);
430           else if (istag ("BASEARCHS"))
431             {
432               char *arch;
433
434               if ((arch = splitword(&value)) != 0)
435                 {
436                   s->arch = str2id(pool, arch, 1);
437                   while ((arch = splitword(&value)) != 0)
438                     {
439                        otherarchs = sat_extend(otherarchs, numotherarchs, 1, sizeof(Id), 7);
440                        otherarchs[numotherarchs++] = str2id(pool, arch, 1);
441                     }
442                 }
443             }
444
445           /*
446            * Every tag below is Code10 only
447            *
448            */
449
450           if (code10 && istag ("DISTPRODUCT"))
451             /* DISTPRODUCT is for registration and Yast, not for the solver. */
452             repo_set_str(repo, s - pool->solvables, PRODUCT_DISTPRODUCT, value);
453           else if (code10 && istag ("DISTVERSION"))
454             /* DISTVERSION is for registration and Yast, not for the solver. */
455             repo_set_str(repo, s - pool->solvables, PRODUCT_DISTVERSION, value);
456           else if (code10 && istag ("ARCH"))
457             /* Theoretically we want to have the best arch of the given
458                modifiers which still is compatible with the system
459                arch.  We don't know the latter here, though.  */
460             s->arch = ARCH_NOARCH;
461           else if (code10 && istag ("PREREQUIRES"))
462             s->requires = adddep(pool, &pd, s->requires, value, SOLVABLE_PREREQMARKER);
463           else if (code10 && istag ("REQUIRES"))
464             s->requires = adddep(pool, &pd, s->requires, value, -SOLVABLE_PREREQMARKER);
465           else if (code10 && istag ("PROVIDES"))
466             s->provides = adddep(pool, &pd, s->provides, value, 0);
467           else if (code10 && istag ("CONFLICTS"))
468             s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
469           else if (code10 && istag ("OBSOLETES"))
470             s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
471           else if (code10 && istag ("RECOMMENDS"))
472             s->recommends = adddep(pool, &pd, s->recommends, value, 0);
473           else if (code10 && istag ("SUGGESTS"))
474             s->suggests = adddep(pool, &pd, s->suggests, value, 0);
475           else if (code10 && istag ("SUPPLEMENTS"))
476             s->supplements = adddep(pool, &pd, s->supplements, value, 0);
477           else if (code10 && istag ("ENHANCES"))
478             s->enhances = adddep(pool, &pd, s->enhances, value, 0);
479           /* FRESHENS doesn't seem to exist.  */
480           else if (code10 && istag ("TYPE"))
481             repo_set_str(repo, s - pool->solvables, PRODUCT_TYPE, value);
482
483           /* XXX do something about LINGUAS and ARCH?
484           * <ma>: Don't think so. zypp does not use or propagate them.
485           */
486 #undef istag
487         }
488       else
489         pool_debug(pool, SAT_ERROR, "repo_content: malformed line: %s\n", line);
490     }
491
492   if (datadir)
493     free(datadir);
494   if (descrdir)
495     free(descrdir);
496   if (defvendor)
497     free(defvendor);
498
499   if (!s || !s->name)
500     {
501       pool_debug(pool, SAT_FATAL, "repo_content: 'content' incomplete, no product solvable created!\n");
502       exit(1);
503     }
504
505   if (pd.tmpvers)
506     {
507       if (pd.tmprel)
508         s->evr = makeevr(pool, join2(pd.tmpvers, "-", pd.tmprel));
509       else
510         s->evr = makeevr(pool, pd.tmpvers);
511     }
512   else if (pd.tmprel)
513     {
514       s->evr = makeevr(pool, join2("", "-", pd.tmprel));
515     }
516   pd.tmpvers = sat_free((void *)pd.tmpvers);
517   pd.tmprel = sat_free((void *)pd.tmprel);
518
519   if (!s->arch)
520     s->arch = ARCH_NOARCH;
521   if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
522     {
523       s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
524       if (code10)
525         s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0);
526     }
527
528   /* now for every other arch, clone the product except the architecture */
529   for (i = 0; i < numotherarchs; ++i)
530     {
531       Solvable *p = pool_id2solvable(pool, repo_add_solvable(repo));
532       repodata_extend(data, p - pool->solvables);
533       p->name = s->name;
534       p->evr = s->evr;
535       p->vendor = s->vendor;
536       p->arch = otherarchs[i];
537
538       /* self provides */
539       if (p->arch != ARCH_SRC && p->arch != ARCH_NOSRC)
540           p->provides = repo_addid_dep(repo, p->provides, rel2id(pool, p->name, p->evr, REL_EQ, 1), 0);
541
542       /* now merge the attributes */
543       repodata_merge_attrs(data, p - pool->solvables, s - pool->solvables);
544     }
545
546   if (pd.tmp)
547     sat_free(pd.tmp);
548   sat_free(line);
549   sat_free(otherarchs);
550   join_freemem();
551   if (!(flags & REPO_NO_INTERNALIZE))
552     repodata_internalize(data);
553 }