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