improve guessing of appdata.xml file name
[platform/upstream/libsolv.git] / ext / repo_cudf.c
1 /*
2  * Copyright (c) 2012, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <zlib.h>
15 #include <errno.h>
16
17 #include "pool.h"
18 #include "repo.h"
19 #include "util.h"
20 #include "chksum.h"
21 #include "solver.h"
22 #include "repo_cudf.h"
23
24 static Id
25 parseonedep(Pool *pool, char *p)
26 {
27   char *n, *ne, *e, *ee;
28   Id name, evr;
29   int flags;
30
31   while (*p == ' ' || *p == '\t' || *p == '\n')
32     p++;
33   if (!*p)
34     return 0;
35   if (!strcmp(p, "!true"))
36     return 0;
37   if (!strcmp(p, "!false"))
38     return pool_str2id(pool, p, 1);
39   n = p;
40   /* find end of name */
41   while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '|')
42     p++;
43   ne = p;
44   while (*p == ' ' || *p == '\t' || *p == '\n')
45     p++;
46   evr = 0;
47   flags = 0;
48   e = ee = 0;
49   if (*p == '>' || *p == '<' || *p == '=' || *p == '!')
50     {
51       if (*p == '>')
52         flags |= REL_GT;
53       else if (*p == '=')
54         flags |= REL_EQ;
55       else if (*p == '<')
56         flags |= REL_LT;
57       else if (*p == '!')
58         flags |= REL_LT | REL_GT | REL_EQ;
59       p++;
60       if (flags && *p == '=')
61         {
62           if (p[-1] != '=')
63             flags ^= REL_EQ;
64           p++;
65         }
66       while (*p == ' ' || *p == '\t' || *p == '\n')
67         p++;
68       e = p;
69       while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '|')
70         p++;
71       ee = p;
72       while (*p == ' ' || *p == '\t' || *p == '\n')
73         p++;
74     }
75   name = pool_strn2id(pool, n, ne - n, 1);
76   if (e)
77     {
78       evr = pool_strn2id(pool, e, ee - e, 1);
79       name = pool_rel2id(pool, name, evr, flags, 1);
80     }
81   if (*p == '|')
82     {
83       Id id = parseonedep(pool, p + 1);
84       if (id)
85         name = pool_rel2id(pool, name, id, REL_OR, 1);
86     }
87   return name;
88 }
89 static unsigned int
90 makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
91 {
92   Pool *pool = repo->pool;
93   char *p;
94   Id id;
95
96   while ((p = strchr(deps, ',')) != 0)
97     {
98       *p = 0;
99       olddeps = makedeps(repo, deps, olddeps, marker);
100       *p = ',';
101       deps = p + 1;
102     }
103   id = parseonedep(pool, deps);
104   if (!id)
105     return olddeps;
106   return repo_addid_dep(repo, olddeps, id, marker);
107 }
108
109 static Offset
110 copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
111 {
112   Id *ida, *from;
113   int cc;
114   Offset off;
115
116   if (!fromoff)
117     return 0;
118   from = fromrepo->idarraydata + fromoff;
119   for (ida = from, cc = 0; *ida; ida++, cc++)
120     ;
121   if (cc == 0)
122     return 0;
123   off = repo_reserve_ids(repo, 0, cc);
124   memcpy(repo->idarraydata + off, from, (cc + 1) * sizeof(Id));
125   repo->idarraysize += cc + 1;
126   return off;
127 }
128
129 static void
130 copysolvabledata(Pool *pool, Solvable *s, Repo *repo)
131 {
132   Repo *srepo = s->repo;
133   if (srepo == repo)
134     return;
135   s->provides = copydeps(pool, repo, s->provides, srepo);
136   s->requires = copydeps(pool, repo, s->requires, srepo);
137   s->conflicts = copydeps(pool, repo, s->conflicts, srepo);
138   s->obsoletes = copydeps(pool, repo, s->obsoletes, srepo);
139   s->recommends = copydeps(pool, repo, s->recommends, srepo);
140   s->suggests = copydeps(pool, repo, s->suggests, srepo);
141   s->supplements = copydeps(pool, repo, s->supplements, srepo);
142   s->enhances  = copydeps(pool, repo, s->enhances, srepo);
143 }
144
145 #define KEEP_VERSION 1
146 #define KEEP_PACKAGE 2
147 #define KEEP_FEATURE 3
148
149 static void
150 finishpackage(Pool *pool, Solvable *s, int keep, Queue *job)
151 {
152   Id *idp, id, sid;
153   if (!s)
154     return;
155   if (!s->arch)
156     s->arch = ARCH_ANY;
157   if (!s->evr)
158     s->evr = ID_EMPTY;
159   sid = pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
160   s->provides = repo_addid_dep(s->repo, s->provides, sid, 0);
161   if (!job || !pool->installed || s->repo != pool->installed)
162     return;
163   if (keep == KEEP_VERSION)
164     queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, sid);
165   else if (keep == KEEP_PACKAGE)
166     queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, s->name);
167   else if (keep == KEEP_FEATURE)
168     {
169       for (idp = s->repo->idarraydata + s->provides; (id = *idp) != 0; idp++)
170         {
171           if (id != sid)        /* skip self-provides */
172             queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id);
173         }
174     }
175 }
176
177 int
178 repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags)
179 {
180   Pool *pool;
181   char *buf, *p;
182   int bufa, bufl, c;
183   Solvable *s;
184   int instanza = 0;
185   int inrequest = 0;
186   int isinstalled = 0;
187   int keep = 0;
188   Repo *xrepo;
189
190   xrepo = repo ? repo : installedrepo;
191   if (!xrepo)
192     return -1;
193   pool = xrepo->pool;
194
195   buf = solv_malloc(4096);
196   bufa = 4096;
197   bufl = 0;
198   s = 0;
199
200   while (fgets(buf + bufl, bufa - bufl, fp) > 0)
201     {
202       bufl += strlen(buf + bufl);
203       if (bufl && buf[bufl - 1] != '\n')
204         {
205           if (bufa - bufl < 256)
206             {
207               bufa += 4096;
208               buf = solv_realloc(buf, bufa);
209             }
210           continue;
211         }
212       buf[--bufl] = 0;
213       c = getc(fp);
214       if (c == ' ' || c == '\t')
215         {
216           /* continuation line */
217           buf[bufl++] = ' ';
218           continue;
219         }
220       if (c != EOF)
221         ungetc(c, fp);
222       bufl = 0;
223       if (*buf == '#')
224         continue;
225       if (!*buf)
226         {
227           if (s && !repo && !isinstalled)
228             {
229               repo_free_solvable(repo, s - pool->solvables, 1);
230               s = 0;
231             }
232           if (s)
233             finishpackage(pool, s, keep, job);
234           s = 0;
235           keep = 0;
236           instanza = 0;
237           inrequest = 0;
238           continue;
239         }
240       p = strchr(buf, ':');
241       if (!p)
242         continue;       /* hmm */
243       *p++ = 0;
244       while (*p == ' ' || *p == '\t')
245         p++;
246       if (!instanza)
247         {
248           instanza = 1;
249           inrequest = 0;
250           if (!strcmp(buf, "request"))
251             {
252               inrequest = 1;
253               continue;
254             }
255           if (!strcmp(buf, "package"))
256             {
257               s = pool_id2solvable(pool, repo_add_solvable(xrepo));
258               isinstalled = 0;
259               keep = 0;
260             }
261         }
262       if (inrequest)
263         {
264           if (!job)
265             continue;
266           if (!strcmp(buf, "install"))
267             {
268               Id id, *idp;
269               Offset off = makedeps(xrepo, p, 0, 0);
270               for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
271                 queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id);
272             }
273           else if (!strcmp(buf, "remove"))
274             {
275               Id id, *idp;
276               Offset off = makedeps(xrepo, p, 0, 0);
277               for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
278                 queue_push2(job, SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES, id);
279             }
280           else if (!strcmp(buf, "upgrade"))
281             {
282               Id id, *idp;
283               Offset off = makedeps(xrepo, p, 0, 0);
284               for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
285                 queue_push2(job, SOLVER_INSTALL|SOLVER_ORUPDATE|SOLVER_SOLVABLE_PROVIDES, id);
286             }
287           continue;
288         }
289       if (!s)
290         continue;       /* we ignore the preamble for now */
291       switch (buf[0])
292         {
293         case 'c':
294           if (!strcmp(buf, "conflicts"))
295             {
296               s->conflicts = makedeps(s->repo, p, s->conflicts, 0);
297               continue;
298             }
299         case 'd':
300           if (!strcmp(buf, "depends"))
301             {
302               s->requires = makedeps(s->repo, p, s->requires, 0);
303               continue;
304             }
305           break;
306         case 'k':
307           if (!strcmp(buf, "keep"))
308             {
309               if (!job)
310                 continue;
311               if (!strcmp(p, "version"))
312                 keep = KEEP_VERSION;
313               else if (!strcmp(p, "package"))
314                 keep = KEEP_PACKAGE;
315               else if (!strcmp(p, "feature"))
316                 keep = KEEP_FEATURE;
317               continue;
318             }
319           break;
320         case 'i':
321           if (!strcmp(buf, "installed"))
322             {
323               if (!strcmp(p, "true"))
324                 {
325                   isinstalled = 1;
326                   if (!installedrepo)
327                     {
328                       repo_free_solvable(repo, s - pool->solvables, 1);
329                       s = 0;
330                     }
331                   else if (s->repo != installedrepo)
332                     {
333                       copysolvabledata(pool, s, installedrepo);
334                       s->repo->nsolvables--;
335                       s->repo = installedrepo;
336                       if (s - pool->solvables < s->repo->start)
337                         s->repo->start = s - pool->solvables;
338                       if (s - pool->solvables >= s->repo->end)
339                         s->repo->end = s - pool->solvables + 1;
340                       s->repo->nsolvables++;
341                     }
342                 }
343               continue;
344             }
345           break;
346         case 'p':
347           if (!strcmp(buf, "package"))
348             {
349               s->name = pool_str2id(pool, p, 1);
350               continue;
351             }
352           if (!strcmp(buf, "provides"))
353             {
354               s->provides = makedeps(s->repo, p, s->provides, 0);
355               continue;
356             }
357           break;
358         case 'r':
359           if (!strcmp(buf, "depends"))
360             {
361               s->recommends = makedeps(s->repo, p, s->recommends, 0);
362               continue;
363             }
364           break;
365         case 'v':
366           if (!strcmp(buf, "version"))
367             {
368               s->evr = pool_str2id(pool, p, 1);
369               continue;
370             }
371           break;
372         }
373     }
374   if (s && !repo && !isinstalled)
375     {
376       repo_free_solvable(repo, s - pool->solvables, 1);
377       s = 0;
378     }
379   if (s)
380     finishpackage(pool, s, keep, job);
381   solv_free(buf);
382   return 0;
383 }
384