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