- make installcheck work with debian Packages files
[platform/upstream/libsolv.git] / tools / installcheck.c
1 /* vim: sw=2 et cino=>4,n-2,{1s
2  */
3
4 /*
5  * Copyright (c) 2009, Novell Inc.
6  *
7  * This program is licensed under the BSD license, read LICENSE.BSD
8  * for further information
9  */
10
11
12 #define _GNU_SOURCE
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <zlib.h>
19
20 #include "pool.h"
21 #include "poolarch.h"
22 #include "repo_solv.h"
23 #ifndef DEBIAN
24 #include "repo_susetags.h"
25 #include "repo_rpmmd.h"
26 #else
27 #include "repo_deb.h"
28 #endif
29 #include "solver.h"
30
31 static ssize_t
32 cookie_gzread(void *cookie, char *buf, size_t nbytes)
33 {
34   return gzread((gzFile *)cookie, buf, nbytes);
35 }
36
37 static int
38 cookie_gzclose(void *cookie)
39 {
40   return gzclose((gzFile *)cookie);
41 }
42
43 FILE *
44 myfopen(const char *fn)
45 {
46   cookie_io_functions_t cio;
47   char *suf;
48   gzFile *gzf;
49
50   if (!fn)
51     return 0;
52   suf = strrchr(fn, '.');
53   if (!suf || strcmp(suf, ".gz") != 0)
54     return fopen(fn, "r");
55   gzf = gzopen(fn, "r");
56   if (!gzf)
57     return 0;
58   memset(&cio, 0, sizeof(cio));
59   cio.read = cookie_gzread;
60   cio.close = cookie_gzclose;
61   return  fopencookie(gzf, "r", cio);
62 }
63
64 void
65 usage(char** argv)
66 {
67   printf("Usage:\n%s: <arch> repo [--nocheck repo]...\n", argv[0]);
68   exit(1);
69 }
70
71
72 int
73 main(int argc, char **argv)
74 {
75   Pool *pool;
76   Solver *solv;
77   Queue job;
78   Queue rids;
79   Queue cand;
80   Queue archlocks;
81   char *arch, *exclude_pat;
82   int i, j;
83   Id p;
84   Id rpmid, rpmarch, rpmrel, archlock;
85   int status = 0;
86   int nocheck = 0;
87   int withsrc = 0;
88
89   exclude_pat = 0;
90   archlock = 0;
91   if (argc < 3)
92     usage(argv);
93
94   arch = argv[1];
95   pool = pool_create();
96   pool_setarch(pool, arch);
97   for (i = 2; i < argc; i++)
98     {
99       FILE *fp;
100       int l;
101
102       if (!strcmp(argv[i], "--withsrc"))
103         {
104           withsrc++;
105           continue;
106         }
107       if (!strcmp(argv[i], "--nocheck"))
108         {
109           if (!nocheck)
110             nocheck = pool->nsolvables;
111           continue;
112         }
113       if (!strcmp(argv[i], "--exclude"))
114         {
115           if (i + 1 >= argc)
116             {
117               printf("--exclude needs a whitespace separated list of substrings as parameter\n");
118               exit(1);
119             }
120           exclude_pat = argv[i + 1];
121           ++i;
122           continue;
123         }
124       l = strlen(argv[i]);
125       if (!strcmp(argv[i], "-"))
126         fp = stdin;
127       else if ((fp = myfopen(argv[i])) == 0)
128         {
129           perror(argv[i]);
130           exit(1);
131         }
132       Repo *repo = repo_create(pool, argv[i]);
133 #ifndef DEBIAN
134       if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
135         {
136           repo_add_susetags(repo, fp, 0, 0, 0);
137         }
138       else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
139         {
140           repo_add_susetags(repo, fp, 0, 0, 0);
141         }
142       else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
143         {
144           repo_add_rpmmd(repo, fp, 0, 0);
145         }
146 #else
147       if (l >= 8 && !strcmp(argv[i] + l - 8, "Packages"))
148         {
149           repo_add_debpackages(repo, fp, 0);
150         }
151       else if (l >= 11 && !strcmp(argv[i] + l - 11, "Packages.gz"))
152         {
153           repo_add_debpackages(repo, fp, 0);
154         }
155 #endif
156       else if (repo_add_solv(repo, fp))
157         {
158           fprintf(stderr, "could not add repo %s\n", argv[i]);
159           exit(1);
160         }
161       if (fp != stdin)
162         fclose(fp);
163     }
164   pool_addfileprovides(pool);
165   pool_createwhatprovides(pool);
166   rpmid = str2id(pool, "rpm", 0);
167   rpmarch = str2id(pool, arch, 0);
168   rpmrel = 0;
169 #ifndef DEBIAN
170   if (rpmid && rpmarch)
171     {
172       for (p = 1; p < pool->nsolvables; p++)
173         {
174           Solvable *s = pool->solvables + p;
175           if (s->name == rpmid && s->arch == rpmarch)
176             break;
177         }
178       if (p < pool->nsolvables)
179         rpmrel = rel2id(pool, rpmid, rpmarch, REL_ARCH, 1);
180     }
181 #endif
182   
183   queue_init(&job);
184   queue_init(&rids);
185   queue_init(&cand);
186   queue_init(&archlocks);
187   for (p = 1; p < pool->nsolvables; p++)
188     {
189       Solvable *s = pool->solvables + p;
190       if (!s->repo)
191         continue;
192       if (withsrc && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
193         {
194           queue_push(&cand, p);
195           continue;
196         }
197       if (!pool_installable(pool, s))
198         continue;
199       if (rpmrel && s->arch != rpmarch)
200         {
201           Id rp, rpp;
202           FOR_PROVIDES(rp, rpp, s->name)
203             {
204               if (pool->solvables[rp].name != s->name)
205                 continue;
206               if (pool->solvables[rp].arch == rpmarch)
207                 break;
208             }
209           if (rp)
210             {
211               queue_push(&archlocks, p);
212               continue;
213             }
214         }
215       queue_push(&cand, p);
216     }
217   
218   if (archlocks.count)
219     {
220       archlock = pool_queuetowhatprovides(pool, &archlocks);
221     }
222   /* prune cand by doing weak installs */
223   while (cand.count)
224     {
225       solv = solver_create(pool);
226       queue_empty(&job);
227       for (i = 0; i < cand.count; i++)
228         {
229           p = cand.elements[i];
230           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
231           queue_push(&job, p);
232         }
233       if (rpmrel)
234         {
235           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
236           queue_push(&job, rpmrel);
237         }
238       if (archlock)
239         {
240           queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
241           queue_push(&job, archlock);
242         }
243       solv->dontinstallrecommended = 1;
244       solver_solve(solv, &job);
245       /* prune... */
246       for (i = j = 0; i < cand.count; i++)
247         {
248           p = cand.elements[i];
249           if (solv->decisionmap[p] <= 0)
250             {
251               cand.elements[j++] = p;
252               continue;
253             }
254 #if 0
255           Solvable *s = pool->solvables + p;
256           if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
257             {
258               cand.elements[j++] = p;
259               continue;
260             }
261 #endif
262         }
263       cand.count = j;
264       if (i == j)
265         break;
266     }
267
268   /* now check every candidate */
269   for (i = 0; i < cand.count; i++)
270     {
271       Solvable *s;
272
273       p = cand.elements[i];
274       if (nocheck && p >= nocheck)
275         continue;
276       if (exclude_pat)
277         {
278           char *ptr, *save = 0, *pattern;
279           int match = 0;
280           pattern = strdup(exclude_pat);
281
282           for (ptr = strtok_r(pattern, " ", &save);
283               ptr;
284               ptr = strtok_r(NULL, " ", &save))
285             {
286               if (*ptr && strstr(solvid2str(pool, p), ptr))
287                 {
288                   match = 1;
289                   break;
290                 }
291             }
292           free(pattern);
293           if (match)
294             continue;
295         }
296       s = pool->solvables + p;
297       solv = solver_create(pool);
298       queue_empty(&job);
299       queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
300       queue_push(&job, p);
301       if (rpmrel)
302         {
303           queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME);
304           queue_push(&job, rpmrel);
305         }
306       if (archlock)
307         {
308           queue_push(&job, SOLVER_LOCK|SOLVER_SOLVABLE_ONE_OF);
309           queue_push(&job, archlock);
310         }
311       solv->dontinstallrecommended = 1;
312       solver_solve(solv, &job);
313       if (solv->problems.count)
314         {
315           Id problem = 0;
316           Solvable *s2;
317
318           status = 1;
319           printf("can't install %s:\n", solvable2str(pool, s));
320           while ((problem = solver_next_problem(solv, problem)) != 0)
321             {
322               solver_findallproblemrules(solv, problem, &rids);
323               for (j = 0; j < rids.count; j++)
324                 {
325                   Id probr = rids.elements[j];
326                   int k;
327                   Queue rinfo;
328                   queue_init(&rinfo);
329
330                   solver_allruleinfos(solv, probr, &rinfo);
331                   for (k = 0; k < rinfo.count; k += 4)
332                     {
333                       Id dep, source, target;
334                       source = rinfo.elements[k + 1];
335                       target = rinfo.elements[k + 2];
336                       dep = rinfo.elements[k + 3];
337                       switch (rinfo.elements[k])
338                         {
339                         case SOLVER_PROBLEM_DISTUPGRADE_RULE:
340                           break;
341                         case SOLVER_PROBLEM_INFARCH_RULE:
342                           s = pool_id2solvable(pool, source);
343                           printf("  %s has inferior architecture\n", solvable2str(pool, s));
344                           break;
345                         case SOLVER_PROBLEM_UPDATE_RULE:
346                           break;
347                         case SOLVER_PROBLEM_JOB_RULE:
348                           break;
349                         case SOLVER_PROBLEM_RPM_RULE:
350                           printf("  some dependency problem\n");
351                           break;
352                         case SOLVER_PROBLEM_JOB_NOTHING_PROVIDES_DEP:
353                           printf("  nothing provides requested %s\n", dep2str(pool, dep));
354                           break;
355                         case SOLVER_PROBLEM_NOT_INSTALLABLE:
356                           s = pool_id2solvable(pool, source);
357                           printf("  package %s is not installable\n", solvable2str(pool, s));
358                           break;
359                         case SOLVER_PROBLEM_NOTHING_PROVIDES_DEP:
360                           s = pool_id2solvable(pool, source);
361                           printf("  nothing provides %s needed by %s\n", dep2str(pool, dep), solvable2str(pool, s));
362                           if (ISRELDEP(dep))
363                             {
364                               Reldep *rd = GETRELDEP(pool, dep);
365                               if (!ISRELDEP(rd->name))
366                                 {
367                                   Id rp, rpp;
368                                   FOR_PROVIDES(rp, rpp, rd->name)
369                                     printf("    (we have %s)\n", solvable2str(pool, pool->solvables + rp));
370                                 }
371                             }
372                           break;
373                         case SOLVER_PROBLEM_SAME_NAME:
374                           s = pool_id2solvable(pool, source);
375                           s2 = pool_id2solvable(pool, target);
376                           printf("  cannot install both %s and %s\n", solvable2str(pool, s), solvable2str(pool, s2));
377                           break;
378                         case SOLVER_PROBLEM_PACKAGE_CONFLICT:
379                           s = pool_id2solvable(pool, source);
380                           s2 = pool_id2solvable(pool, target);
381                           printf("  package %s conflicts with %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
382                           break;
383                         case SOLVER_PROBLEM_PACKAGE_OBSOLETES:
384                           s = pool_id2solvable(pool, source);
385                           s2 = pool_id2solvable(pool, target);
386                           printf("  package %s obsoletes %s provided by %s\n", solvable2str(pool, s), dep2str(pool, dep), solvable2str(pool, s2));
387                           break;
388                         case SOLVER_PROBLEM_DEP_PROVIDERS_NOT_INSTALLABLE:
389                           s = pool_id2solvable(pool, source);
390                           printf("  package %s requires %s, but none of the providers can be installed\n", solvable2str(pool, s), dep2str(pool, dep));
391                           break;
392                         case SOLVER_PROBLEM_SELF_CONFLICT:
393                           s = pool_id2solvable(pool, source);
394                           printf("  package %s conflicts with %s provided by itself\n", solvable2str(pool, s), dep2str(pool, dep));
395                           break;
396                         }
397                     }
398                 }
399             }
400         }
401 #if 0
402       else
403         {
404           if (!strcmp(id2str(pool, s->name), "libusb-compat-devel"))
405             {
406               solver_printdecisions(solv);
407             }
408         }
409 #endif
410       solver_free(solv);
411     }
412   exit(status);
413 }