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