]> cygwin.com Git - cygwin-apps/setup.git/blame - libsolv.cc
Suppress bogus free-nonheap-object warning in iniparse.cc
[cygwin-apps/setup.git] / libsolv.cc
CommitLineData
1c159e0a
JT
1/*
2 * Copyright (c) 2017 Jon Turney
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 */
13
14#include "libsolv.h"
16994679
KB
15#include "package_db.h"
16#include "package_meta.h"
5fa727e1 17#include "resource.h"
1c159e0a
JT
18
19#include "solv/solver.h"
20#include "solv/solverdebug.h"
21#include "solv/evr.h"
22
23#include "LogSingleton.h"
4938eeae
JT
24#include <iomanip>
25#include <algorithm>
1c159e0a
JT
26
27// ---------------------------------------------------------------------------
28// Utility functions for mapping between Operators and Relation Ids
29// ---------------------------------------------------------------------------
30
31static Id
32Operator2RelId(PackageSpecification::_operators op)
33{
34 switch (op)
35 {
36 case PackageSpecification::Equals:
37 return REL_EQ;
38 case PackageSpecification::LessThan:
39 return REL_LT;
40 case PackageSpecification::MoreThan:
41 return REL_GT;
42 case PackageSpecification::LessThanEquals:
43 return REL_LT | REL_EQ;
44 case PackageSpecification::MoreThanEquals:
45 return REL_GT | REL_EQ;
46 }
47
48 return 0;
49}
50
51static PackageSpecification::_operators
52RelId2Operator(Id id)
53{
54 switch (id)
55 {
56 case REL_EQ:
57 return PackageSpecification::Equals;
58 case REL_LT:
59 return PackageSpecification::LessThan;
60 case REL_GT:
61 return PackageSpecification::MoreThan;
62 case REL_LT | REL_EQ:
63 return PackageSpecification::LessThanEquals;
64 case REL_GT | REL_EQ:
65 return PackageSpecification::MoreThanEquals;
66 }
67
68 return PackageSpecification::Equals;
69}
70
71// ---------------------------------------------------------------------------
72// implements class SolvableVersion
73//
74// a wrapper around a libsolv Solvable
75// ---------------------------------------------------------------------------
76
bfe593cf
KB
77Id
78SolvableVersion::name_id () const
79{
80 Solvable *solvable = pool_id2solvable(pool, id);
81 return solvable->name;
82}
83
1c159e0a
JT
84const std::string
85SolvableVersion::Name () const
86{
e2ec1fa2
KB
87 if (!id)
88 return "";
bfe593cf 89 return pool_id2str(pool, name_id());
1c159e0a
JT
90}
91
92const std::string
93SolvableVersion::Canonical_version() const
94{
e2ec1fa2
KB
95 if (!id)
96 return "";
1c159e0a
JT
97 Solvable *solvable = pool_id2solvable(pool, id);
98 return std::string(pool_id2str(pool, solvable->evr));
99}
100
101package_type_t
102SolvableVersion::Type () const
103{
e2ec1fa2
KB
104 if (!id)
105 return package_binary;
1c159e0a
JT
106 Solvable *solvable = pool_id2solvable(pool, id);
107 if (solvable->arch == ARCH_SRC)
108 return package_source;
109 else
110 return package_binary;
111}
112
113const PackageDepends
114SolvableVersion::depends() const
5ebe14e4
KB
115{
116 return deplist(SOLVABLE_REQUIRES);
117}
118
119const PackageDepends
120SolvableVersion::obsoletes() const
121{
122 return deplist(SOLVABLE_OBSOLETES);
123}
124
6d23697e
KB
125const PackageDepends
126SolvableVersion::provides() const
127{
128 return deplist(SOLVABLE_PROVIDES);
129}
130
131const PackageDepends
132SolvableVersion::conflicts() const
133{
134 return deplist(SOLVABLE_CONFLICTS);
135}
136
5ebe14e4
KB
137// helper function which returns the deplist for a given key, as a PackageDepends
138const PackageDepends
139SolvableVersion::deplist(Id keyname) const
1c159e0a 140{
e2ec1fa2
KB
141 static PackageDepends empty_package;
142 if (!id)
143 return empty_package;
1c159e0a
JT
144 Solvable *solvable = pool_id2solvable(pool, id);
145
146 Queue q;
147 queue_init(&q);
148
5ebe14e4 149 if (repo_lookup_idarray(solvable->repo, id, keyname, &q))
1c159e0a
JT
150 {
151 // convert
152 PackageDepends dep;
153
154 for (int i = 0; i < q.count; i++)
155 {
156#ifdef DEBUG
157 Log (LOG_PLAIN) << "dep " << std::hex << q.elements[i] << ": " << pool_dep2str(pool, q.elements[i]) << endLog;
158#endif
159
160 const char *name = pool_id2str(pool, q.elements[i]);
161 PackageSpecification *spec = new PackageSpecification (name);
162
5947bc92 163 if (ISRELDEP(q.elements[i]))
1c159e0a 164 {
5947bc92 165 Reldep *rd = GETRELDEP(pool, q.elements[i]);
1c159e0a
JT
166 spec->setOperator(RelId2Operator(rd->flags));
167 spec->setVersion(pool_id2str(pool, rd->evr));
168 }
169
170 dep.push_back (spec);
171 }
172
173 queue_empty(&q);
174
175 return dep;
176 }
177
178 // otherwise, return an empty depends list
1c159e0a
JT
179 return empty_package;
180}
181
182const std::string
183SolvableVersion::SDesc () const
184{
e2ec1fa2
KB
185 if (!id)
186 return "";
1c159e0a
JT
187 Solvable *solvable = pool_id2solvable(pool, id);
188 const char *sdesc = repo_lookup_str(solvable->repo, id, SOLVABLE_SUMMARY);
c4b8d6dd
JT
189
190 if (!sdesc)
191 return "";
192
1c159e0a
JT
193 return sdesc;
194}
195
30cae42f
JT
196const std::string
197SolvableVersion::LDesc () const
198{
199 if (!id)
200 return "";
201 Solvable *solvable = pool_id2solvable(pool, id);
202 const char *ldesc = repo_lookup_str(solvable->repo, id, SOLVABLE_DESCRIPTION);
203
204 if (!ldesc)
205 return "";
206
207 return ldesc;
208}
209
c59b92e8
JT
210const std::string
211SolvableVersion::sourcePackageName () const
212{
213 if (!id)
214 return "";
215
216 // extract source package name
217 Solvable *solvable = pool_id2solvable(pool, id);
218 Id spkg = repo_lookup_id(solvable->repo, id, SOLVABLE_SOURCENAME);
219
220 // has no such attribute
221 if (!spkg)
222 return "";
223
224 return std::string(pool_id2str(pool, spkg));
225}
226
f158577d
JT
227const std::string
228SolvableVersion::Vendor () const
229{
230 if (!id)
231 return "";
232
233 // extract vendor
234 Solvable *solvable = pool_id2solvable(pool, id);
235 Id vendor = repo_lookup_id(solvable->repo, id, SOLVABLE_VENDOR);
236
237 // has no such attribute
238 if (!vendor)
239 return "";
240
241 return std::string(pool_id2str(pool, vendor));
242}
243
1c159e0a
JT
244SolvableVersion
245SolvableVersion::sourcePackage () const
246{
247 if (!id)
248 return SolvableVersion();
249
250 // extract source package id
251 Solvable *solvable = pool_id2solvable(pool, id);
252 Id spkg_attr = pool_str2id(pool, "solvable:sourceid", 1);
253 Id spkg_id = repo_lookup_id(solvable->repo, id, spkg_attr);
254
255 // has no such attribute
256 if (!spkg_id)
257 return SolvableVersion();
258
259 return SolvableVersion(spkg_id, pool);
260}
261
c59b92e8
JT
262void
263SolvableVersion::fixup_spkg_id (SolvableVersion spkg_id) const
264{
e2ec1fa2
KB
265 if (!id)
266 return;
c59b92e8
JT
267 Solvable *solvable = pool_id2solvable(pool, id);
268 Repodata *data = repo_last_repodata(solvable->repo);
269 Id handle = id;
270 Id spkg_attr = pool_str2id(pool, "solvable:sourceid", 1);
271 repodata_set_id(data, handle, spkg_attr, spkg_id.id);
272}
273
1c159e0a
JT
274packagesource *
275SolvableVersion::source() const
276{
c4b8d6dd 277 static packagesource empty_source = packagesource();
1c159e0a 278 if (!id) {
1c159e0a
JT
279 return &empty_source;
280 }
281
282 Solvable *solvable = pool_id2solvable(pool, id);
283 Id psrc_attr = pool_str2id(pool, "solvable:packagesource", 1);
c4b8d6dd 284 return (packagesource *)repo_lookup_num(solvable->repo, id, psrc_attr, (unsigned long long)&empty_source);
1c159e0a
JT
285}
286
287bool
288SolvableVersion::accessible () const
289{
5fa727e1
KB
290 // empty packages are never accessible
291 if (id == 0)
292 return false;
293
294 // If we're doing a local re-install, is there an archive available?
de8fc0b8 295 //
5fa727e1
KB
296 // (This assumes that packagemeta::ScanDownloadedFiles() has already been
297 // called to check for presence in the package cache, which would have removed
298 // the version if not available, unless it is already installed)
299 if (::source == IDC_SOURCE_LOCALDIR)
300 return source ()->Cached ();
301
302 // Otherwise, package is (presumably) retrievable
303 return true;
1c159e0a
JT
304}
305
306package_stability_t
307SolvableVersion::Stability () const
308{
e2ec1fa2
KB
309 if (!id)
310 return TRUST_UNKNOWN;
1c159e0a
JT
311 Solvable *solvable = pool_id2solvable(pool, id);
312 Id stability_attr = pool_str2id(pool, "solvable:stability", 1);
313 return (package_stability_t)repo_lookup_num(solvable->repo, id, stability_attr, TRUST_UNKNOWN);
314}
315
316bool
317SolvableVersion::operator <(SolvableVersion const &rhs) const
318{
319 return (compareVersions(*this, rhs) < 0);
320}
321
322bool
323SolvableVersion::operator ==(SolvableVersion const &rhs) const
324{
325 return (compareVersions(*this, rhs) == 0);
326}
327
328bool
329SolvableVersion::operator !=(SolvableVersion const &rhs) const
330{
331 return (compareVersions(*this, rhs) != 0);
332}
333
334int
335SolvableVersion::compareVersions(const SolvableVersion &a,
336 const SolvableVersion &b)
337{
338 if (a.id == b.id)
339 return 0;
340
341 // if a and b are different, at least one of them has a pool
342 Pool *pool = a.pool ? a.pool : b.pool;
343
344 Solvable *sa = a.id ? pool_id2solvable(a.pool, a.id) : NULL;
345 Solvable *sb = b.id ? pool_id2solvable(b.pool, b.id) : NULL;
346
347 // empty versions compare as if their version is the empty string
348 Id evra = sa ? sa->evr : pool_str2id(pool, "", 1);
349 Id evrb = sb ? sb->evr : pool_str2id(pool, "", 1);
350
351 return pool_evrcmp(pool, evra, evrb, EVRCMP_COMPARE);
352}
353
972b2d9a
JT
354void
355SolvableVersion::remove() const
356{
357 if (!id)
358 return;
359
360 Solvable *solvable = pool_id2solvable(pool, id);
361 repo_free_solvable(solvable->repo, id, 0);
362}
363
1c159e0a
JT
364// ---------------------------------------------------------------------------
365// implements class SolverPool
366//
367// a simplified wrapper for libsolv
368// ---------------------------------------------------------------------------
369
370static
371void debug_callback(Pool *pool, void *data, int type, const char *str)
372{
373 if (type & (SOLV_FATAL|SOLV_ERROR))
374 LogPlainPrintf("libsolv: %s", str);
375 else
376 LogBabblePrintf("libsolv: %s", str);
377}
378
379SolverPool::SolverPool()
ab67dafa
JT
380{
381 init();
382}
383
384void
385SolverPool::init()
1c159e0a
JT
386{
387 /* create a pool */
388 pool = pool_create();
389
390 pool_setdebugcallback(pool, debug_callback, NULL);
391
392 int level = 1;
393#if DEBUG
394 level = 3;
395#endif
396 pool_setdebuglevel(pool, level);
397
398 /* create the repo to hold installed packages */
399 SolvRepo *installed = getRepo("_installed");
400 pool_set_installed(pool, installed->repo);
401}
402
ab67dafa
JT
403void
404SolverPool::clear()
405{
406 repos.clear();
407 pool_free(pool);
408 pool = NULL;
409
410 init();
411}
412
1c159e0a
JT
413SolvRepo *
414SolverPool::getRepo(const std::string &name, bool test)
415{
416 RepoList::iterator i = repos.find(name);
417 if (i != repos.end())
418 return i->second;
419
420 /* create repo if not found */
421 SolvRepo *r = new(SolvRepo);
422 r->repo = repo_create(pool, name.c_str());
423
424 /* create attribute store, with no local pool */
425 r->data = repo_add_repodata(r->repo, 0);
426
427 /* remember if this is a test stability repo */
428 r->test = test;
429
3c3d695d
KB
430 /* set default priority */
431 r->repo->priority = SolvRepo::priorityNormal;
432
1c159e0a
JT
433 repos[name] = r;
434
435 return r;
436}
437
438/*
439 Helper function to convert a PackageDepends list to libsolv dependencies.
440*/
441Id
442SolverPool::makedeps(Repo *repo, PackageDepends *requires)
443{
444 Id deps = 0;
445
446 for (PackageDepends::iterator i = requires->begin();
447 i != requires->end();
448 i++)
449 {
450 Id name = pool_str2id(pool, (*i)->packageName().c_str(), 1);
451
452 if ((*i)->version().size() == 0)
453 {
454 // no relation, so dependency is just on package name
455 deps = repo_addid_dep(repo, deps, name, 0);
456 }
457 else
458 {
459 // otherwise, dependency is on package name with a version condition
460 Id evr = pool_str2id(pool, (*i)->version().c_str(), 1);
461 int rel = pool_rel2id(pool, name, evr, Operator2RelId((*i)->op()), 1);
462
463 deps = repo_addid_dep(repo, deps, rel, 0);
464 }
465 }
466
467 return deps;
468}
469
470SolvableVersion
471SolverPool::addPackage(const std::string& pkgname, const addPackageData &pkgdata)
472{
473 std::string repoName = pkgdata.reponame;
474 bool test = false;
475
3c3d695d
KB
476 /* It's simplest to place test packages into a separate repo, and
477 then arrange for that repo to have low priority, if we don't want
478 to install those packages by default */
1c159e0a 479
88f3d803 480 if (pkgdata.stability == TRUST_TEST && repoName != "_installed")
1c159e0a
JT
481 {
482 repoName = pkgdata.reponame + "_test_";
483 test = true;
484 }
485
486 SolvRepo *r = getRepo(repoName, test);
487 Repo *repo = r->repo;
488
489 /* create a solvable */
490 Id s = repo_add_solvable(repo);
491 Solvable *solvable = pool_id2solvable(pool, s);
492
493 /* initialize solvable for this packageo/version/etc. */
494 solvable->name = pool_str2id(pool, pkgname.c_str(), 1);
495 solvable->arch = (pkgdata.type == package_binary) ? ARCH_ANY : ARCH_SRC;
496 solvable->evr = pool_str2id(repo->pool, pkgdata.version.c_str(), 1);
497 solvable->vendor = pool_str2id(repo->pool, pkgdata.vendor.c_str(), 1);
9c3e3256
JT
498 if (pkgdata.provides)
499 solvable->provides = makedeps(repo, pkgdata.provides);
f4bddeea 500 /* in the absence of specific provides, we provide what we obsolete */
9c3e3256 501 else if (pkgdata.obsoletes)
f4bddeea
JT
502 solvable->provides = makedeps(repo, pkgdata.obsoletes);
503 /* we always provide ourselves */
1c159e0a
JT
504 solvable->provides = repo_addid_dep(repo, solvable->provides, pool_rel2id(pool, solvable->name, solvable->evr, REL_EQ, 1), 0);
505 if (pkgdata.requires)
506 solvable->requires = makedeps(repo, pkgdata.requires);
20b98f20
JT
507 if (pkgdata.obsoletes)
508 solvable->obsoletes = makedeps(repo, pkgdata.obsoletes);
e6433da6
JT
509 if (pkgdata.conflicts)
510 solvable->conflicts = makedeps(repo, pkgdata.conflicts);
1c159e0a
JT
511
512 /* a solvable can also store arbitrary attributes not needed for dependency
513 resolution, if we need them */
514
515 Repodata *data = r->data;
516 Id handle = s;
517#if DEBUG
518 Log (LOG_PLAIN) << "solvable " << s << " name " << pkgname << endLog;
519#endif
520
521 /* store short description attribute */
522 repodata_set_str(data, handle, SOLVABLE_SUMMARY, pkgdata.sdesc.c_str());
523 /* store long description attribute */
524 repodata_set_str(data, handle, SOLVABLE_DESCRIPTION, pkgdata.ldesc.c_str());
525
526 /* store source-package attribute */
527 const std::string sname = pkgdata.spkg.packageName();
528 if (!sname.empty())
529 repodata_set_id(data, handle, SOLVABLE_SOURCENAME, pool_str2id(pool, sname.c_str(), 1));
530 else
531 repodata_set_void(data, handle, SOLVABLE_SOURCENAME);
532 /* solvable:sourceevr may also be available from spkg but assumed to be same
533 as evr for the moment */
534
535 /* store source-package id */
c59b92e8
JT
536 /* (If the source-package hasn't been seen yet, we don't know what it's Id
537 will be. That gets fixed up later.) */
538 if (pkgdata.spkg_id)
539 {
540 Id spkg_attr = pool_str2id(pool, "solvable:sourceid", 1);
541 repodata_set_id(data, handle, spkg_attr, pkgdata.spkg_id.id);
542 }
1c159e0a
JT
543
544 /* we could store packagesource information as attributes ...
545
546 e.g.
547 size SOLVABLE_DOWNLOADSIZE
548 pathname SOLVABLE_MEDIAFILE
549 site SOLVABLE_MEDIABASE
550 checksum SOLVABLE_CHECKSUM
551
552 ... but for the moment, we just store a pointer to a packagesource object
553 */
554 Id psrc_attr = pool_str2id(pool, "solvable:packagesource", 1);
555 packagesource *psrc = new packagesource(pkgdata.archive);
556 repodata_set_num(data, handle, psrc_attr, (intptr_t)psrc);
557
558 /* store stability level attribute */
559 Id stability_attr = pool_str2id(pool, "solvable:stability", 1);
560 repodata_set_num(data, handle, stability_attr, pkgdata.stability);
561
562#if 0
563 repodata_internalize(data);
564
565 /* debug: verify the attributes we've just set get retrieved correctly */
566 SolvableVersion sv = SolvableVersion(s, pool);
567 const std::string check_sdesc = sv.SDesc();
568 if (pkgdata.sdesc.compare(check_sdesc) != 0) {
569 Log (LOG_PLAIN) << pkgname << " has sdesc mismatch: '" << pkgdata.sdesc << "' and '"
570 << check_sdesc << "'" << endLog;
571 }
572 if (!sname.empty()) {
573 SolvableVersion check_spkg = sv.sourcePackage();
574 Solvable *check_spkg_solvable = pool_id2solvable(pool, check_spkg.id);
575 std::string check_sname = pool_id2str(pool, check_spkg_solvable->name);
576 if (sname.compare(check_sname) != 0) {
577 Log (LOG_PLAIN) << pkgname << " has spkg mismatch: '" << pkgdata.spkg.packageName()
578 << "' and '" << check_sname << "'" << endLog;
579 }
580 }
581 packagesource *check_archive = sv.source();
582 if (check_archive != psrc)
583 Log (LOG_PLAIN) << pkgname << " has archive mismatch: " << psrc
584 << " and " << check_archive << endLog;
585 package_stability_t check_stability = sv.Stability();
586 if (check_stability != pkgdata.stability) {
587 Log (LOG_PLAIN) << pkgname << " has stability mismatch: " << pkgdata.stability
588 << " and " << check_stability << endLog;
589 }
590#endif
591
592 return SolvableVersion(s, pool);
593}
594
595void
596SolverPool::internalize()
597{
598 /* Make attribute data available to queries */
599 for (RepoList::iterator i = repos.begin();
600 i != repos.end();
601 i++)
602 {
603 repodata_internalize(i->second->data);
604 }
605}
1d553f34 606
d76a9ffd
JT
607bool
608SolverPool::is_test_package(SolvableVersion sv)
609{
610 Solvable *solvable = pool_id2solvable(pool, sv.id);
611
612 for (RepoList::iterator i = repos.begin();
613 i != repos.end();
614 i++)
615 {
616 if (solvable->repo == i->second->repo)
617 return i->second->test;
618 }
619
620 return false;
621}
622
16994679
KB
623void
624SolverTasks::setTasks()
625{
626 // go through all packages, adding changed ones to the solver task list
627 packagedb db;
2506055b 628 tasks.clear();
16994679
KB
629
630 for (packagedb::packagecollection::iterator p = db.packages.begin ();
631 p != db.packages.end (); ++p)
632 {
633 packagemeta *pkg = p->second;
634
14579ca8 635 switch (pkg->get_action())
16994679 636 {
14579ca8
JT
637 case packagemeta::NoChange_action: // skip/keep
638 // keep and skip need attention only when they differ from the
639 // solver's solution
640 if (pkg->installed)
d2e0c29e 641 {
14579ca8
JT
642 if (!pkg->picked() && pkg->installed != pkg->default_version)
643 add(pkg->installed, taskKeep); // keep
644 else if (pkg->isBlacklisted(pkg->installed))
d2e0c29e 645 {
14579ca8
JT
646 // if installed (with no action selected), but blacklisted,
647 // force a distupgrade of this package
d2e0c29e
JT
648 add(pkg->installed, taskForceDistUpgrade);
649 }
650 }
14579ca8
JT
651 else if (pkg->default_version)
652 add(pkg->default_version, taskSkip); // skip
653
654 break;
655
656 case packagemeta::Install_action:
20a29666
JT
657 if (pkg->desired)
658 add(pkg->desired, taskInstall); // install/upgrade
b0bd1695
JT
659 else
660 {
661 // install
662 //
663 // empty desired means "any version", it doesn't matter which one
664 // we use as taskInstallAny only match on the provides name
665 if (pkg->curr)
666 add(pkg->curr, taskInstallAny);
667 else if (pkg->exp)
668 add(pkg->exp, taskInstallAny);
669 }
14579ca8
JT
670 break;
671
672 case packagemeta::Uninstall_action:
673 add(pkg->installed, taskUninstall); // uninstall
674 break;
675
676 case packagemeta::Reinstall_action:
677 add(pkg->installed, taskReinstall); // reinstall
678 break;
16994679
KB
679 }
680
681 // only install action makes sense for source packages
682 if (pkg->srcpicked())
683 {
684 if (pkg->desired)
685 add(pkg->desired.sourcePackage(), taskInstall);
686 else
687 add(pkg->installed.sourcePackage(), taskInstall);
688 }
689 }
690}
691
1d553f34
JT
692void
693SolverPool::use_test_packages(bool use_test_packages)
694{
3c3d695d
KB
695 // Give repos containing test packages higher priority than normal
696 // if wanted, otherwise lower priority.
697 SolvRepo::priority_t p = use_test_packages ? SolvRepo::priorityNormal : SolvRepo::priorityLow;
1d553f34
JT
698 for (RepoList::iterator i = repos.begin();
699 i != repos.end();
700 i++)
701 {
702 if (i->second->test)
3c3d695d 703 i->second->setPriority(p);
1d553f34
JT
704 }
705}
706
707// ---------------------------------------------------------------------------
708// implements class SolverSolution
709//
710// A wrapper around the libsolv solver
711// ---------------------------------------------------------------------------
712
2506055b
JT
713SolverSolution::SolverSolution(SolverPool &_pool) : pool(_pool), solv(NULL)
714{
715 queue_init(&job);
716}
717
1d553f34 718SolverSolution::~SolverSolution()
ab67dafa
JT
719{
720 clear();
721}
722
723void
724SolverSolution::clear()
1d553f34
JT
725{
726 if (solv)
727 {
728 solver_free(solv);
729 solv = NULL;
730 }
2506055b 731 queue_free(&job);
1d553f34
JT
732}
733
7c94d449
KB
734void
735SolverSolution::trans2db() const
736{
737 packagedb db;
9ca5efb3
KB
738 // First reset all packages to the "no changes" state
739 db.noChanges ();
740
7c94d449
KB
741 // Now make changes according to trans. transErase requires some
742 // care; it could either be a "plain" uninstall, or it could be
743 // paired with a transInstall for an upgrade/downgrade or reinstall.
744 for (SolverTransactionList::const_iterator i = trans.begin();
745 i != trans.end(); i++)
746 {
747 const packageversion & pv = i->version;
748 packagemeta *pkg = db.findBinary(PackageSpecification(pv.Name()));
749 if (!pkg)
750 // Can't happen - throw an exception?
751 {
752 Log (LOG_PLAIN) << "Can't happen. No packagemeta for "
753 << pv.Name() << endLog;
754 return;
755 }
756 switch (i->type)
757 {
758 case SolverTransaction::transInstall:
759 if (pv.Type() == package_binary)
760 {
6dc6650a
JT
761 pkg->set_action(packagemeta::Install_action, pv);
762 pkg->default_version = pv;
7c94d449
KB
763 }
764 else // source package
765 pkg->srcpick(true);
766 break;
767 case SolverTransaction::transErase:
768 // Only relevant if pkg is still in its "no change" state
6dc6650a
JT
769 if (pkg->get_action() == packagemeta::NoChange_action)
770 {
771 pkg->set_action(packagemeta::Uninstall_action, packageversion());
772 pkg->default_version = packageversion();
773 }
7c94d449
KB
774 break;
775 default:
776 break;
777 }
778 }
779}
780
9a7507eb
KB
781void
782SolverSolution::db2trans()
783{
784 trans.clear();
785 packagedb db;
786
787 for (packagedb::packagecollection::iterator p = db.packages.begin ();
788 p != db.packages.end (); ++p)
789 {
790 packagemeta *pkg = p->second;
6dc6650a
JT
791 if ((pkg->get_action() == packagemeta::Install_action) ||
792 (pkg->get_action() == packagemeta::Reinstall_action))
9a7507eb
KB
793 {
794 trans.push_back(SolverTransaction(pkg->desired, SolverTransaction::transInstall));
795 if (pkg->installed)
796 trans.push_back(SolverTransaction(pkg->installed, SolverTransaction::transErase));
797 }
6dc6650a 798 else if (pkg->get_action() == packagemeta::Uninstall_action)
9a7507eb
KB
799 trans.push_back(SolverTransaction(pkg->installed, SolverTransaction::transErase));
800
801 if (pkg->srcpicked())
802 {
803 if (pkg->desired)
804 trans.push_back(SolverTransaction(pkg->desired.sourcePackage(), SolverTransaction::transInstall));
805 else
806 trans.push_back(SolverTransaction(pkg->installed.sourcePackage(), SolverTransaction::transInstall));
807 }
808 }
809}
810
1d553f34
JT
811static
812std::ostream &operator<<(std::ostream &stream,
813 SolverTransaction::transType type)
814{
815 switch (type)
816 {
817 case SolverTransaction::transInstall:
818 stream << "install";
819 break;
820 case SolverTransaction::transErase:
821 stream << "erase";
822 break;
823 default:
824 stream << "unknown";
825 }
826 return stream;
827}
828
2506055b
JT
829void
830SolverSolution::tasksToJobs(SolverTasks &tasks, updateMode update, Queue &job)
1d553f34 831{
1d553f34
JT
832 // solver accepts a queue containing pairs of (cmd, id) tasks
833 // cmd is job and selection flags ORed together
834 for (SolverTasks::taskList::const_iterator i = tasks.tasks.begin();
835 i != tasks.tasks.end();
836 i++)
837 {
838 const SolvableVersion &sv = (*i).first;
839
840 switch ((*i).second)
841 {
842 case SolverTasks::taskInstall:
843 queue_push2(&job, SOLVER_INSTALL | SOLVER_SOLVABLE, sv.id);
844 break;
20a29666
JT
845 case SolverTasks::taskInstallAny:
846 queue_push2(&job, SOLVER_INSTALL | SOLVER_SOLVABLE_PROVIDES, sv.name_id());
847 break;
1d553f34
JT
848 case SolverTasks::taskUninstall:
849 queue_push2(&job, SOLVER_ERASE | SOLVER_SOLVABLE, sv.id);
850 break;
851 case SolverTasks::taskReinstall:
852 // we don't know how to ask solver for this, so we just add the erase
853 // and install later
854 break;
9deed604
KB
855 case SolverTasks::taskKeep:
856 queue_push2(&job, SOLVER_LOCK | SOLVER_SOLVABLE, sv.id);
857 break;
bfe593cf
KB
858 case SolverTasks::taskSkip:
859 queue_push2(&job, SOLVER_LOCK | SOLVER_SOLVABLE_NAME, sv.name_id());
860 break;
d2e0c29e
JT
861 case SolverTasks::taskForceDistUpgrade:
862 queue_push2(&job, SOLVER_DISTUPGRADE | SOLVER_SOLVABLE, sv.id);
863 break;
1d553f34
JT
864 default:
865 Log (LOG_PLAIN) << "unknown task " << (*i).second << endLog;
866 }
867 }
868
45f5ab69
JT
869 // Ask solver to update packages
870 switch (update)
871 {
872 case keep:
873 break;
874
875 case updateBest:
876 // Update to best version
877 queue_push2(&job, SOLVER_UPDATE | SOLVER_SOLVABLE_ALL, 0);
878 break;
879
880 case updateForce:
881 // Bring installed, non-orphaned packages in sync with the ones in the
882 // repository
883 queue_push2(&job, SOLVER_DISTUPGRADE | SOLVER_SOLVABLE_ALL, 0);
884 break;
885 }
1d553f34 886
ca8245b2
KB
887 // Ask solver to check dependencies of installed packages.
888 queue_push2(&job, SOLVER_VERIFY | SOLVER_SOLVABLE_ALL, 0);
2506055b
JT
889}
890
891bool
892SolverSolution::update(SolverTasks &tasks, updateMode update, bool use_test_packages)
893{
894 Log (LOG_PLAIN) << "solving: " << tasks.tasks.size() << " tasks," <<
895 " update: " << (update ? "yes" : "no") << "," <<
896 " use test packages: " << (use_test_packages ? "yes" : "no") << endLog;
897
898 pool.use_test_packages(use_test_packages);
899
900 queue_free(&job);
901 tasksToJobs(tasks, update, job);
ca8245b2 902
1d553f34
JT
903 if (!solv)
904 solv = solver_create(pool.pool);
905
2506055b
JT
906 return solve();
907}
908
909bool
910SolverSolution::solve()
911{
1d553f34
JT
912 solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1);
913 solver_set_flag(solv, SOLVER_FLAG_ALLOW_DOWNGRADE, 0);
45f5ab69
JT
914 solver_set_flag(solv, SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE, 1);
915 solver_set_flag(solv, SOLVER_FLAG_DUP_ALLOW_DOWNGRADE, 1);
1d553f34 916 solver_solve(solv, &job);
1d553f34
JT
917
918 int pcnt = solver_problem_count(solv);
919 solver_printdecisions(solv);
920
2506055b
JT
921 solutionToTransactionList();
922
923 return (pcnt == 0);
924}
925
926void
927SolverSolution::solutionToTransactionList()
928{
1d553f34
JT
929 // get transactions for solution
930 Transaction *t = solver_create_transaction(solv);
931 transaction_order(t, 0);
932 transaction_print(t);
933
934 // massage into SolverTransactions form
935 trans.clear();
1d553f34
JT
936 for (int i = 0; i < t->steps.count; i++)
937 {
938 Id id = t->steps.elements[i];
939 SolverTransaction::transType tt = type(t, i);
45f5ab69
JT
940 if (tt != SolverTransaction::transIgnore)
941 trans.push_back(SolverTransaction(SolvableVersion(id, pool.pool), tt));
1d553f34
JT
942 }
943
2506055b
JT
944 transaction_free(t);
945
3969f3ea 946#if DEBUG
2506055b 947 dumpTransactionList();
3969f3ea 948#endif
2506055b
JT
949}
950
951void
952SolverSolution::augmentTasks(SolverTasks &tasks)
953{
1d553f34
JT
954 // add install and remove tasks for anything marked as reinstall
955 for (SolverTasks::taskList::const_iterator i = tasks.tasks.begin();
956 i != tasks.tasks.end();
957 i++)
958 {
959 const SolvableVersion &sv = (*i).first;
960
d997f4cf 961 if (sv && (((*i).second) == SolverTasks::taskReinstall))
1d553f34
JT
962 {
963 trans.push_back(SolverTransaction(SolvableVersion(sv.id, pool.pool),
964 SolverTransaction::transErase));
965 trans.push_back(SolverTransaction(SolvableVersion(sv.id, pool.pool),
966 SolverTransaction::transInstall));
967 }
968 }
2506055b 969}
1d553f34 970
2506055b
JT
971void
972SolverSolution::addSource(bool include_source)
973{
1d553f34
JT
974 // if include_source mode is on, also install source for everything we are
975 // installing
976 if (include_source)
977 {
978 // (this uses indicies into the vector, as iterators might become
979 // invalidated by doing push_back)
980 size_t n = trans.size();
981 for (size_t i = 0; i < n; i++)
982 {
983 if (trans[i].type == SolverTransaction::transInstall)
984 {
985 SolvableVersion src_version = trans[i].version.sourcePackage();
986 if (src_version)
987 trans.push_back(SolverTransaction(src_version,
988 SolverTransaction::transInstall));
989 }
990 }
991 }
2506055b 992}
1d553f34 993
2506055b
JT
994void
995SolverSolution::dumpTransactionList() const
996{
1d553f34
JT
997 if (trans.size())
998 {
4938eeae
JT
999 size_t width_name = 0;
1000 size_t width_version = 0;
1001
1002 for (SolverTransactionList::const_iterator i = trans.begin ();
1003 i != trans.end ();
1004 ++i)
1005 {
1006 width_name = std::max(width_name, i->version.Name().length()+1);
1007 width_version = std::max(width_version, i->version.Canonical_version().length()+1);
1008 }
1009
1d553f34 1010 Log (LOG_PLAIN) << "Augmented Transaction List:" << endLog;
2506055b 1011 for (SolverTransactionList::const_iterator i = trans.begin ();
1d553f34
JT
1012 i != trans.end ();
1013 ++i)
1014 {
1015 Log (LOG_PLAIN) << std::setw(4) << std::distance(trans.begin(), i)
4938eeae
JT
1016 << std::setw(8) << i->type << " "
1017 << std::left
1018 << std::setw(width_name) << i->version.Name()
1019 << std::setw(width_version) << i->version.Canonical_version() << endLog;
1d553f34
JT
1020 }
1021 }
2506055b
JT
1022 else
1023 Log (LOG_PLAIN) << "Augmented Transaction List: is empty" << endLog;
1024}
1d553f34 1025
2506055b
JT
1026void SolverSolution::applyDefaultProblemSolutions()
1027{
1028 // adjust the task list with the default solutions
1029 int pcnt = solver_problem_count(solv);
1030 for (Id problem = 1; problem <= pcnt; problem++)
1031 {
1032 int scnt = solver_solution_count(solv, problem);
1033 solver_take_solution(solv, problem, scnt, &job);
1034 }
1d553f34 1035
2506055b
JT
1036 // re-solve
1037 if (!solve())
1038 Log (LOG_PLAIN) << "default solutions did not solve all problems!" << endLog;
1d553f34
JT
1039}
1040
1041const SolverTransactionList &
1042SolverSolution::transactions() const
1043{
1044 return trans;
1045}
1046
1047// Construct a string reporting the problems and solutions
1048std::string
1049SolverSolution::report() const
1050{
d76f912c 1051 packagedb db;
1d553f34
JT
1052 std::string r = "";
1053 int pcnt = solver_problem_count(solv);
1054 for (Id problem = 1; problem <= pcnt; problem++)
1055 {
1056 r += "Problem " + std::to_string(problem) + "/" + std::to_string(pcnt);
1057 r += "\n";
1058
1059 Id probr = solver_findproblemrule(solv, problem);
1060 Id dep, source, target;
1061 SolverRuleinfo type = solver_ruleinfo(solv, probr, &source, &target, &dep);
d76f912c
KB
1062 if (source == db.basepkg.id)
1063 r += "package " + std::string(pool_dep2str(pool.pool, dep)) + " is a Base package and is therefore required";
1064 else
1065 r += solver_problemruleinfo2str(solv, type, source, target, dep);
1d553f34
JT
1066 r += "\n";
1067
1068 int scnt = solver_solution_count(solv, problem);
1069 for (Id solution = 1; solution <= scnt; solution++)
1070 {
1071 r += "Solution " + std::to_string(solution) + "/" + std::to_string(scnt);
2506055b 1072 if (solution == scnt) r += " (default)";
1d553f34
JT
1073 r += "\n";
1074
1075 Id p, rp, element;
1076 element = 0;
1077 while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
1078 {
1079 r += " - ";
d76f912c
KB
1080 if (p == db.basepkg.id)
1081 r += "allow deinstallation of Base packages";
1082 else
1083 r += solver_solutionelement2str(solv, p, rp);
1d553f34
JT
1084 r += "\n";
1085 }
1086 }
1087 }
d14b4325
JT
1088
1089 // since package arch isn't set usefully at the moment, remove all ".any" from
1090 // package names in the problem report string.
1091 std::string any = ".any";
1092 size_t pos;
1093 while ((pos = r.find(any)) != std::string::npos)
1094 {
1095 r.replace(pos, any.length(), "");
1096 }
1097
1d553f34
JT
1098 return r;
1099}
1100
1101// helper function to map transaction type
1102SolverTransaction::transType
1103SolverSolution::type(Transaction *trans, int pos)
1104{
1105 Id tt = transaction_type(trans, trans->steps.elements[pos],
1106 SOLVER_TRANSACTION_SHOW_ACTIVE);
1107
1108 // if active side of transaction is nothing, ask again for passive side of
1109 // transaction
1110 if (tt == SOLVER_TRANSACTION_IGNORE)
1111 tt = transaction_type(trans, trans->steps.elements[pos], 0);
1112
1113 switch(tt)
1114 {
1115 case SOLVER_TRANSACTION_INSTALL:
1116 case SOLVER_TRANSACTION_REINSTALL:
1117 case SOLVER_TRANSACTION_UPGRADE:
1118 case SOLVER_TRANSACTION_DOWNGRADE:
1119 return SolverTransaction::transInstall;
1120 case SOLVER_TRANSACTION_ERASE:
1121 case SOLVER_TRANSACTION_REINSTALLED:
1122 case SOLVER_TRANSACTION_UPGRADED:
1123 case SOLVER_TRANSACTION_DOWNGRADED:
1124 return SolverTransaction::transErase;
1125 default:
1126 Log (LOG_PLAIN) << "unknown transaction type " << std::hex << tt << endLog;
45f5ab69
JT
1127 case SOLVER_TRANSACTION_CHANGE:
1128 case SOLVER_TRANSACTION_CHANGED:
1d553f34
JT
1129 case SOLVER_TRANSACTION_IGNORE:
1130 return SolverTransaction::transIgnore;
1131 }
1132};
This page took 0.207926 seconds and 5 git commands to generate.