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