Imported Upstream version 0.7.2
[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             s = solvable_free(s, 1);
228           if (s)
229             finishpackage(pool, s, keep, job);
230           s = 0;
231           keep = 0;
232           instanza = 0;
233           inrequest = 0;
234           continue;
235         }
236       p = strchr(buf, ':');
237       if (!p)
238         continue;       /* hmm */
239       *p++ = 0;
240       while (*p == ' ' || *p == '\t')
241         p++;
242       if (!instanza)
243         {
244           instanza = 1;
245           inrequest = 0;
246           if (!strcmp(buf, "request"))
247             {
248               inrequest = 1;
249               continue;
250             }
251           if (!strcmp(buf, "package"))
252             {
253               s = pool_id2solvable(pool, repo_add_solvable(xrepo));
254               isinstalled = 0;
255               keep = 0;
256             }
257         }
258       if (inrequest)
259         {
260           if (!job)
261             continue;
262           if (!strcmp(buf, "install"))
263             {
264               Id id, *idp;
265               Offset off = makedeps(xrepo, p, 0, 0);
266               for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
267                 queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id);
268             }
269           else if (!strcmp(buf, "remove"))
270             {
271               Id id, *idp;
272               Offset off = makedeps(xrepo, p, 0, 0);
273               for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
274                 queue_push2(job, SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES, id);
275             }
276           else if (!strcmp(buf, "upgrade"))
277             {
278               Id id, *idp;
279               Offset off = makedeps(xrepo, p, 0, 0);
280               for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
281                 queue_push2(job, SOLVER_INSTALL|SOLVER_ORUPDATE|SOLVER_SOLVABLE_PROVIDES, id);
282             }
283           continue;
284         }
285       if (!s)
286         continue;       /* we ignore the preamble for now */
287       switch (buf[0])
288         {
289         case 'c':
290           if (!strcmp(buf, "conflicts"))
291             {
292               s->conflicts = makedeps(s->repo, p, s->conflicts, 0);
293               continue;
294             }
295         case 'd':
296           if (!strcmp(buf, "depends"))
297             {
298               s->requires = makedeps(s->repo, p, s->requires, 0);
299               continue;
300             }
301           break;
302         case 'k':
303           if (!strcmp(buf, "keep"))
304             {
305               if (!job)
306                 continue;
307               if (!strcmp(p, "version"))
308                 keep = KEEP_VERSION;
309               else if (!strcmp(p, "package"))
310                 keep = KEEP_PACKAGE;
311               else if (!strcmp(p, "feature"))
312                 keep = KEEP_FEATURE;
313               continue;
314             }
315           break;
316         case 'i':
317           if (!strcmp(buf, "installed"))
318             {
319               if (!strcmp(p, "true"))
320                 {
321                   isinstalled = 1;
322                   if (!installedrepo)
323                     s = solvable_free(s, 1);
324                   else if (s->repo != installedrepo)
325                     {
326                       copysolvabledata(pool, s, installedrepo);
327                       s->repo->nsolvables--;
328                       s->repo = installedrepo;
329                       if (s - pool->solvables < s->repo->start)
330                         s->repo->start = s - pool->solvables;
331                       if (s - pool->solvables >= s->repo->end)
332                         s->repo->end = s - pool->solvables + 1;
333                       s->repo->nsolvables++;
334                     }
335                 }
336               continue;
337             }
338           break;
339         case 'p':
340           if (!strcmp(buf, "package"))
341             {
342               s->name = pool_str2id(pool, p, 1);
343               continue;
344             }
345           if (!strcmp(buf, "provides"))
346             {
347               s->provides = makedeps(s->repo, p, s->provides, 0);
348               continue;
349             }
350           break;
351         case 'r':
352           if (!strcmp(buf, "depends"))
353             {
354               s->recommends = makedeps(s->repo, p, s->recommends, 0);
355               continue;
356             }
357           break;
358         case 'v':
359           if (!strcmp(buf, "version"))
360             {
361               s->evr = pool_str2id(pool, p, 1);
362               continue;
363             }
364           break;
365         }
366     }
367   if (s && !repo && !isinstalled)
368     s = solvable_free(s, 1);
369   if (s)
370     finishpackage(pool, s, keep, job);
371   solv_free(buf);
372   return 0;
373 }
374