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 <limits.h> 11#include <fcntl.h> 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15#include <errno.h> 16 17#include "pool.h" 18#include "poolarch.h" 19#include "poolvendor.h" 20#include "repo.h" 21#include "repo_solv.h" 22#include "solver.h" 23#include "solverdebug.h" 24#include "chksum.h" 25#include "testcase.h" 26#include "selection.h" 27#include "solv_xfopen.h" 28 29#define DISABLE_JOIN2 30#include "tools_util.h" 31 32static struct job2str { 33 Id job; 34 const char *str; 35} job2str[] = { 36 { SOLVER_NOOP, "noop" }, 37 { SOLVER_INSTALL, "install" }, 38 { SOLVER_ERASE, "erase" }, 39 { SOLVER_UPDATE, "update" }, 40 { SOLVER_WEAKENDEPS, "weakendeps" }, 41 { SOLVER_MULTIVERSION, "multiversion" }, 42 { SOLVER_MULTIVERSION, "noobsoletes" }, /* old name */ 43 { SOLVER_LOCK, "lock" }, 44 { SOLVER_DISTUPGRADE, "distupgrade" }, 45 { SOLVER_VERIFY, "verify" }, 46 { SOLVER_DROP_ORPHANED, "droporphaned" }, 47 { SOLVER_USERINSTALLED, "userinstalled" }, 48 { 0, 0 } 49}; 50 51static struct jobflags2str { 52 Id flag; 53 const char *str; 54} jobflags2str[] = { 55 { SOLVER_WEAK, "weak" }, 56 { SOLVER_ESSENTIAL, "essential" }, 57 { SOLVER_CLEANDEPS, "cleandeps" }, 58 { SOLVER_ORUPDATE, "orupdate" }, 59 { SOLVER_FORCEBEST, "forcebest" }, 60 { SOLVER_TARGETED, "targeted" }, 61 { SOLVER_SETEV, "setev" }, 62 { SOLVER_SETEVR, "setevr" }, 63 { SOLVER_SETARCH, "setarch" }, 64 { SOLVER_SETVENDOR, "setvendor" }, 65 { SOLVER_SETREPO, "setrepo" }, 66 { SOLVER_NOAUTOSET, "noautoset" }, 67 { 0, 0 } 68}; 69 70static struct resultflags2str { 71 Id flag; 72 const char *str; 73} resultflags2str[] = { 74 { TESTCASE_RESULT_TRANSACTION, "transaction" }, 75 { TESTCASE_RESULT_PROBLEMS, "problems" }, 76 { TESTCASE_RESULT_ORPHANED, "orphaned" }, 77 { TESTCASE_RESULT_RECOMMENDED, "recommended" }, 78 { TESTCASE_RESULT_UNNEEDED, "unneeded" }, 79 { 0, 0 } 80}; 81 82static struct solverflags2str { 83 Id flag; 84 const char *str; 85 int def; 86} solverflags2str[] = { 87 { SOLVER_FLAG_ALLOW_DOWNGRADE, "allowdowngrade", 0 }, 88 { SOLVER_FLAG_ALLOW_NAMECHANGE, "allownamechange", 1 }, 89 { SOLVER_FLAG_ALLOW_ARCHCHANGE, "allowarchchange", 0 }, 90 { SOLVER_FLAG_ALLOW_VENDORCHANGE, "allowvendorchange", 0 }, 91 { SOLVER_FLAG_ALLOW_UNINSTALL, "allowuninstall", 0 }, 92 { SOLVER_FLAG_NO_UPDATEPROVIDE, "noupdateprovide", 0 }, 93 { SOLVER_FLAG_SPLITPROVIDES, "splitprovides", 0 }, 94 { SOLVER_FLAG_IGNORE_RECOMMENDED, "ignorerecommended", 0 }, 95 { SOLVER_FLAG_ADD_ALREADY_RECOMMENDED, "addalreadyrecommended", 0 }, 96 { SOLVER_FLAG_NO_INFARCHCHECK, "noinfarchcheck", 0 }, 97 { SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES, "keepexplicitobsoletes", 0 }, 98 { SOLVER_FLAG_BEST_OBEY_POLICY, "bestobeypolicy", 0 }, 99 { SOLVER_FLAG_NO_AUTOTARGET, "noautotarget", 0 }, 100 { 0, 0, 0 } 101}; 102 103static struct poolflags2str { 104 Id flag; 105 const char *str; 106 int def; 107} poolflags2str[] = { 108 { POOL_FLAG_PROMOTEEPOCH, "promoteepoch", 0 }, 109 { POOL_FLAG_FORBIDSELFCONFLICTS, "forbidselfconflicts", 0 }, 110 { POOL_FLAG_OBSOLETEUSESPROVIDES, "obsoleteusesprovides", 0 }, 111 { POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES, "implicitobsoleteusesprovides", 0 }, 112 { POOL_FLAG_OBSOLETEUSESCOLORS, "obsoleteusescolors", 0 }, 113 { POOL_FLAG_NOINSTALLEDOBSOLETES, "noinstalledobsoletes", 0 }, 114 { POOL_FLAG_HAVEDISTEPOCH, "havedistepoch", 0 }, 115 { 0, 0, 0 } 116}; 117 118static struct disttype2str { 119 Id type; 120 const char *str; 121} disttype2str[] = { 122 { DISTTYPE_RPM, "rpm" }, 123 { DISTTYPE_DEB, "deb" }, 124 { DISTTYPE_ARCH, "arch" }, 125 { 0, 0 } 126}; 127 128static struct selflags2str { 129 Id flag; 130 const char *str; 131} selflags2str[] = { 132 { SELECTION_NAME, "name" }, 133 { SELECTION_PROVIDES, "provides" }, 134 { SELECTION_FILELIST, "filelist" }, 135 { SELECTION_CANON, "canon" }, 136 { SELECTION_DOTARCH, "dotarch" }, 137 { SELECTION_REL, "rel" }, 138 { SELECTION_INSTALLED_ONLY, "installedonly" }, 139 { SELECTION_GLOB, "glob" }, 140 { SELECTION_FLAT, "flat" }, 141 { SELECTION_NOCASE, "nocase" }, 142 { SELECTION_SOURCE_ONLY, "sourceonly" }, 143 { SELECTION_WITH_SOURCE, "withsource" }, 144 { 0, 0 } 145}; 146 147 148typedef struct strqueue { 149 char **str; 150 int nstr; 151} Strqueue; 152 153#define STRQUEUE_BLOCK 63 154 155static void 156strqueue_init(Strqueue *q) 157{ 158 q->str = 0; 159 q->nstr = 0; 160} 161 162static void 163strqueue_free(Strqueue *q) 164{ 165 int i; 166 for (i = 0; i < q->nstr; i++) 167 solv_free(q->str[i]); 168 q->str = solv_free(q->str); 169 q->nstr = 0; 170} 171 172static void 173strqueue_push(Strqueue *q, const char *s) 174{ 175 q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK); 176 q->str[q->nstr++] = solv_strdup(s); 177} 178 179static void 180strqueue_pushjoin(Strqueue *q, const char *s1, const char *s2, const char *s3) 181{ 182 q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK); 183 q->str[q->nstr++] = solv_dupjoin(s1, s2, s3); 184} 185 186static int 187strqueue_sort_cmp(const void *ap, const void *bp, void *dp) 188{ 189 const char *a = *(const char **)ap; 190 const char *b = *(const char **)bp; 191 return strcmp(a ? a : "", b ? b : ""); 192} 193 194static void 195strqueue_sort(Strqueue *q) 196{ 197 if (q->nstr > 1) 198 solv_sort(q->str, q->nstr, sizeof(*q->str), strqueue_sort_cmp, 0); 199} 200 201static void 202strqueue_sort_u(Strqueue *q) 203{ 204 int i, j; 205 strqueue_sort(q); 206 for (i = j = 0; i < q->nstr; i++) 207 if (!j || strqueue_sort_cmp(q->str + i, q->str + j - 1, 0) != 0) 208 q->str[j++] = q->str[i]; 209 q->nstr = j; 210} 211 212static char * 213strqueue_join(Strqueue *q) 214{ 215 int i, l = 0; 216 char *r, *rp; 217 for (i = 0; i < q->nstr; i++) 218 if (q->str[i]) 219 l += strlen(q->str[i]) + 1; 220 l++; /* trailing \0 */ 221 r = solv_malloc(l); 222 rp = r; 223 for (i = 0; i < q->nstr; i++) 224 if (q->str[i]) 225 { 226 strcpy(rp, q->str[i]); 227 rp += strlen(rp); 228 *rp++ = '\n'; 229 } 230 *rp = 0; 231 return r; 232} 233 234static void 235strqueue_split(Strqueue *q, const char *s) 236{ 237 const char *p; 238 if (!s) 239 return; 240 while ((p = strchr(s, '\n')) != 0) 241 { 242 q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK); 243 q->str[q->nstr] = solv_malloc(p - s + 1); 244 if (p > s) 245 memcpy(q->str[q->nstr], s, p - s); 246 q->str[q->nstr][p - s] = 0; 247 q->nstr++; 248 s = p + 1; 249 } 250 if (*s) 251 strqueue_push(q, s); 252} 253 254static void 255strqueue_diff(Strqueue *sq1, Strqueue *sq2, Strqueue *osq) 256{ 257 int i = 0, j = 0; 258 while (i < sq1->nstr && j < sq2->nstr) 259 { 260 int r = strqueue_sort_cmp(sq1->str + i, sq2->str + j, 0); 261 if (!r) 262 i++, j++; 263 else if (r < 0) 264 strqueue_pushjoin(osq, "-", sq1->str[i++], 0); 265 else 266 strqueue_pushjoin(osq, "+", sq2->str[j++], 0); 267 } 268 while (i < sq1->nstr) 269 strqueue_pushjoin(osq, "-", sq1->str[i++], 0); 270 while (j < sq2->nstr) 271 strqueue_pushjoin(osq, "+", sq2->str[j++], 0); 272} 273 274static inline int 275pool_isknownarch(Pool *pool, Id id) 276{ 277 if (!id || id == ID_EMPTY) 278 return 0; 279 if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH) 280 return 1; 281 if (!pool->id2arch || (id > pool->lastarch || !pool->id2arch[id])) 282 return 0; 283 return 1; 284} 285 286Id 287testcase_str2dep(Pool *pool, char *s) 288{ 289 char *n, *a; 290 Id id; 291 int flags; 292 293 if ((n = strchr(s, '|')) != 0) 294 { 295 id = testcase_str2dep(pool, n + 1); 296 *n = 0; 297 id = pool_rel2id(pool, testcase_str2dep(pool, s), id, REL_OR, 1); 298 *n = '|'; 299 return id; 300 } 301 while (*s == ' ' || *s == '\t') 302 s++; 303 n = s; 304 while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>') 305 { 306 if (*s == '(') 307 { 308 while (*s && *s != ')') 309 s++; 310 } 311 else 312 s++; 313 } 314 if ((a = strchr(n, '.')) != 0 && a + 1 < s && s[-1] != ')') 315 { 316 Id archid = pool_strn2id(pool, a + 1, s - (a + 1), 0); 317 if (pool_isknownarch(pool, archid)) 318 { 319 id = pool_strn2id(pool, n, a - n, 1); 320 id = pool_rel2id(pool, id, archid, REL_ARCH, 1); 321 } 322 else 323 id = pool_strn2id(pool, n, s - n, 1); 324 } 325 else 326 id = pool_strn2id(pool, n, s - n, 1); 327 if (!*s) 328 return id; 329 while (*s == ' ' || *s == '\t') 330 s++; 331 flags = 0; 332 for (;;s++) 333 { 334 if (*s == '<') 335 flags |= REL_LT; 336 else if (*s == '=') 337 flags |= REL_EQ; 338 else if (*s == '>') 339 flags |= REL_GT; 340 else 341 break; 342 } 343 if (!flags) 344 return id; 345 while (*s == ' ' || *s == '\t') 346 s++; 347 n = s; 348 while (*s && *s != ' ' && *s != '\t') 349 s++; 350 return pool_rel2id(pool, id, pool_strn2id(pool, n, s - n, 1), flags, 1); 351} 352 353const char * 354testcase_repoid2str(Pool *pool, Id repoid) 355{ 356 Repo *repo = pool_id2repo(pool, repoid); 357 if (repo->name) 358 { 359 char *r = pool_tmpjoin(pool, repo->name, 0, 0); 360 char *rp; 361 for (rp = r; *rp; rp++) 362 if (*rp == ' ' || *rp == '\t') 363 *rp = '_'; 364 return r; 365 } 366 else 367 { 368 char buf[20]; 369 sprintf(buf, "#%d", repoid); 370 return pool_tmpjoin(pool, buf, 0, 0); 371 } 372} 373 374const char * 375testcase_solvid2str(Pool *pool, Id p) 376{ 377 Solvable *s = pool->solvables + p; 378 const char *n, *e, *a; 379 char *str, buf[20]; 380 381 if (p == SYSTEMSOLVABLE) 382 return "@SYSTEM"; 383 n = pool_id2str(pool, s->name); 384 e = pool_id2str(pool, s->evr); 385 a = pool_id2str(pool, s->arch); 386 str = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3); 387 sprintf(str, "%s-%s.%s", n, e, a); 388 if (!s->repo) 389 return pool_tmpappend(pool, str, "@", 0); 390 if (s->repo->name) 391 { 392 int l = strlen(str); 393 char *str2 = pool_tmpappend(pool, str, "@", s->repo->name); 394 for (; str2[l]; l++) 395 if (str2[l] == ' ' || str2[l] == '\t') 396 str2[l] = '_'; 397 return str2; 398 } 399 sprintf(buf, "@#%d", s->repo->repoid); 400 return pool_tmpappend(pool, str, buf, 0); 401} 402 403Repo * 404testcase_str2repo(Pool *pool, const char *str) 405{ 406 int repoid; 407 Repo *repo = 0; 408 if (str[0] == '#' && (str[1] >= '0' && str[1] <= '9')) 409 { 410 int j; 411 repoid = 0; 412 for (j = 1; str[j] >= '0' && str[j] <= '9'; j++) 413 repoid = repoid * 10 + (str[j] - '0'); 414 if (!str[j] && repoid > 0 && repoid < pool->nrepos) 415 repo = pool_id2repo(pool, repoid); 416 } 417 if (!repo) 418 { 419 FOR_REPOS(repoid, repo) 420 { 421 int i, l; 422 if (!repo->name) 423 continue; 424 l = strlen(repo->name); 425 for (i = 0; i < l; i++) 426 { 427 int c = repo->name[i]; 428 if (c == ' ' || c == '\t') 429 c = '_'; 430 if (c != str[i]) 431 break; 432 } 433 if (i == l && !str[l]) 434 break; 435 } 436 if (repoid >= pool->nrepos) 437 repo = 0; 438 } 439 return repo; 440} 441 442Id 443testcase_str2solvid(Pool *pool, const char *str) 444{ 445 int i, l = strlen(str); 446 int repostart; 447 Repo *repo; 448 Id arch; 449 450 if (!l) 451 return 0; 452 if (*str == '@' && !strcmp(str, "@SYSTEM")) 453 return SYSTEMSOLVABLE; 454 repo = 0; 455 for (i = l - 1; i >= 0; i--) 456 if (str[i] == '@' && (repo = testcase_str2repo(pool, str + i + 1)) != 0) 457 break; 458 if (i < 0) 459 i = l; 460 repostart = i; 461 /* now find the arch (if present) */ 462 arch = 0; 463 for (i = repostart - 1; i > 0; i--) 464 if (str[i] == '.') 465 { 466 arch = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0); 467 if (arch) 468 repostart = i; 469 break; 470 } 471 /* now find the name */ 472 for (i = repostart - 1; i > 0; i--) 473 { 474 if (str[i] == '-') 475 { 476 Id nid, evrid, p, pp; 477 nid = pool_strn2id(pool, str, i, 0); 478 if (!nid) 479 continue; 480 evrid = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0); 481 if (!evrid) 482 continue; 483 FOR_PROVIDES(p, pp, nid) 484 { 485 Solvable *s = pool->solvables + p; 486 if (s->name != nid || s->evr != evrid) 487 continue; 488 if (repo && s->repo != repo) 489 continue; 490 if (arch && s->arch != arch) 491 continue; 492 return p; 493 } 494 } 495 } 496 return 0; 497} 498 499const char * 500testcase_job2str(Pool *pool, Id how, Id what) 501{ 502 char *ret; 503 const char *jobstr; 504 const char *selstr; 505 const char *pkgstr; 506 int i, o; 507 Id select = how & SOLVER_SELECTMASK; 508 509 for (i = 0; job2str[i].str; i++) 510 if ((how & SOLVER_JOBMASK) == job2str[i].job) 511 break; 512 jobstr = job2str[i].str ? job2str[i].str : "unknown"; 513 if (select == SOLVER_SOLVABLE) 514 { 515 selstr = " pkg "; 516 pkgstr = testcase_solvid2str(pool, what); 517 } 518 else if (select == SOLVER_SOLVABLE_NAME) 519 { 520 selstr = " name "; 521 pkgstr = pool_dep2str(pool, what); 522 } 523 else if (select == SOLVER_SOLVABLE_PROVIDES) 524 { 525 selstr = " provides "; 526 pkgstr = pool_dep2str(pool, what); 527 } 528 else if (select == SOLVER_SOLVABLE_ONE_OF) 529 { 530 Id p; 531 selstr = " oneof "; 532 pkgstr = 0; 533 while ((p = pool->whatprovidesdata[what++]) != 0) 534 { 535 const char *s = testcase_solvid2str(pool, p); 536 if (pkgstr) 537 { 538 pkgstr = pool_tmpappend(pool, pkgstr, " ", s); 539 pool_freetmpspace(pool, s); 540 } 541 else 542 pkgstr = s; 543 } 544 if (!pkgstr) 545 pkgstr = "nothing"; 546 } 547 else if (select == SOLVER_SOLVABLE_REPO) 548 { 549 Repo *repo = pool_id2repo(pool, what); 550 selstr = " repo "; 551 if (!repo->name) 552 { 553 char buf[20]; 554 sprintf(buf, "#%d", repo->repoid); 555 pkgstr = pool_tmpjoin(pool, buf, 0, 0); 556 } 557 else 558 pkgstr = pool_tmpjoin(pool, repo->name, 0, 0); 559 } 560 else if (select == SOLVER_SOLVABLE_ALL) 561 { 562 selstr = " all "; 563 pkgstr = "packages"; 564 } 565 else 566 { 567 selstr = " unknown "; 568 pkgstr = "unknown"; 569 } 570 ret = pool_tmpjoin(pool, jobstr, selstr, pkgstr); 571 o = strlen(ret); 572 ret = pool_tmpappend(pool, ret, " ", 0); 573 for (i = 0; jobflags2str[i].str; i++) 574 if ((how & jobflags2str[i].flag) != 0) 575 ret = pool_tmpappend(pool, ret, ",", jobflags2str[i].str); 576 if (!ret[o + 1]) 577 ret[o] = 0; 578 else 579 { 580 ret[o + 1] = '['; 581 ret = pool_tmpappend(pool, ret, "]", 0); 582 } 583 return ret; 584} 585 586static int 587str2selflags(Pool *pool, char *s) /* modifies the string! */ 588{ 589 int i, selflags = 0; 590 while (s) 591 { 592 char *se = strchr(s, ','); 593 if (se) 594 *se++ = 0; 595 for (i = 0; selflags2str[i].str; i++) 596 if (!strcmp(s, selflags2str[i].str)) 597 { 598 selflags |= selflags2str[i].flag; 599 break; 600 } 601 if (!selflags2str[i].str) 602 pool_debug(pool, SOLV_ERROR, "str2job: unknown selection flag '%s'\n", s); 603 s = se; 604 } 605 return selflags; 606} 607 608static int 609str2jobflags(Pool *pool, char *s) /* modifies the string */ 610{ 611 int i, jobflags = 0; 612 while (s) 613 { 614 char *se = strchr(s, ','); 615 if (se) 616 *se++ = 0; 617 for (i = 0; jobflags2str[i].str; i++) 618 if (!strcmp(s, jobflags2str[i].str)) 619 { 620 jobflags |= jobflags2str[i].flag; 621 break; 622 } 623 if (!jobflags2str[i].str) 624 pool_debug(pool, SOLV_ERROR, "str2job: unknown job flag '%s'\n", s); 625 s = se; 626 } 627 return jobflags; 628} 629 630Id 631testcase_str2job(Pool *pool, const char *str, Id *whatp) 632{ 633 int i; 634 Id job; 635 Id what; 636 char *s; 637 char **pieces = 0; 638 int npieces = 0; 639 640 *whatp = 0; 641 /* so we can patch it */ 642 s = pool_tmpjoin(pool, str, 0, 0); 643 /* split it in pieces */ 644 for (;;) 645 { 646 while (*s == ' ' || *s == '\t') 647 s++; 648 if (!*s) 649 break; 650 pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7); 651 pieces[npieces++] = s; 652 while (*s && *s != ' ' && *s != '\t') 653 s++; 654 if (*s) 655 *s++ = 0; 656 } 657 if (npieces < 3) 658 { 659 pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str); 660 solv_free(pieces); 661 return -1; 662 } 663 664 for (i = 0; job2str[i].str; i++) 665 if (!strcmp(pieces[0], job2str[i].str)) 666 break; 667 if (!job2str[i].str) 668 { 669 pool_debug(pool, SOLV_ERROR, "str2job: unknown job '%s'\n", str); 670 solv_free(pieces); 671 return -1; 672 } 673 job = job2str[i].job; 674 what = 0; 675 if (npieces > 3) 676 { 677 char *flags = pieces[npieces - 1]; 678 if (*flags == '[' && flags[strlen(flags) - 1] == ']') 679 { 680 npieces--; 681 flags++; 682 flags[strlen(flags) - 1] = 0; 683 job |= str2jobflags(pool, flags); 684 } 685 } 686 if (!strcmp(pieces[1], "pkg")) 687 { 688 if (npieces != 3) 689 { 690 pool_debug(pool, SOLV_ERROR, "str2job: bad pkg selector in '%s'\n", str); 691 solv_free(pieces); 692 return -1; 693 } 694 job |= SOLVER_SOLVABLE; 695 what = testcase_str2solvid(pool, pieces[2]); 696 if (!what) 697 { 698 pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[2]); 699 solv_free(pieces); 700 return -1; 701 } 702 } 703 else if (!strcmp(pieces[1], "name") || !strcmp(pieces[1], "provides")) 704 { 705 /* join em again for dep2str... */ 706 char *sp; 707 for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++) 708 if (*sp == 0) 709 *sp = ' '; 710 what = 0; 711 if (pieces[1][0] == 'p' && strncmp(pieces[2], "namespace:", 10) == 0) 712 { 713 char *spe = strchr(pieces[2], '('); 714 int l = strlen(pieces[2]); 715 if (spe && pieces[2][l - 1] == ')') 716 { 717 /* special namespace provides */ 718 if (strcmp(spe, "(<NULL>)") != 0) 719 { 720 pieces[2][l - 1] = 0; 721 what = testcase_str2dep(pool, spe + 1); 722 pieces[2][l - 1] = ')'; 723 } 724 what = pool_rel2id(pool, pool_strn2id(pool, pieces[2], spe - pieces[2], 1), what, REL_NAMESPACE, 1); 725 } 726 } 727 if (!what) 728 what = testcase_str2dep(pool, pieces[2]); 729 if (pieces[1][0] == 'n') 730 job |= SOLVER_SOLVABLE_NAME; 731 else 732 job |= SOLVER_SOLVABLE_PROVIDES; 733 } 734 else if (!strcmp(pieces[1], "oneof")) 735 { 736 Queue q; 737 job |= SOLVER_SOLVABLE_ONE_OF; 738 queue_init(&q); 739 if (npieces > 3 && strcmp(pieces[2], "nothing") != 0) 740 { 741 for (i = 2; i < npieces; i++) 742 { 743 Id p = testcase_str2solvid(pool, pieces[i]); 744 if (!p) 745 { 746 pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[i]); 747 queue_free(&q); 748 solv_free(pieces); 749 return -1; 750 } 751 queue_push(&q, p); 752 } 753 } 754 what = pool_queuetowhatprovides(pool, &q); 755 queue_free(&q); 756 } 757 else if (!strcmp(pieces[1], "repo")) 758 { 759 Repo *repo; 760 if (npieces != 3) 761 { 762 pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str); 763 solv_free(pieces); 764 return -1; 765 } 766 repo = testcase_str2repo(pool, pieces[2]); 767 if (!repo) 768 { 769 pool_debug(pool, SOLV_ERROR, "str2job: unknown repo '%s'\n", pieces[2]); 770 solv_free(pieces); 771 return -1; 772 } 773 job |= SOLVER_SOLVABLE_REPO; 774 what = repo->repoid; 775 } 776 else if (!strcmp(pieces[1], "all")) 777 { 778 if (npieces != 3 && strcmp(pieces[2], "packages") != 0) 779 { 780 pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str); 781 solv_free(pieces); 782 return -1; 783 } 784 job |= SOLVER_SOLVABLE_ALL; 785 what = 0; 786 } 787 else 788 { 789 pool_debug(pool, SOLV_ERROR, "str2job: unknown selection in '%s'\n", str); 790 solv_free(pieces); 791 return -1; 792 } 793 *whatp = what; 794 solv_free(pieces); 795 return job; 796} 797 798int 799addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue) 800{ 801 Id job; 802 int i, r; 803 int selflags; 804 Queue sel; 805 806 for (i = 0; job2str[i].str; i++) 807 if (!strcmp(pieces[0], job2str[i].str)) 808 break; 809 if (!job2str[i].str) 810 { 811 pool_debug(pool, SOLV_ERROR, "selstr2job: unknown job '%s'\n", pieces[0]); 812 return -1; 813 } 814 job = job2str[i].job; 815 if (npieces > 3) 816 { 817 char *flags = pieces[npieces - 1]; 818 if (*flags == '[' && flags[strlen(flags) - 1] == ']') 819 { 820 npieces--; 821 flags++; 822 flags[strlen(flags) - 1] = 0; 823 job |= str2jobflags(pool, flags); 824 } 825 } 826 if (npieces < 4) 827 { 828 pool_debug(pool, SOLV_ERROR, "selstr2job: no selection flags\n"); 829 return -1; 830 } 831 selflags = str2selflags(pool, pieces[3]); 832 queue_init(&sel); 833 r = selection_make(pool, &sel, pieces[2], selflags); 834 for (i = 0; i < sel.count; i += 2) 835 queue_push2(jobqueue, job | sel.elements[i], sel.elements[i + 1]); 836 queue_free(&sel); 837 return r; 838} 839 840static void 841writedeps(Repo *repo, FILE *fp, const char *tag, Id key, Solvable *s, Offset off) 842{ 843 Pool *pool = repo->pool; 844 Id id, *dp, *prvdp; 845 int tagwritten = 0; 846 const char *idstr; 847 848 if (!off) 849 return; 850 dp = repo->idarraydata + off; 851 prvdp = 0; 852 while ((id = *dp++) != 0) 853 { 854 if (key == SOLVABLE_REQUIRES && id == SOLVABLE_PREREQMARKER) 855 { 856 if (tagwritten) 857 fprintf(fp, "-%s\n", tag); 858 tagwritten = 0; 859 tag = "Prq:"; 860 continue; 861 } 862 if (key == SOLVABLE_PROVIDES && id == SOLVABLE_FILEMARKER) 863 { 864 prvdp = dp; 865 continue; 866 } 867 idstr = pool_dep2str(pool, id); 868 if (ISRELDEP(id)) 869 { 870 Reldep *rd = GETRELDEP(pool, id); 871 if (key == SOLVABLE_CONFLICTS && rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS) 872 { 873 if (!strncmp(idstr, "namespace:", 10)) 874 idstr += 10; 875 } 876 if (key == SOLVABLE_SUPPLEMENTS) 877 { 878 if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_FILESYSTEM) 879 { 880 if (!strncmp(idstr, "namespace:", 10)) 881 idstr += 10; 882 } 883 else if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_MODALIAS) 884 { 885 if (!strncmp(idstr, "namespace:", 10)) 886 idstr += 10; 887 } 888 else if (rd->flags == REL_AND) 889 { 890 /* either packageand chain or modalias */ 891 idstr = 0; 892 if (ISRELDEP(rd->evr)) 893 { 894 Reldep *mrd = GETRELDEP(pool, rd->evr); 895 if (mrd->flags == REL_NAMESPACE && mrd->name == NAMESPACE_MODALIAS) 896 { 897 idstr = pool_tmpjoin(pool, "modalias(", pool_dep2str(pool, rd->name), ":"); 898 idstr = pool_tmpappend(pool, idstr, pool_dep2str(pool, mrd->evr), ")"); 899 } 900 else if (mrd->flags >= 8) 901 continue; 902 } 903 if (!idstr) 904 { 905 /* must be and chain */ 906 idstr = pool_dep2str(pool, rd->evr); 907 for (;;) 908 { 909 id = rd->name; 910 if (!ISRELDEP(id)) 911 break; 912 rd = GETRELDEP(pool, id); 913 if (rd->flags != REL_AND) 914 break; 915 idstr = pool_tmpjoin(pool, pool_dep2str(pool, rd->evr), ":", idstr); 916 } 917 idstr = pool_tmpjoin(pool, pool_dep2str(pool, id), ":", idstr); 918 idstr = pool_tmpjoin(pool, "packageand(", idstr, ")"); 919 } 920 } 921 else if (rd->flags >= 8) 922 continue; 923 } 924 } 925 if (!tagwritten) 926 { 927 fprintf(fp, "+%s\n", tag); 928 tagwritten = 1; 929 } 930 fprintf(fp, "%s\n", idstr); 931 } 932 if (key == SOLVABLE_PROVIDES) 933 { 934 /* add the filelist */ 935 Dataiterator di; 936 dataiterator_init(&di, pool, repo, s - pool->solvables, SOLVABLE_FILELIST, 0, 0); 937 while (dataiterator_step(&di)) 938 { 939 const char *s = repodata_dir2str(di.data, di.kv.id, di.kv.str); 940 if (prvdp) 941 { 942 Id id = pool_str2id(pool, s, 0); 943 if (id) 944 { 945 for (dp = prvdp; *dp; dp++) 946 if (*dp == id) 947 break; 948 if (*dp) 949 continue; /* already included */ 950 } 951 } 952 if (!tagwritten) 953 { 954 fprintf(fp, "+%s", tag); 955 tagwritten = 1; 956 } 957 fprintf(fp, "%s\n", s); 958 } 959 } 960 if (tagwritten) 961 fprintf(fp, "-%s\n", tag); 962} 963 964int 965testcase_write_testtags(Repo *repo, FILE *fp) 966{ 967 Pool *pool = repo->pool; 968 Solvable *s; 969 Id p; 970 const char *name; 971 const char *evr; 972 const char *arch; 973 const char *release; 974 const char *tmp; 975 unsigned int ti; 976 977 fprintf(fp, "=Ver: 2.0\n"); 978 FOR_REPO_SOLVABLES(repo, p, s) 979 { 980 name = pool_id2str(pool, s->name); 981 evr = pool_id2str(pool, s->evr); 982 arch = pool_id2str(pool, s->arch); 983 release = strrchr(evr, '-'); 984 if (!release) 985 release = evr + strlen(evr); 986 fprintf(fp, "=Pkg: %s %.*s %s %s\n", name, (int)(release - evr), evr, *release && release[1] ? release + 1 : "-", arch); 987 tmp = solvable_lookup_str(s, SOLVABLE_SUMMARY); 988 if (tmp) 989 fprintf(fp, "=Sum: %s\n", tmp); 990 writedeps(repo, fp, "Req:", SOLVABLE_REQUIRES, s, s->requires); 991 writedeps(repo, fp, "Prv:", SOLVABLE_PROVIDES, s, s->provides); 992 writedeps(repo, fp, "Obs:", SOLVABLE_OBSOLETES, s, s->obsoletes); 993 writedeps(repo, fp, "Con:", SOLVABLE_CONFLICTS, s, s->conflicts); 994 writedeps(repo, fp, "Rec:", SOLVABLE_RECOMMENDS, s, s->recommends); 995 writedeps(repo, fp, "Sup:", SOLVABLE_SUPPLEMENTS, s, s->supplements); 996 writedeps(repo, fp, "Sug:", SOLVABLE_SUGGESTS, s, s->suggests); 997 writedeps(repo, fp, "Enh:", SOLVABLE_ENHANCES, s, s->enhances); 998 if (s->vendor) 999 fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor)); 1000 ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0); 1001 if (ti) 1002 fprintf(fp, "=Tim: %u\n", ti); 1003 } 1004 return 0; 1005} 1006 1007static inline Offset 1008adddep(Repo *repo, Offset olddeps, char *str, Id marker) 1009{ 1010 Id id = *str == '/' ? pool_str2id(repo->pool, str, 1) : testcase_str2dep(repo->pool, str); 1011 return repo_addid_dep(repo, olddeps, id, marker); 1012} 1013 1014static void 1015finish_solvable(Pool *pool, Repodata *data, Solvable *s, char *filelist, int nfilelist) 1016{ 1017 if (nfilelist) 1018 { 1019 int l; 1020 Id did; 1021 for (l = 0; l < nfilelist; l += strlen(filelist + l) + 1) 1022 { 1023 char *p = strrchr(filelist + l, '/'); 1024 if (!p) 1025 continue; 1026 *p++ = 0; 1027 did = repodata_str2dir(data, filelist + l, 1); 1028 p[-1] = '/'; 1029 if (!did) 1030 did = repodata_str2dir(data, "/", 1); 1031 repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, did, p); 1032 } 1033 } 1034 if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) 1035 s->provides = repo_addid_dep(s->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); 1036 s->supplements = repo_fix_supplements(s->repo, s->provides, s->supplements, 0); 1037 s->conflicts = repo_fix_conflicts(s->repo, s->conflicts); 1038} 1039 1040/* stripped down version of susetags parser used for testcases */ 1041int 1042testcase_add_testtags(Repo *repo, FILE *fp, int flags) 1043{ 1044 Pool *pool = repo->pool; 1045 char *line, *linep; 1046 int aline; 1047 int tag; 1048 Repodata *data; 1049 Solvable *s; 1050 char *sp[5]; 1051 unsigned int t; 1052 int intag; 1053 char *filelist = 0; 1054 int afilelist = 0; 1055 int nfilelist = 0; 1056 1057 data = repo_add_repodata(repo, flags); 1058 s = 0; 1059 intag = 0; 1060 1061 aline = 1024; 1062 line = solv_malloc(aline); 1063 linep = line; 1064 for (;;) 1065 { 1066 if (linep - line + 16 > aline) 1067 { 1068 aline = linep - line; 1069 line = solv_realloc(line, aline + 512); 1070 linep = line + aline; 1071 aline += 512; 1072 } 1073 if (!fgets(linep, aline - (linep - line), fp)) 1074 break; 1075 linep += strlen(linep); 1076 if (linep == line || linep[-1] != '\n') 1077 continue; 1078 *--linep = 0; 1079 linep = line + intag; 1080 if (intag) 1081 { 1082 if (line[intag] == '-' && !strncmp(line + 1, line + intag + 1, intag - 2)) 1083 { 1084 intag = 0; 1085 linep = line; 1086 continue; 1087 } 1088 } 1089 else if (line[0] == '+' && line[1] && line[1] != ':') 1090 { 1091 char *tagend = strchr(line, ':'); 1092 if (!tagend) 1093 continue; 1094 line[0] = '='; 1095 tagend[1] = ' '; 1096 intag = tagend + 2 - line; 1097 linep = line + intag; 1098 continue; 1099 } 1100 if (*line != '=' || !line[1] || !line[2] || !line[3] || line[4] != ':') 1101 continue; 1102 tag = line[1] << 16 | line[2] << 8 | line[3]; 1103 switch(tag) 1104 { 1105 case 'P' << 16 | 'k' << 8 | 'g': 1106 if (s) 1107 finish_solvable(pool, data, s, filelist, nfilelist); 1108 nfilelist = 0; 1109 if (split(line + 5, sp, 5) != 4) 1110 break; 1111 s = pool_id2solvable(pool, repo_add_solvable(repo)); 1112 s->name = pool_str2id(pool, sp[0], 1); 1113 /* join back version and release */ 1114 if (sp[2] && !(sp[2][0] == '-' && !sp[2][1])) 1115 sp[2][-1] = '-'; 1116 s->evr = makeevr(pool, sp[1]); 1117 s->arch = pool_str2id(pool, sp[3], 1); 1118 break; 1119 case 'S' << 16 | 'u' << 8 | 'm': 1120 repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 6); 1121 break; 1122 case 'V' << 16 | 'n' << 8 | 'd': 1123 s->vendor = pool_str2id(pool, line + 6, 1); 1124 break; 1125 case 'T' << 16 | 'i' << 8 | 'm': 1126 t = atoi(line + 6); 1127 if (t) 1128 repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, t); 1129 break; 1130 case 'R' << 16 | 'e' << 8 | 'q': 1131 s->requires = adddep(repo, s->requires, line + 6, -SOLVABLE_PREREQMARKER); 1132 break; 1133 case 'P' << 16 | 'r' << 8 | 'q': 1134 s->requires = adddep(repo, s->requires, line + 6, SOLVABLE_PREREQMARKER); 1135 break; 1136 case 'P' << 16 | 'r' << 8 | 'v': 1137 if (line[6] == '/') 1138 { 1139 int l = strlen(line + 6) + 1; 1140 if (nfilelist + l > afilelist) 1141 { 1142 afilelist = nfilelist + l + 512; 1143 filelist = solv_realloc(filelist, afilelist); 1144 } 1145 memcpy(filelist + nfilelist, line + 6, l); 1146 nfilelist += l; 1147 break; 1148 } 1149 if (nfilelist) 1150 { 1151 int l; 1152 for (l = 0; l < nfilelist; l += strlen(filelist + l) + 1) 1153 s->provides = repo_addid_dep(repo, s->provides, pool_str2id(pool, filelist + l, 1), 0); 1154 nfilelist = 0; 1155 } 1156 s->provides = adddep(repo, s->provides, line + 6, 0); 1157 break; 1158 case 'O' << 16 | 'b' << 8 | 's': 1159 s->obsoletes = adddep(repo, s->obsoletes, line + 6, 0); 1160 break; 1161 case 'C' << 16 | 'o' << 8 | 'n': 1162 s->conflicts = adddep(repo, s->conflicts, line + 6, 0); 1163 break; 1164 case 'R' << 16 | 'e' << 8 | 'c': 1165 s->recommends = adddep(repo, s->recommends, line + 6, 0); 1166 break; 1167 case 'S' << 16 | 'u' << 8 | 'p': 1168 s->supplements = adddep(repo, s->supplements, line + 6, 0); 1169 break; 1170 case 'S' << 16 | 'u' << 8 | 'g': 1171 s->suggests = adddep(repo, s->suggests, line + 6, 0); 1172 break; 1173 case 'E' << 16 | 'n' << 8 | 'h': 1174 s->enhances = adddep(repo, s->enhances, line + 6, 0); 1175 break; 1176 default: 1177 break; 1178 } 1179 } 1180 if (s) 1181 finish_solvable(pool, data, s, filelist, nfilelist); 1182 solv_free(line); 1183 solv_free(filelist); 1184 repodata_free_dircache(data); 1185 if (!(flags & REPO_NO_INTERNALIZE)) 1186 repodata_internalize(data); 1187 return 0; 1188} 1189 1190const char * 1191testcase_getpoolflags(Pool *pool) 1192{ 1193 const char *str = 0; 1194 int i, v; 1195 for (i = 0; poolflags2str[i].str; i++) 1196 { 1197 v = pool_get_flag(pool, poolflags2str[i].flag); 1198 if (v == poolflags2str[i].def) 1199 continue; 1200 str = pool_tmpappend(pool, str, v ? " " : " !", poolflags2str[i].str); 1201 } 1202 return str ? str + 1 : ""; 1203} 1204 1205int 1206testcase_setpoolflags(Pool *pool, const char *str) 1207{ 1208 const char *p = str, *s; 1209 int i, v; 1210 for (;;) 1211 { 1212 while (*p == ' ' || *p == '\t' || *p == ',') 1213 p++; 1214 v = 1; 1215 if (*p == '!') 1216 { 1217 p++; 1218 v = 0; 1219 } 1220 if (!*p) 1221 break; 1222 s = p; 1223 while (*p && *p != ' ' && *p != '\t' && *p != ',') 1224 p++; 1225 for (i = 0; poolflags2str[i].str; i++) 1226 if (!strncmp(poolflags2str[i].str, s, p - s) && poolflags2str[i].str[p - s] == 0) 1227 break; 1228 if (!poolflags2str[i].str) 1229 { 1230 pool_debug(pool, SOLV_ERROR, "setpoolflags: unknown flag '%.*s'\n", (int)(p - s), s); 1231 return 0; 1232 } 1233 pool_set_flag(pool, poolflags2str[i].flag, v); 1234 } 1235 return 1; 1236} 1237 1238void 1239testcase_resetpoolflags(Pool *pool) 1240{ 1241 int i; 1242 for (i = 0; poolflags2str[i].str; i++) 1243 pool_set_flag(pool, poolflags2str[i].flag, poolflags2str[i].def); 1244} 1245 1246const char * 1247testcase_getsolverflags(Solver *solv) 1248{ 1249 Pool *pool = solv->pool; 1250 const char *str = 0; 1251 int i, v; 1252 for (i = 0; solverflags2str[i].str; i++) 1253 { 1254 v = solver_get_flag(solv, solverflags2str[i].flag); 1255 if (v == solverflags2str[i].def) 1256 continue; 1257 str = pool_tmpappend(pool, str, v ? " " : " !", solverflags2str[i].str); 1258 } 1259 return str ? str + 1 : ""; 1260} 1261 1262int 1263testcase_setsolverflags(Solver *solv, const char *str) 1264{ 1265 const char *p = str, *s; 1266 int i, v; 1267 for (;;) 1268 { 1269 while (*p == ' ' || *p == '\t' || *p == ',') 1270 p++; 1271 v = 1; 1272 if (*p == '!') 1273 { 1274 p++; 1275 v = 0; 1276 } 1277 if (!*p) 1278 break; 1279 s = p; 1280 while (*p && *p != ' ' && *p != '\t' && *p != ',') 1281 p++; 1282 for (i = 0; solverflags2str[i].str; i++) 1283 if (!strncmp(solverflags2str[i].str, s, p - s) && solverflags2str[i].str[p - s] == 0) 1284 break; 1285 if (!solverflags2str[i].str) 1286 { 1287 pool_debug(solv->pool, SOLV_ERROR, "setsolverflags: unknown flag '%.*s'\n", (int)(p - s), s); 1288 return 0; 1289 } 1290 solver_set_flag(solv, solverflags2str[i].flag, v); 1291 } 1292 return 1; 1293} 1294 1295void 1296testcase_resetsolverflags(Solver *solv) 1297{ 1298 int i; 1299 for (i = 0; solverflags2str[i].str; i++) 1300 solver_set_flag(solv, solverflags2str[i].flag, solverflags2str[i].def); 1301} 1302 1303static const char * 1304testcase_ruleid(Solver *solv, Id rid) 1305{ 1306 Strqueue sq; 1307 Queue q; 1308 int i; 1309 void *chk; 1310 const unsigned char *md5; 1311 int md5l; 1312 const char *s; 1313 1314 queue_init(&q); 1315 strqueue_init(&sq); 1316 solver_ruleliterals(solv, rid, &q); 1317 for (i = 0; i < q.count; i++) 1318 { 1319 Id p = q.elements[i]; 1320 s = testcase_solvid2str(solv->pool, p > 0 ? p : -p); 1321 if (p < 0) 1322 s = pool_tmpjoin(solv->pool, "!", s, 0); 1323 strqueue_push(&sq, s); 1324 } 1325 queue_free(&q); 1326 strqueue_sort_u(&sq); 1327 chk = solv_chksum_create(REPOKEY_TYPE_MD5); 1328 for (i = 0; i < sq.nstr; i++) 1329 solv_chksum_add(chk, sq.str[i], strlen(sq.str[i]) + 1); 1330 md5 = solv_chksum_get(chk, &md5l); 1331 s = pool_bin2hex(solv->pool, md5, md5l); 1332 chk = solv_chksum_free(chk, 0); 1333 strqueue_free(&sq); 1334 return s; 1335} 1336 1337static const char * 1338testcase_problemid(Solver *solv, Id problem) 1339{ 1340 Strqueue sq; 1341 Queue q; 1342 void *chk; 1343 const unsigned char *md5; 1344 int i, md5l; 1345 const char *s; 1346 1347 /* we build a hash of all rules that define the problem */ 1348 queue_init(&q); 1349 strqueue_init(&sq); 1350 solver_findallproblemrules(solv, problem, &q); 1351 for (i = 0; i < q.count; i++) 1352 strqueue_push(&sq, testcase_ruleid(solv, q.elements[i])); 1353 queue_free(&q); 1354 strqueue_sort_u(&sq); 1355 chk = solv_chksum_create(REPOKEY_TYPE_MD5); 1356 for (i = 0; i < sq.nstr; i++) 1357 solv_chksum_add(chk, sq.str[i], strlen(sq.str[i]) + 1); 1358 md5 = solv_chksum_get(chk, &md5l); 1359 s = pool_bin2hex(solv->pool, md5, 4); 1360 chk = solv_chksum_free(chk, 0); 1361 strqueue_free(&sq); 1362 return s; 1363} 1364 1365static const char * 1366testcase_solutionid(Solver *solv, Id problem, Id solution) 1367{ 1368 Id intid; 1369 void *chk; 1370 const unsigned char *md5; 1371 int md5l; 1372 const char *s; 1373 1374 intid = solver_solutionelement_internalid(solv, problem, solution); 1375 /* internal stuff! handle with care! */ 1376 if (intid < 0) 1377 { 1378 /* it's a job */ 1379 s = testcase_job2str(solv->pool, solv->job.elements[-intid - 1], solv->job.elements[-intid]); 1380 } 1381 else 1382 { 1383 /* it's a rule */ 1384 s = testcase_ruleid(solv, intid); 1385 } 1386 chk = solv_chksum_create(REPOKEY_TYPE_MD5); 1387 solv_chksum_add(chk, s, strlen(s) + 1); 1388 md5 = solv_chksum_get(chk, &md5l); 1389 s = pool_bin2hex(solv->pool, md5, 4); 1390 chk = solv_chksum_free(chk, 0); 1391 return s; 1392} 1393 1394static struct class2str { 1395 Id class; 1396 const char *str; 1397} class2str[] = { 1398 { SOLVER_TRANSACTION_ERASE, "erase" }, 1399 { SOLVER_TRANSACTION_INSTALL, "install" }, 1400 { SOLVER_TRANSACTION_REINSTALLED, "reinstall" }, 1401 { SOLVER_TRANSACTION_DOWNGRADED, "downgrade" }, 1402 { SOLVER_TRANSACTION_CHANGED, "change" }, 1403 { SOLVER_TRANSACTION_UPGRADED, "upgrade" }, 1404 { SOLVER_TRANSACTION_OBSOLETED, "obsolete" }, 1405 { SOLVER_TRANSACTION_MULTIINSTALL, "multiinstall" }, 1406 { SOLVER_TRANSACTION_MULTIREINSTALL, "multireinstall" }, 1407 { 0, 0 } 1408}; 1409 1410char * 1411testcase_solverresult(Solver *solv, int resultflags) 1412{ 1413 Pool *pool = solv->pool; 1414 int i, j; 1415 Id p, op; 1416 const char *s; 1417 char *result; 1418 Strqueue sq; 1419 1420 strqueue_init(&sq); 1421 if ((resultflags & TESTCASE_RESULT_TRANSACTION) != 0) 1422 { 1423 Transaction *trans = solver_create_transaction(solv); 1424 Queue q; 1425 1426 queue_init(&q); 1427 for (i = 0; class2str[i].str; i++) 1428 { 1429 queue_empty(&q); 1430 transaction_classify_pkgs(trans, SOLVER_TRANSACTION_KEEP_PSEUDO, class2str[i].class, 0, 0, &q); 1431 for (j = 0; j < q.count; j++) 1432 { 1433 p = q.elements[j]; 1434 op = 0; 1435 if (pool->installed && pool->solvables[p].repo == pool->installed) 1436 op = transaction_obs_pkg(trans, p); 1437 s = pool_tmpjoin(pool, class2str[i].str, " ", testcase_solvid2str(pool, p)); 1438 if (op) 1439 s = pool_tmpjoin(pool, s, " ", testcase_solvid2str(pool, op)); 1440 strqueue_push(&sq, s); 1441 } 1442 } 1443 queue_free(&q); 1444 transaction_free(trans); 1445 } 1446 if ((resultflags & TESTCASE_RESULT_PROBLEMS) != 0) 1447 { 1448 char *probprefix, *solprefix; 1449 int problem, solution, element; 1450 int pcnt, scnt; 1451 1452 pcnt = solver_problem_count(solv); 1453 for (problem = 1; problem <= pcnt; problem++) 1454 { 1455 Id rid, from, to, dep; 1456 SolverRuleinfo rinfo; 1457 rid = solver_findproblemrule(solv, problem); 1458 s = testcase_problemid(solv, problem); 1459 probprefix = solv_dupjoin("problem ", s, 0); 1460 rinfo = solver_ruleinfo(solv, rid, &from, &to, &dep); 1461 s = pool_tmpjoin(pool, probprefix, " info ", solver_problemruleinfo2str(solv, rinfo, from, to, dep)); 1462 strqueue_push(&sq, s); 1463 scnt = solver_solution_count(solv, problem); 1464 for (solution = 1; solution <= scnt; solution++) 1465 { 1466 s = testcase_solutionid(solv, problem, solution); 1467 solprefix = solv_dupjoin(probprefix, " solution ", s); 1468 element = 0; 1469 while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &op)) != 0) 1470 { 1471 if (p == SOLVER_SOLUTION_JOB) 1472 s = pool_tmpjoin(pool, solprefix, " deljob ", testcase_job2str(pool, solv->job.elements[op - 1], solv->job.elements[op])); 1473 else if (p > 0 && op == 0) 1474 s = pool_tmpjoin(pool, solprefix, " erase ", testcase_solvid2str(pool, p)); 1475 else if (p > 0 && op > 0) 1476 { 1477 s = pool_tmpjoin(pool, solprefix, " replace ", testcase_solvid2str(pool, p)); 1478 s = pool_tmpappend(pool, s, " ", testcase_solvid2str(pool, op)); 1479 } 1480 else if (p < 0 && op > 0) 1481 s = pool_tmpjoin(pool, solprefix, " allow ", testcase_solvid2str(pool, op)); 1482 else 1483 s = pool_tmpjoin(pool, solprefix, " unknown", 0); 1484 strqueue_push(&sq, s); 1485 } 1486 solv_free(solprefix); 1487 } 1488 solv_free(probprefix); 1489 } 1490 } 1491 1492 if ((resultflags & TESTCASE_RESULT_ORPHANED) != 0) 1493 { 1494 Queue q; 1495 1496 queue_init(&q); 1497 solver_get_orphaned(solv, &q); 1498 for (i = 0; i < q.count; i++) 1499 { 1500 s = pool_tmpjoin(pool, "orphaned ", testcase_solvid2str(pool, q.elements[i]), 0); 1501 strqueue_push(&sq, s); 1502 } 1503 queue_free(&q); 1504 } 1505 1506 if ((resultflags & TESTCASE_RESULT_RECOMMENDED) != 0) 1507 { 1508 Queue qr, qs; 1509 1510 queue_init(&qr); 1511 queue_init(&qs); 1512 solver_get_recommendations(solv, &qr, &qs, 0); 1513 for (i = 0; i < qr.count; i++) 1514 { 1515 s = pool_tmpjoin(pool, "recommended ", testcase_solvid2str(pool, qr.elements[i]), 0); 1516 strqueue_push(&sq, s); 1517 } 1518 for (i = 0; i < qs.count; i++) 1519 { 1520 s = pool_tmpjoin(pool, "suggested ", testcase_solvid2str(pool, qs.elements[i]), 0); 1521 strqueue_push(&sq, s); 1522 } 1523 queue_free(&qr); 1524 queue_free(&qs); 1525 } 1526 1527 if ((resultflags & TESTCASE_RESULT_UNNEEDED) != 0) 1528 { 1529 Queue q; 1530 1531 queue_init(&q); 1532 solver_get_unneeded(solv, &q, 0); 1533 for (i = 0; i < q.count; i++) 1534 { 1535 s = pool_tmpjoin(pool, "unneeded ", testcase_solvid2str(pool, q.elements[i]), 0); 1536 strqueue_push(&sq, s); 1537 } 1538 queue_free(&q); 1539 } 1540 1541 strqueue_sort(&sq); 1542 result = strqueue_join(&sq); 1543 strqueue_free(&sq); 1544 return result; 1545} 1546 1547 1548int 1549testcase_write(Solver *solv, char *dir, int resultflags, const char *testcasename, const char *resultname) 1550{ 1551 Pool *pool = solv->pool; 1552 Repo *repo; 1553 int i; 1554 Id arch, repoid; 1555 Id lowscore; 1556 FILE *fp; 1557 Strqueue sq; 1558 char *cmd, *out; 1559 const char *s; 1560 1561 if (!testcasename) 1562 testcasename = "testcase.t"; 1563 if (!resultname) 1564 resultname = "solver.result"; 1565 1566 if (mkdir(dir, 0777) && errno != EEXIST) 1567 { 1568 pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not create directory '%s'\n", dir); 1569 return 0; 1570 } 1571 strqueue_init(&sq); 1572 FOR_REPOS(repoid, repo) 1573 { 1574 const char *name = testcase_repoid2str(pool, repoid); 1575 char priobuf[50]; 1576 if (repo->subpriority) 1577 sprintf(priobuf, "%d.%d", repo->priority, repo->subpriority); 1578 else 1579 sprintf(priobuf, "%d", repo->priority); 1580 out = pool_tmpjoin(pool, name, ".repo", ".gz"); 1581 cmd = pool_tmpjoin(pool, "repo ", name, " "); 1582 cmd = pool_tmpappend(pool, cmd, priobuf, " "); 1583 cmd = pool_tmpappend(pool, cmd, "testtags ", out); 1584 strqueue_push(&sq, cmd); 1585 out = pool_tmpjoin(pool, dir, "/", out); 1586 if (!(fp = solv_xfopen(out, "w"))) 1587 { 1588 pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out); 1589 strqueue_free(&sq); 1590 return 0; 1591 } 1592 testcase_write_testtags(repo, fp); 1593 if (fclose(fp)) 1594 { 1595 pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); 1596 strqueue_free(&sq); 1597 return 0; 1598 } 1599 } 1600 /* hmm, this is not optimal... we currently search for the lowest score */ 1601 lowscore = 0; 1602 arch = pool->solvables[SYSTEMSOLVABLE].arch; 1603 for (i = 0; i < pool->lastarch; i++) 1604 { 1605 if (pool->id2arch[i] == 1 && !lowscore) 1606 arch = i; 1607 if (pool->id2arch[i] > 0x10000 && (!lowscore || pool->id2arch[i] < lowscore)) 1608 { 1609 arch = i; 1610 lowscore = pool->id2arch[i]; 1611 } 1612 } 1613 cmd = pool_tmpjoin(pool, "system ", pool->lastarch ? pool_id2str(pool, arch) : "unset", 0); 1614 for (i = 0; disttype2str[i].str != 0; i++) 1615 if (pool->disttype == disttype2str[i].type) 1616 break; 1617 pool_tmpappend(pool, cmd, " ", disttype2str[i].str ? disttype2str[i].str : "unknown"); 1618 if (pool->installed) 1619 cmd = pool_tmpappend(pool, cmd, " ", testcase_repoid2str(pool, pool->installed->repoid)); 1620 strqueue_push(&sq, cmd); 1621 s = testcase_getpoolflags(solv->pool); 1622 if (*s) 1623 { 1624 cmd = pool_tmpjoin(pool, "poolflags ", s, 0); 1625 strqueue_push(&sq, cmd); 1626 } 1627 1628 if (pool->vendorclasses) 1629 { 1630 cmd = 0; 1631 for (i = 0; pool->vendorclasses[i]; i++) 1632 { 1633 cmd = pool_tmpappend(pool, cmd ? cmd : "vendorclass", " ", pool->vendorclasses[i]); 1634 if (!pool->vendorclasses[i + 1]) 1635 { 1636 strqueue_push(&sq, cmd); 1637 cmd = 0; 1638 i++; 1639 } 1640 } 1641 } 1642 1643 s = testcase_getsolverflags(solv); 1644 if (*s) 1645 { 1646 cmd = pool_tmpjoin(pool, "solverflags ", s, 0); 1647 strqueue_push(&sq, cmd); 1648 } 1649 1650 /* now dump all the ns callback values we know */ 1651 if (pool->nscallback) 1652 { 1653 Id rid; 1654 int d; 1655 for (rid = 1; rid < pool->nrels; rid++) 1656 { 1657 Reldep *rd = pool->rels + rid; 1658 if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS) 1659 continue; 1660 /* evaluate all namespace ids, skip empty results */ 1661 d = pool_whatprovides(pool, MAKERELDEP(rid)); 1662 if (!d || !pool->whatprovidesdata[d]) 1663 continue; 1664 cmd = pool_tmpjoin(pool, "namespace ", pool_id2str(pool, rd->name), "("); 1665 cmd = pool_tmpappend(pool, cmd, pool_id2str(pool, rd->evr), ")"); 1666 for (; pool->whatprovidesdata[d]; d++) 1667 cmd = pool_tmpappend(pool, cmd, " ", testcase_solvid2str(pool, pool->whatprovidesdata[d])); 1668 strqueue_push(&sq, cmd); 1669 } 1670 } 1671 1672 for (i = 0; i < solv->job.count; i += 2) 1673 { 1674 cmd = (char *)testcase_job2str(pool, solv->job.elements[i], solv->job.elements[i + 1]); 1675 cmd = pool_tmpjoin(pool, "job ", cmd, 0); 1676 strqueue_push(&sq, cmd); 1677 } 1678 1679 if (resultflags) 1680 { 1681 char *result; 1682 cmd = 0; 1683 for (i = 0; resultflags2str[i].str; i++) 1684 if ((resultflags & resultflags2str[i].flag) != 0) 1685 cmd = pool_tmpappend(pool, cmd, cmd ? "," : 0, resultflags2str[i].str); 1686 cmd = pool_tmpjoin(pool, "result ", cmd ? cmd : "?", 0); 1687 cmd = pool_tmpappend(pool, cmd, " ", resultname); 1688 strqueue_push(&sq, cmd); 1689 result = testcase_solverresult(solv, resultflags); 1690 if (!strcmp(resultname, "<inline>")) 1691 { 1692 int i; 1693 Strqueue rsq; 1694 strqueue_init(&rsq); 1695 strqueue_split(&rsq, result); 1696 for (i = 0; i < rsq.nstr; i++) 1697 { 1698 cmd = pool_tmpjoin(pool, "#>", rsq.str[i], 0); 1699 strqueue_push(&sq, cmd); 1700 } 1701 strqueue_free(&rsq); 1702 } 1703 else 1704 { 1705 out = pool_tmpjoin(pool, dir, "/", resultname); 1706 if (!(fp = fopen(out, "w"))) 1707 { 1708 pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out); 1709 solv_free(result); 1710 strqueue_free(&sq); 1711 return 0; 1712 } 1713 if (result && *result && fwrite(result, strlen(result), 1, fp) != 1) 1714 { 1715 pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); 1716 solv_free(result); 1717 strqueue_free(&sq); 1718 return 0; 1719 } 1720 if (fclose(fp)) 1721 { 1722 pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); 1723 strqueue_free(&sq); 1724 return 0; 1725 } 1726 } 1727 solv_free(result); 1728 } 1729 1730 cmd = strqueue_join(&sq); 1731 out = pool_tmpjoin(pool, dir, "/", testcasename); 1732 if (!(fp = fopen(out, "w"))) 1733 { 1734 pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out); 1735 strqueue_free(&sq); 1736 return 0; 1737 } 1738 if (*cmd && fwrite(cmd, strlen(cmd), 1, fp) != 1) 1739 { 1740 pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); 1741 strqueue_free(&sq); 1742 return 0; 1743 } 1744 if (fclose(fp)) 1745 { 1746 pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); 1747 strqueue_free(&sq); 1748 return 0; 1749 } 1750 solv_free(cmd); 1751 strqueue_free(&sq); 1752 return 1; 1753} 1754 1755static char * 1756read_inline_file(FILE *fp, char **bufp, char **bufpp, int *buflp) 1757{ 1758 char *result = solv_malloc(1024); 1759 char *rp = result; 1760 int resultl = 1024; 1761 1762 for (;;) 1763 { 1764 size_t rl; 1765 if (rp - result + 256 >= resultl) 1766 { 1767 resultl = rp - result; 1768 result = solv_realloc(result, resultl + 1024); 1769 rp = result + resultl; 1770 resultl += 1024; 1771 } 1772 if (!fgets(rp, resultl - (rp - result), fp)) 1773 *rp = 0; 1774 rl = strlen(rp); 1775 if (rl && (rp == result || rp[-1] == '\n')) 1776 { 1777 if (rl > 1 && rp[0] == '#' && rp[1] == '>') 1778 { 1779 memmove(rp, rp + 2, rl - 2); 1780 rl -= 2; 1781 } 1782 else 1783 { 1784 while (rl + 16 > *buflp) 1785 { 1786 *bufp = solv_realloc(*bufp, *buflp + 512); 1787 *buflp += 512; 1788 } 1789 memmove(*bufp, rp, rl); 1790 if ((*bufp)[rl - 1] == '\n') 1791 { 1792 ungetc('\n', fp); 1793 rl--; 1794 } 1795 (*bufp)[rl] = 0; 1796 (*bufpp) = *bufp + rl; 1797 rl = 0; 1798 } 1799 } 1800 if (rl <= 0) 1801 { 1802 *rp = 0; 1803 break; 1804 } 1805 rp += rl; 1806 } 1807 return result; 1808} 1809 1810static char * 1811read_file(FILE *fp) 1812{ 1813 char *result = solv_malloc(1024); 1814 char *rp = result; 1815 int resultl = 1024; 1816 1817 for (;;) 1818 { 1819 size_t rl; 1820 if (rp - result + 256 >= resultl) 1821 { 1822 resultl = rp - result; 1823 result = solv_realloc(result, resultl + 1024); 1824 rp = result + resultl; 1825 resultl += 1024; 1826 } 1827 rl = fread(rp, 1, resultl - (rp - result), fp); 1828 if (rl <= 0) 1829 { 1830 *rp = 0; 1831 break; 1832 } 1833 rp += rl; 1834 } 1835 return result; 1836} 1837 1838static int 1839str2resultflags(Pool *pool, char *s) /* modifies the string! */ 1840{ 1841 int i, resultflags = 0; 1842 while (s) 1843 { 1844 char *se = strchr(s, ','); 1845 if (se) 1846 *se++ = 0; 1847 for (i = 0; resultflags2str[i].str; i++) 1848 if (!strcmp(s, resultflags2str[i].str)) 1849 { 1850 resultflags |= resultflags2str[i].flag; 1851 break; 1852 } 1853 if (!resultflags2str[i].str) 1854 pool_debug(pool, SOLV_ERROR, "result: unknown flag '%s'\n", s); 1855 s = se; 1856 } 1857 return resultflags; 1858} 1859 1860Solver * 1861testcase_read(Pool *pool, FILE *fp, char *testcase, Queue *job, char **resultp, int *resultflagsp) 1862{ 1863 Solver *solv; 1864 char *buf, *bufp; 1865 int bufl; 1866 char *testcasedir, *s; 1867 int l; 1868 char **pieces = 0; 1869 int npieces = 0; 1870 int prepared = 0; 1871 int closefp = !fp; 1872 int poolflagsreset = 0; 1873 1874 if (!fp && !(fp = fopen(testcase, "r"))) 1875 { 1876 pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", testcase); 1877 return 0; 1878 } 1879 testcasedir = solv_strdup(testcase); 1880 if ((s = strrchr(testcasedir, '/')) != 0) 1881 s[1] = 0; 1882 else 1883 *testcasedir = 0; 1884 bufl = 1024; 1885 buf = solv_malloc(bufl); 1886 bufp = buf; 1887 solv = 0; 1888 for (;;) 1889 { 1890 if (bufp - buf + 16 > bufl) 1891 { 1892 bufl = bufp - buf; 1893 buf = solv_realloc(buf, bufl + 512); 1894 bufp = buf + bufl; 1895 bufl += 512; 1896 } 1897 if (!fgets(bufp, bufl - (bufp - buf), fp)) 1898 break; 1899 bufp = buf; 1900 l = strlen(buf); 1901 if (!l || buf[l - 1] != '\n') 1902 { 1903 bufp += l; 1904 continue; 1905 } 1906 buf[--l] = 0; 1907 s = buf; 1908 while (*s && (*s == ' ' || *s == '\t')) 1909 s++; 1910 if (!*s || *s == '#') 1911 continue; 1912 npieces = 0; 1913 /* split it in pieces */ 1914 for (;;) 1915 { 1916 while (*s == ' ' || *s == '\t') 1917 s++; 1918 if (!*s) 1919 break; 1920 pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7); 1921 pieces[npieces++] = s; 1922 while (*s && *s != ' ' && *s != '\t') 1923 s++; 1924 if (*s) 1925 *s++ = 0; 1926 } 1927 pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7); 1928 pieces[npieces] = 0; 1929 if (!strcmp(pieces[0], "repo") && npieces >= 4) 1930 { 1931 Repo *repo = repo_create(pool, pieces[1]); 1932 FILE *rfp; 1933 int prio, subprio; 1934 const char *rdata; 1935 1936 prepared = 0; 1937 if (!poolflagsreset) 1938 { 1939 poolflagsreset = 1; 1940 testcase_resetpoolflags(pool); /* hmm */ 1941 } 1942 if (sscanf(pieces[2], "%d.%d", &prio, &subprio) != 2) 1943 { 1944 subprio = 0; 1945 prio = atoi(pieces[2]); 1946 } 1947 repo->priority = prio; 1948 repo->subpriority = subprio; 1949 if (strcmp(pieces[3], "empty") != 0) 1950 { 1951 const char *repotype = pool_tmpjoin(pool, pieces[3], 0, 0); /* gets overwritten in <inline> case */ 1952 if (!strcmp(pieces[4], "<inline>")) 1953 { 1954 char *idata = read_inline_file(fp, &buf, &bufp, &bufl); 1955 rdata = "<inline>"; 1956 rfp = solv_xfopen_buf(rdata, &idata, 0, "rf"); 1957 } 1958 else 1959 { 1960 rdata = pool_tmpjoin(pool, testcasedir, pieces[4], 0); 1961 rfp = solv_xfopen(rdata, "r"); 1962 } 1963 if (!rfp) 1964 { 1965 pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", rdata); 1966 } 1967 else if (!strcmp(repotype, "testtags")) 1968 { 1969 testcase_add_testtags(repo, rfp, 0); 1970 fclose(rfp); 1971 } 1972 else if (!strcmp(repotype, "solv")) 1973 { 1974 repo_add_solv(repo, rfp, 0); 1975 fclose(rfp); 1976 } 1977#if 0 1978 else if (!strcmp(repotype, "helix")) 1979 { 1980 repo_add_helix(repo, rfp, 0); 1981 fclose(rfp); 1982 } 1983#endif 1984 else 1985 { 1986 fclose(rfp); 1987 pool_debug(pool, SOLV_ERROR, "testcase_read: unknown repo type for repo '%s'\n", repo->name); 1988 } 1989 } 1990 } 1991 else if (!strcmp(pieces[0], "system") && npieces >= 3) 1992 { 1993 int i; 1994 prepared = 0; 1995 /* must set the disttype before the arch */ 1996 for (i = 0; disttype2str[i].str != 0; i++) 1997 if (!strcmp(disttype2str[i].str, pieces[2])) 1998 break; 1999 if (!disttype2str[i].str) 2000 pool_debug(pool, SOLV_ERROR, "testcase_read: system: unknown disttype '%s'\n", pieces[2]); 2001 else if (pool->disttype != disttype2str[i].type) 2002 { 2003#ifdef MULTI_SEMANTICS 2004 pool_setdisttype(pool, disttype2str[i].type); 2005#else 2006 pool_debug(pool, SOLV_ERROR, "testcase_read: system: cannot change disttype to '%s'\n", pieces[2]); 2007#endif 2008 } 2009 if (strcmp(pieces[1], "unset") != 0) 2010 pool_setarch(pool, pieces[1]); 2011 else 2012 pool_setarch(pool, 0); 2013 if (npieces > 3) 2014 { 2015 Repo *repo = testcase_str2repo(pool, pieces[3]); 2016 if (!repo) 2017 pool_debug(pool, SOLV_ERROR, "testcase_read: system: unknown repo '%s'\n", pieces[3]); 2018 else 2019 pool_set_installed(pool, repo); 2020 } 2021 } 2022 else if (!strcmp(pieces[0], "job") && npieces > 1) 2023 { 2024 char *sp; 2025 Id how, what; 2026 if (!prepared) 2027 { 2028 pool_addfileprovides(pool); 2029 pool_createwhatprovides(pool); 2030 prepared = 1; 2031 } 2032 if (npieces >= 3 && !strcmp(pieces[2], "selection")) 2033 { 2034 addselectionjob(pool, pieces + 1, npieces - 1, job); 2035 continue; 2036 } 2037 /* rejoin */ 2038 for (sp = pieces[1]; sp < pieces[npieces - 1]; sp++) 2039 if (*sp == 0) 2040 *sp = ' '; 2041 how = testcase_str2job(pool, pieces[1], &what); 2042 if (how >= 0 && job) 2043 queue_push2(job, how, what); 2044 } 2045 else if (!strcmp(pieces[0], "vendorclass") && npieces > 1) 2046 { 2047 pool_addvendorclass(pool, (const char **)(pieces + 1)); 2048 } 2049 else if (!strcmp(pieces[0], "namespace") && npieces > 1) 2050 { 2051 int i = strlen(pieces[1]); 2052 s = strchr(pieces[1], '('); 2053 if (!s && pieces[1][i - 1] != ')') 2054 { 2055 pool_debug(pool, SOLV_ERROR, "testcase_read: bad namespace '%s'\n", pieces[1]); 2056 } 2057 else 2058 { 2059 Id name, evr, id; 2060 Queue q; 2061 queue_init(&q); 2062 *s = 0; 2063 pieces[1][i - 1] = 0; 2064 name = pool_str2id(pool, pieces[1], 1); 2065 evr = pool_str2id(pool, s + 1, 1); 2066 *s = '('; 2067 pieces[1][i - 1] = ')'; 2068 id = pool_rel2id(pool, name, evr, REL_NAMESPACE, 1); 2069 for (i = 2; i < npieces; i++) 2070 queue_push(&q, testcase_str2solvid(pool, pieces[i])); 2071 /* now do the callback */ 2072 if (!prepared) 2073 { 2074 pool_addfileprovides(pool); 2075 pool_createwhatprovides(pool); 2076 prepared = 1; 2077 } 2078 pool->whatprovides_rel[GETRELID(id)] = pool_queuetowhatprovides(pool, &q); 2079 queue_free(&q); 2080 } 2081 } 2082 else if (!strcmp(pieces[0], "poolflags")) 2083 { 2084 int i; 2085 if (!poolflagsreset) 2086 { 2087 poolflagsreset = 1; 2088 testcase_resetpoolflags(pool); /* hmm */ 2089 } 2090 for (i = 1; i < npieces; i++) 2091 testcase_setpoolflags(pool, pieces[i]); 2092 } 2093 else if (!strcmp(pieces[0], "solverflags") && npieces > 1) 2094 { 2095 int i; 2096 if (!solv) 2097 { 2098 solv = solver_create(pool); 2099 testcase_resetsolverflags(solv); 2100 } 2101 for (i = 1; i < npieces; i++) 2102 testcase_setsolverflags(solv, pieces[i]); 2103 } 2104 else if (!strcmp(pieces[0], "result") && npieces > 2) 2105 { 2106 char *result = 0; 2107 int resultflags = str2resultflags(pool, pieces[1]); 2108 const char *rdata = pool_tmpjoin(pool, testcasedir, pieces[2], 0); 2109 if (!strcmp(pieces[2], "<inline>")) 2110 result = read_inline_file(fp, &buf, &bufp, &bufl); 2111 else 2112 { 2113 FILE *rfp = fopen(rdata, "r"); 2114 if (!rfp) 2115 pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", rdata); 2116 else 2117 { 2118 result = read_file(rfp); 2119 fclose(rfp); 2120 } 2121 } 2122 if (resultp) 2123 *resultp = result; 2124 else 2125 solv_free(result); 2126 if (resultflagsp) 2127 *resultflagsp = resultflags; 2128 } 2129 else if (!strcmp(pieces[0], "nextjob") && npieces == 1) 2130 { 2131 break; 2132 } 2133 else 2134 { 2135 pool_debug(pool, SOLV_ERROR, "testcase_read: cannot parse command '%s'\n", pieces[0]); 2136 } 2137 } 2138 buf = solv_free(buf); 2139 pieces = solv_free(pieces); 2140 solv_free(testcasedir); 2141 if (!prepared) 2142 { 2143 pool_addfileprovides(pool); 2144 pool_createwhatprovides(pool); 2145 } 2146 if (!solv) 2147 { 2148 solv = solver_create(pool); 2149 testcase_resetsolverflags(solv); 2150 } 2151 if (closefp) 2152 fclose(fp); 2153 return solv; 2154} 2155 2156char * 2157testcase_resultdiff(char *result1, char *result2) 2158{ 2159 Strqueue sq1, sq2, osq; 2160 char *r; 2161 strqueue_init(&sq1); 2162 strqueue_init(&sq2); 2163 strqueue_init(&osq); 2164 strqueue_split(&sq1, result1); 2165 strqueue_split(&sq2, result2); 2166 strqueue_sort(&sq1); 2167 strqueue_sort(&sq2); 2168 strqueue_diff(&sq1, &sq2, &osq); 2169 r = osq.nstr ? strqueue_join(&osq) : 0; 2170 strqueue_free(&sq1); 2171 strqueue_free(&sq2); 2172 strqueue_free(&osq); 2173 return r; 2174} 2175 2176