Imported Upstream version 0.7.27
[platform/upstream/libsolv.git] / tools / testsolv.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <getopt.h>
5
6 #include "pool.h"
7 #include "repo.h"
8 #include "solver.h"
9 #include "selection.h"
10 #include "solverdebug.h"
11 #include "testcase.h"
12 #include "evr.h"
13
14 static struct resultflags2str {
15   Id flag;
16   const char *str;
17 } resultflags2str[] = {
18   { TESTCASE_RESULT_TRANSACTION,        "transaction" },
19   { TESTCASE_RESULT_PROBLEMS,           "problems" },
20   { TESTCASE_RESULT_ORPHANED,           "orphaned" },
21   { TESTCASE_RESULT_RECOMMENDED,        "recommended" },
22   { TESTCASE_RESULT_UNNEEDED,           "unneeded" },
23   { TESTCASE_RESULT_ALTERNATIVES,       "alternatives" },
24   { TESTCASE_RESULT_RULES,              "rules" },
25   { TESTCASE_RESULT_GENID,              "genid" },
26   { TESTCASE_RESULT_REASON,             "reason" },
27   { TESTCASE_RESULT_CLEANDEPS,          "cleandeps" },
28   { TESTCASE_RESULT_JOBS,               "jobs" },
29   { 0, 0 }
30 };
31
32 static void
33 usage(int ex)
34 {
35   fprintf(ex ? stderr : stdout, "Usage: testsolv <testcase>\n");
36   exit(ex);
37 }
38
39 struct reportsolutiondata {
40   int count;
41   char *result;
42 };
43
44 static int
45 reportsolutioncb(Solver *solv, void *cbdata)
46 {
47   struct reportsolutiondata *sd = cbdata;
48   char *res;
49
50   sd->count++;
51   res = testcase_solverresult(solv, TESTCASE_RESULT_TRANSACTION);
52   if (*res)
53     {
54       char prefix[64];
55       char *p2, *p = res;
56       sprintf(prefix, "callback%d:", sd->count);
57       while ((p2 = strchr(p, '\n')) != 0)
58         {
59           char c = p2[1];
60           p2[1] = 0;
61           sd->result = solv_dupappend(sd->result, prefix, p);
62           p2[1] = c;
63           p = p2 + 1;
64         }
65     }
66   solv_free(res);
67   return 0;
68 }
69
70 static void
71 free_considered(Pool *pool)
72 {
73   if (pool->considered)
74     {
75       map_free(pool->considered);
76       pool->considered = solv_free(pool->considered);
77     }
78 }
79
80 void
81 showwhy(Solver *solv, const char *showwhypkgstr)
82 {
83   Pool *pool = solv->pool;
84   Queue dq, rq, iq;
85   int ii, i;
86
87   queue_init(&dq);
88   queue_init(&rq);
89   queue_init(&iq);
90
91   i = testcase_str2solvid(pool, showwhypkgstr);
92   if (i)
93     solver_get_decisionlist(solv, i, SOLVER_DECISIONLIST_SOLVABLE | SOLVER_DECISIONLIST_SORTED, &dq);
94   else
95     {
96       int selflags = SELECTION_NAME | SELECTION_CANON;
97       selection_make(pool, &dq, showwhypkgstr, selflags);
98       selection_solvables(pool, &dq, &iq);
99       if (!iq.count)
100         printf("No package matches %s\n", showwhypkgstr);
101       queue_empty(&dq);
102       solver_get_decisionlist_multiple(solv, &iq, SOLVER_DECISIONLIST_SOLVABLE | SOLVER_DECISIONLIST_SORTED, &dq);
103     }
104   for (ii = 0; ii < dq.count; ii += 3)
105     {
106       Id v = dq.elements[ii];
107       int reason = dq.elements[ii + 1];
108       int info = dq.elements[ii + 2];
109
110       printf("%s %s:\n", v < 0 ? "conflicted" : "installed", testcase_solvid2str(pool, v >= 0 ? v : -v));
111       /* special case some reasons where we want to show multiple rule infos or extra info */
112       if (reason == SOLVER_REASON_WEAKDEP || reason == SOLVER_REASON_UNIT_RULE || reason == SOLVER_REASON_RESOLVE)
113         {
114           queue_empty(&iq);
115           if (reason == SOLVER_REASON_WEAKDEP)
116             solver_allweakdepinfos(solv, v, &iq);
117           else if (info > 0)
118             solver_allruleinfos(solv, info, &iq);
119           if (iq.count)
120             {
121               for (i = 0; i < iq.count; i += 4)
122                 {
123                   int bits;
124                   if (iq.elements[i] == SOLVER_RULE_LEARNT)
125                     {
126                       printf("  a learnt rule:\n");
127                       solver_ruleliterals(solv, info, &rq);
128                       for (i = 0; i < rq.count; i++)
129                         {
130                           Id p2 = rq.elements[i];
131                           printf("    %c %s\n", p2 > 0 ? '+' : '-', testcase_solvid2str(pool, p2 > 0 ? p2 : -p2));
132                         }
133                       continue;
134                     }
135                   bits = solver_calc_decisioninfo_bits(solv, v, iq.elements[i], iq.elements[i + 1], iq.elements[i + 2], iq.elements[i + 3]);
136                   printf("  %s\n", solver_decisioninfo2str(solv, bits, iq.elements[i], iq.elements[i + 1], iq.elements[i + 2], iq.elements[i + 3]));
137                 }
138               continue;
139             }
140         }
141       printf("  %s\n", solver_decisionreason2str(solv, v, reason, info));
142     }
143   queue_free(&iq);
144   queue_free(&rq);
145   queue_free(&dq);
146 }
147
148 void
149 doshowproof(Solver *solv, Id id, int flags, Queue *lq)
150 {
151   Pool *pool = solv->pool;
152   Queue q, qp;
153   int i, j;
154
155   queue_init(&q);
156   queue_init(&qp);
157   solver_get_decisionlist(solv, id, flags | SOLVER_DECISIONLIST_SORTED | SOLVER_DECISIONLIST_WITHINFO | SOLVER_DECISIONLIST_MERGEDINFO, &q);
158   for (i = 0; i < q.count; i += 8)
159     {
160       Id v = q.elements[i];
161       int reason = q.elements[i + 1], bits = q.elements[i + 3], type = q.elements[i + 4];
162       Id from = q.elements[i + 5], to = q.elements[i + 6], dep = q.elements[i + 7];
163
164       if (reason != SOLVER_REASON_UNSOLVABLE && type == SOLVER_RULE_PKG_SAME_NAME)
165         continue;       /* do not show "obvious" decisions */
166
167       solver_decisionlist_solvables(solv, &q, i, &qp);
168       if (reason == SOLVER_REASON_UNSOLVABLE)
169         printf("unsolvable: ");
170       else
171         printf("%s %s: ", v < 0 ? "conflicted" : "installed", pool_solvidset2str(pool, &qp));
172       i += solver_decisionlist_merged(solv, &q, i) * 8;
173       if (type == 0)
174         {
175           printf("%s\n", solver_reason2str(solv, reason));
176           continue;
177         }
178       if (type == SOLVER_RULE_LEARNT && lq)
179         {
180           for (j = 0; j < lq->count; j++)
181             if (lq->elements[j] == q.elements[i + 2])
182               break;
183           if (j < lq->count)
184             {
185               printf("learnt rule #%d\n", j + 1);
186               continue;
187             }
188         }
189       printf("%s\n", solver_decisioninfo2str(solv, bits, type, from, to, dep));
190     }
191   queue_free(&qp);
192   queue_free(&q);
193 }
194
195 int
196 main(int argc, char **argv)
197 {
198   Pool *pool;
199   Queue job;
200   Queue solq;
201   Solver *solv, *reusesolv = 0;
202   char *result = 0;
203   char *showwhypkgstr = 0;
204   int resultflags = 0;
205   int debuglevel = 0;
206   int writeresult = 0;
207   char *writetestcase = 0;
208   int multijob = 0;
209   int rescallback = 0;
210   int showproof = 0;
211   int c;
212   int ex = 0;
213   const char *list = 0;
214   int list_with_deps = 0;
215   FILE *fp;
216   const char *p;
217
218   queue_init(&solq);
219   while ((c = getopt(argc, argv, "vmrhL:l:s:T:W:P")) >= 0)
220     {
221       switch (c)
222       {
223         case 'v':
224           debuglevel++;
225           break;
226         case 'r':
227           writeresult++;
228           break;
229         case 'm':
230           rescallback = 1;
231           break;
232         case 'h':
233           usage(0);
234           break;
235         case 'l':
236           list = optarg;
237           list_with_deps = 0;
238           break;
239         case 'L':
240           list = optarg;
241           list_with_deps = 1;
242           break;
243         case 'W':
244           showwhypkgstr = optarg;
245           break;
246         case 's':
247           if ((p = strchr(optarg, ':')))
248             queue_push2(&solq, atoi(optarg), atoi(p + 1));
249           else
250             queue_push2(&solq, 1, atoi(optarg));
251           break;
252         case 'T':
253           writetestcase = optarg;
254           break;
255         case 'P':
256           showproof = 1;
257           break;
258         default:
259           usage(1);
260           break;
261       }
262     }
263   if (optind == argc)
264     usage(1);
265   for (; optind < argc; optind++)
266     {
267       pool = pool_create();
268       pool_setdebuglevel(pool, debuglevel);
269       /* report all errors */
270       pool_setdebugmask(pool, pool->debugmask | SOLV_ERROR);
271
272       fp = fopen(argv[optind], "r");
273       if (!fp)
274         {
275           perror(argv[optind]);
276           exit(0);
277         }
278       while (!feof(fp))
279         {
280           queue_init(&job);
281           result = 0;
282           resultflags = 0;
283           solv = testcase_read(pool, fp, argv[optind], &job, &result, &resultflags);
284           if (!solv)
285             {
286               free_considered(pool);
287               pool_free(pool);
288               queue_free(&job);
289               exit(resultflags == 77 ? 77 : 1);
290             }
291           if (reusesolv)
292             {
293               solver_free(solv);
294               solv = reusesolv;
295               reusesolv = 0;
296             }
297           if (!multijob && !feof(fp))
298             multijob = 1;
299
300           if (multijob)
301             printf("test %d:\n", multijob++);
302           if (list)
303             {
304               Id p = 0;
305               int selflags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL|SELECTION_GLOB|SELECTION_FLAT;
306               if (*list == '/')
307                 selflags |= SELECTION_FILELIST;
308               queue_empty(&job);
309               if (list_with_deps)
310                 p = testcase_str2solvid(pool, list);
311               if (p)
312                 queue_push2(&job, SOLVER_SOLVABLE, p);
313               else
314                 selection_make(pool, &job, list, selflags);
315               if (!job.elements)
316                 printf("No match\n");
317               else
318                 {
319                   Queue q;
320                   int i;
321                   queue_init(&q);
322                   selection_solvables(pool, &job, &q);
323                   for (i = 0; i < q.count; i++)
324                     {
325                       printf("  - %s\n", testcase_solvid2str(pool, q.elements[i]));
326                       if (list_with_deps)
327                         {
328                           int j, k;
329                           const char *vendor;
330                           static Id deps[] = {
331                             SOLVABLE_PROVIDES, SOLVABLE_REQUIRES, SOLVABLE_CONFLICTS, SOLVABLE_OBSOLETES,
332                             SOLVABLE_RECOMMENDS, SOLVABLE_SUGGESTS, SOLVABLE_SUPPLEMENTS, SOLVABLE_ENHANCES,
333                             SOLVABLE_PREREQ_IGNOREINST,
334                             0
335                           };
336                           vendor = pool_lookup_str(pool, q.elements[i], SOLVABLE_VENDOR);
337                           if (vendor)
338                             printf("    %s: %s\n", pool_id2str(pool, SOLVABLE_VENDOR), vendor);
339                           for (j = 0; deps[j]; j++)
340                             {
341                               Queue dq;
342                               queue_init(&dq);
343                               pool_lookup_idarray(pool, q.elements[i], deps[j], &dq);
344                               if (dq.count)
345                                 printf("    %s:\n", pool_id2str(pool, deps[j]));
346                               for (k = 0; k < dq.count; k++)
347                                 printf("      %s\n", pool_dep2str(pool, dq.elements[k]));
348                               queue_free(&dq);
349                             }
350                         }
351                     }
352                   queue_free(&q);
353                 }
354             }
355           else if (showwhypkgstr)
356             {
357               solver_solve(solv, &job);
358               showwhy(solv, showwhypkgstr);
359             }
360           else if (showproof)
361             {
362               int pcnt = solver_solve(solv, &job);
363               int problem;
364               if (!pcnt)
365                 printf("nothing to proof\n");
366               for (problem = 1; problem <= pcnt; problem++)
367                 {
368                   Queue lq;
369                   int i;
370                   queue_init(&lq);
371                   solver_get_learnt(solv, problem, SOLVER_DECISIONLIST_PROBLEM, &lq);
372                   for (i = 0; i < lq.count; i++)
373                     {
374                       printf("Learnt rule #%d:\n", i + 1);
375                       doshowproof(solv, lq.elements[i], SOLVER_DECISIONLIST_LEARNTRULE, &lq);
376                       printf("\n");
377                     }
378                   printf("Proof #%d:\n", problem);
379                   doshowproof(solv, problem, SOLVER_DECISIONLIST_PROBLEM, &lq);
380                   queue_free(&lq);
381                   if (problem < pcnt)
382                     printf("\n");
383                 }
384             }
385           else if (result || writeresult)
386             {
387               char *myresult, *resultdiff;
388               struct reportsolutiondata reportsolutiondata;
389               memset(&reportsolutiondata, 0, sizeof(reportsolutiondata));
390               if (rescallback)
391                 {
392                   solv->solution_callback = reportsolutioncb;
393                   solv->solution_callback_data = &reportsolutiondata;
394                 }
395               solver_solve(solv, &job);
396               solv->solution_callback = 0;
397               solv->solution_callback_data = 0;
398               if ((resultflags & ~TESTCASE_RESULT_REUSE_SOLVER) == 0)
399                 resultflags |= TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS;
400               myresult = testcase_solverresult(solv, resultflags);
401               if (rescallback && reportsolutiondata.result)
402                 {
403                   reportsolutiondata.result = solv_dupjoin(reportsolutiondata.result, myresult, 0);
404                   solv_free(myresult);
405                   myresult = reportsolutiondata.result;
406                 }
407               if (writeresult)
408                 {
409                   if (*myresult)
410                     {
411                       if (writeresult > 1)
412                         {
413                           const char *p;
414                           int i;
415                           
416                           printf("result ");
417                           p = "%s";
418                           for (i = 0; resultflags2str[i].str; i++)
419                             if ((resultflags & resultflags2str[i].flag) != 0)
420                               {
421                                 printf(p, resultflags2str[i].str);
422                                 p = ",%s";
423                               }
424                           printf(" <inline>\n");
425                           p = myresult;
426                           while (*p)
427                             {
428                               const char *p2 = strchr(p, '\n');
429                               p2 = p2 ? p2 + 1 : p + strlen(p);
430                               printf("#>%.*s", (int)(p2 - p), p);
431                               p = p2;
432                             }
433                         }
434                       else
435                         printf("%s", myresult);
436                     }
437                 }
438               else
439                 {
440                   resultdiff = testcase_resultdiff(result, myresult);
441                   if (resultdiff)
442                     {
443                       printf("Results differ:\n%s", resultdiff);
444                       ex = 1;
445                       solv_free(resultdiff);
446                     }
447                 }
448               solv_free(result);
449               solv_free(myresult);
450             }
451           else
452             {
453               int pcnt = solver_solve(solv, &job);
454               if (writetestcase)
455                 {
456                   if (!testcase_write(solv, writetestcase, resultflags, 0, 0))
457                     {
458                       fprintf(stderr, "Could not write testcase: %s\n", pool_errstr(pool));
459                       exit(1);
460                     }
461                 }
462               if (pcnt && solq.count)
463                 {
464                   int i, taken = 0;
465                   for (i = 0; i < solq.count; i += 2)
466                     {
467                       if (solq.elements[i] > 0 && solq.elements[i] <= pcnt)
468                         if (solq.elements[i + 1] > 0 && solq.elements[i + 1] <=  solver_solution_count(solv, solq.elements[i]))
469                           {
470                             printf("problem %d: taking solution %d\n", solq.elements[i], solq.elements[i + 1]);
471                             solver_take_solution(solv, solq.elements[i], solq.elements[i + 1], &job);
472                             taken = 1;
473                           }
474                     }
475                   if (taken)
476                     pcnt = solver_solve(solv, &job);
477                 }
478               if (pcnt)
479                 {
480                   int problem, solution, scnt;
481                   printf("Found %d problems:\n", pcnt);
482                   for (problem = 1; problem <= pcnt; problem++)
483                     {
484                       printf("Problem %d:\n", problem);
485 #if 1
486                       solver_printprobleminfo(solv, problem);
487 #else
488                       {
489                         Queue pq;
490                         int j;
491                         queue_init(&pq);
492                         solver_findallproblemrules(solv, problem, &pq);
493                         for (j = 0; j < pq.count; j++)
494                           solver_printproblemruleinfo(solv, pq.elements[j]);
495                         queue_free(&pq);
496                       }
497 #endif
498                       printf("\n");
499                       scnt = solver_solution_count(solv, problem);
500                       for (solution = 1; solution <= scnt; solution++)
501                         {
502                           printf("Solution %d:\n", solution);
503                           solver_printsolution(solv, problem, solution);
504                           printf("\n");
505                         }
506                     }
507                 }
508               else
509                 {
510                   Transaction *trans = solver_create_transaction(solv);
511                   printf("Transaction summary:\n\n");
512                   transaction_print(trans);
513                   transaction_free(trans);
514                 }
515             }
516           queue_free(&job);
517           if ((resultflags & TESTCASE_RESULT_REUSE_SOLVER) != 0 && !feof(fp))
518             reusesolv = solv;
519           else
520             solver_free(solv);
521         }
522       if (reusesolv)
523         solver_free(reusesolv);
524       free_considered(pool);
525       pool_free(pool);
526       fclose(fp);
527     }
528   queue_free(&solq);
529   exit(ex);
530 }