- export repo_add_cudf, use SOLVER_ORUPDATE for cudf update jobs
[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 = repo->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
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