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