2 * Copyright (c) 2017 Jon Turney
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.
9 * A copy of the GNU General Public License can be found at
15 #include "package_db.h"
16 #include "package_meta.h"
19 #include "solv/solver.h"
20 #include "solv/solverdebug.h"
23 #include "LogSingleton.h"
27 // ---------------------------------------------------------------------------
28 // Utility functions for mapping between Operators and Relation Ids
29 // ---------------------------------------------------------------------------
32 Operator2RelId(PackageSpecification::_operators op
)
36 case PackageSpecification::Equals
:
38 case PackageSpecification::LessThan
:
40 case PackageSpecification::MoreThan
:
42 case PackageSpecification::LessThanEquals
:
43 return REL_LT
| REL_EQ
;
44 case PackageSpecification::MoreThanEquals
:
45 return REL_GT
| REL_EQ
;
51 static PackageSpecification::_operators
57 return PackageSpecification::Equals
;
59 return PackageSpecification::LessThan
;
61 return PackageSpecification::MoreThan
;
63 return PackageSpecification::LessThanEquals
;
65 return PackageSpecification::MoreThanEquals
;
68 return PackageSpecification::Equals
;
71 // ---------------------------------------------------------------------------
72 // implements class SolvableVersion
74 // a wrapper around a libsolv Solvable
75 // ---------------------------------------------------------------------------
78 SolvableVersion::name_id () const
80 Solvable
*solvable
= pool_id2solvable(pool
, id
);
81 return solvable
->name
;
85 SolvableVersion::Name () const
89 return pool_id2str(pool
, name_id());
93 SolvableVersion::Canonical_version() const
97 Solvable
*solvable
= pool_id2solvable(pool
, id
);
98 return std::string(pool_id2str(pool
, solvable
->evr
));
102 SolvableVersion::Type () const
105 return package_binary
;
106 Solvable
*solvable
= pool_id2solvable(pool
, id
);
107 if (solvable
->arch
== ARCH_SRC
)
108 return package_source
;
110 return package_binary
;
114 SolvableVersion::depends() const
116 return deplist(SOLVABLE_REQUIRES
);
120 SolvableVersion::obsoletes() const
122 return deplist(SOLVABLE_OBSOLETES
);
126 SolvableVersion::provides() const
128 return deplist(SOLVABLE_PROVIDES
);
132 SolvableVersion::conflicts() const
134 return deplist(SOLVABLE_CONFLICTS
);
137 // helper function which returns the deplist for a given key, as a PackageDepends
139 SolvableVersion::deplist(Id keyname
) const
141 static PackageDepends empty_package
;
143 return empty_package
;
144 Solvable
*solvable
= pool_id2solvable(pool
, id
);
149 if (repo_lookup_idarray(solvable
->repo
, id
, keyname
, &q
))
154 for (int i
= 0; i
< q
.count
; i
++)
157 Log (LOG_PLAIN
) << "dep " << std::hex
<< q
.elements
[i
] << ": " << pool_dep2str(pool
, q
.elements
[i
]) << endLog
;
160 const char *name
= pool_id2str(pool
, q
.elements
[i
]);
161 PackageSpecification
*spec
= new PackageSpecification (name
);
163 if (ISRELDEP(q
.elements
[i
]))
165 Reldep
*rd
= GETRELDEP(pool
, q
.elements
[i
]);
166 spec
->setOperator(RelId2Operator(rd
->flags
));
167 spec
->setVersion(pool_id2str(pool
, rd
->evr
));
170 dep
.push_back (spec
);
178 // otherwise, return an empty depends list
179 return empty_package
;
183 SolvableVersion::SDesc () const
187 Solvable
*solvable
= pool_id2solvable(pool
, id
);
188 const char *sdesc
= repo_lookup_str(solvable
->repo
, id
, SOLVABLE_SUMMARY
);
197 SolvableVersion::LDesc () const
201 Solvable
*solvable
= pool_id2solvable(pool
, id
);
202 const char *ldesc
= repo_lookup_str(solvable
->repo
, id
, SOLVABLE_DESCRIPTION
);
211 SolvableVersion::sourcePackageName () const
216 // extract source package name
217 Solvable
*solvable
= pool_id2solvable(pool
, id
);
218 Id spkg
= repo_lookup_id(solvable
->repo
, id
, SOLVABLE_SOURCENAME
);
220 // has no such attribute
224 return std::string(pool_id2str(pool
, spkg
));
228 SolvableVersion::Vendor () const
234 Solvable
*solvable
= pool_id2solvable(pool
, id
);
235 Id vendor
= repo_lookup_id(solvable
->repo
, id
, SOLVABLE_VENDOR
);
237 // has no such attribute
241 return std::string(pool_id2str(pool
, vendor
));
245 SolvableVersion::sourcePackage () const
248 return SolvableVersion();
250 // extract source package id
251 Solvable
*solvable
= pool_id2solvable(pool
, id
);
252 Id spkg_attr
= pool_str2id(pool
, "solvable:sourceid", 1);
253 Id spkg_id
= repo_lookup_id(solvable
->repo
, id
, spkg_attr
);
255 // has no such attribute
257 return SolvableVersion();
259 return SolvableVersion(spkg_id
, pool
);
263 SolvableVersion::fixup_spkg_id (SolvableVersion spkg_id
) const
267 Solvable
*solvable
= pool_id2solvable(pool
, id
);
268 Repodata
*data
= repo_last_repodata(solvable
->repo
);
270 Id spkg_attr
= pool_str2id(pool
, "solvable:sourceid", 1);
271 repodata_set_id(data
, handle
, spkg_attr
, spkg_id
.id
);
275 SolvableVersion::source() const
277 static packagesource empty_source
= packagesource();
279 return &empty_source
;
282 Solvable
*solvable
= pool_id2solvable(pool
, id
);
283 Id psrc_attr
= pool_str2id(pool
, "solvable:packagesource", 1);
284 return (packagesource
*)repo_lookup_num(solvable
->repo
, id
, psrc_attr
, (unsigned long long)&empty_source
);
288 SolvableVersion::accessible () const
290 // empty packages are never accessible
294 // If we're doing a local re-install, is there an archive available?
296 // (This assumes that packagemeta::ScanDownloadedFiles() has already been
297 // called to check for presence in the package cache, which would have removed
298 // the version if not available, unless it is already installed)
299 if (::source
== IDC_SOURCE_LOCALDIR
)
300 return source ()->Cached ();
302 // Otherwise, package is (presumably) retrievable
307 SolvableVersion::Stability () const
310 return TRUST_UNKNOWN
;
311 Solvable
*solvable
= pool_id2solvable(pool
, id
);
312 Id stability_attr
= pool_str2id(pool
, "solvable:stability", 1);
313 return (package_stability_t
)repo_lookup_num(solvable
->repo
, id
, stability_attr
, TRUST_UNKNOWN
);
317 SolvableVersion::operator <(SolvableVersion
const &rhs
) const
319 return (compareVersions(*this, rhs
) < 0);
323 SolvableVersion::operator ==(SolvableVersion
const &rhs
) const
325 return (compareVersions(*this, rhs
) == 0);
329 SolvableVersion::operator !=(SolvableVersion
const &rhs
) const
331 return (compareVersions(*this, rhs
) != 0);
335 SolvableVersion::compareVersions(const SolvableVersion
&a
,
336 const SolvableVersion
&b
)
341 // if a and b are different, at least one of them has a pool
342 Pool
*pool
= a
.pool
? a
.pool
: b
.pool
;
344 Solvable
*sa
= a
.id
? pool_id2solvable(a
.pool
, a
.id
) : NULL
;
345 Solvable
*sb
= b
.id
? pool_id2solvable(b
.pool
, b
.id
) : NULL
;
347 // empty versions compare as if their version is the empty string
348 Id evra
= sa
? sa
->evr
: pool_str2id(pool
, "", 1);
349 Id evrb
= sb
? sb
->evr
: pool_str2id(pool
, "", 1);
351 return pool_evrcmp(pool
, evra
, evrb
, EVRCMP_COMPARE
);
355 SolvableVersion::remove() const
360 Solvable
*solvable
= pool_id2solvable(pool
, id
);
361 repo_free_solvable(solvable
->repo
, id
, 0);
364 // ---------------------------------------------------------------------------
365 // implements class SolverPool
367 // a simplified wrapper for libsolv
368 // ---------------------------------------------------------------------------
371 void debug_callback(Pool
*pool
, void *data
, int type
, const char *str
)
373 if (type
& (SOLV_FATAL
|SOLV_ERROR
))
374 LogPlainPrintf("libsolv: %s", str
);
376 LogBabblePrintf("libsolv: %s", str
);
379 SolverPool::SolverPool()
388 pool
= pool_create();
390 pool_setdebugcallback(pool
, debug_callback
, NULL
);
396 pool_setdebuglevel(pool
, level
);
398 /* create the repo to hold installed packages */
399 SolvRepo
*installed
= getRepo("_installed");
400 pool_set_installed(pool
, installed
->repo
);
414 SolverPool::getRepo(const std::string
&name
, bool test
)
416 RepoList::iterator i
= repos
.find(name
);
417 if (i
!= repos
.end())
420 /* create repo if not found */
421 SolvRepo
*r
= new(SolvRepo
);
422 r
->repo
= repo_create(pool
, name
.c_str());
424 /* create attribute store, with no local pool */
425 r
->data
= repo_add_repodata(r
->repo
, 0);
427 /* remember if this is a test stability repo */
430 /* set default priority */
431 r
->repo
->priority
= SolvRepo::priorityNormal
;
439 Helper function to convert a PackageDepends list to libsolv dependencies.
442 SolverPool::makedeps(Repo
*repo
, PackageDepends
*requires
)
446 for (PackageDepends::iterator i
= requires
->begin();
447 i
!= requires
->end();
450 Id name
= pool_str2id(pool
, (*i
)->packageName().c_str(), 1);
452 if ((*i
)->version().size() == 0)
454 // no relation, so dependency is just on package name
455 deps
= repo_addid_dep(repo
, deps
, name
, 0);
459 // otherwise, dependency is on package name with a version condition
460 Id evr
= pool_str2id(pool
, (*i
)->version().c_str(), 1);
461 int rel
= pool_rel2id(pool
, name
, evr
, Operator2RelId((*i
)->op()), 1);
463 deps
= repo_addid_dep(repo
, deps
, rel
, 0);
471 SolverPool::addPackage(const std::string
& pkgname
, const addPackageData
&pkgdata
)
473 std::string repoName
= pkgdata
.reponame
;
476 /* It's simplest to place test packages into a separate repo, and
477 then arrange for that repo to have low priority, if we don't want
478 to install those packages by default */
480 if (pkgdata
.stability
== TRUST_TEST
&& repoName
!= "_installed")
482 repoName
= pkgdata
.reponame
+ "_test_";
486 SolvRepo
*r
= getRepo(repoName
, test
);
487 Repo
*repo
= r
->repo
;
489 /* create a solvable */
490 Id s
= repo_add_solvable(repo
);
491 Solvable
*solvable
= pool_id2solvable(pool
, s
);
493 /* initialize solvable for this packageo/version/etc. */
494 solvable
->name
= pool_str2id(pool
, pkgname
.c_str(), 1);
495 solvable
->arch
= (pkgdata
.type
== package_binary
) ? ARCH_ANY
: ARCH_SRC
;
496 solvable
->evr
= pool_str2id(repo
->pool
, pkgdata
.version
.c_str(), 1);
497 solvable
->vendor
= pool_str2id(repo
->pool
, pkgdata
.vendor
.c_str(), 1);
498 if (pkgdata
.provides
)
499 solvable
->provides
= makedeps(repo
, pkgdata
.provides
);
500 /* in the absence of specific provides, we provide what we obsolete */
501 else if (pkgdata
.obsoletes
)
502 solvable
->provides
= makedeps(repo
, pkgdata
.obsoletes
);
503 /* we always provide ourselves */
504 solvable
->provides
= repo_addid_dep(repo
, solvable
->provides
, pool_rel2id(pool
, solvable
->name
, solvable
->evr
, REL_EQ
, 1), 0);
505 if (pkgdata
.requires
)
506 solvable
->requires
= makedeps(repo
, pkgdata
.requires
);
507 if (pkgdata
.obsoletes
)
508 solvable
->obsoletes
= makedeps(repo
, pkgdata
.obsoletes
);
509 if (pkgdata
.conflicts
)
510 solvable
->conflicts
= makedeps(repo
, pkgdata
.conflicts
);
512 /* a solvable can also store arbitrary attributes not needed for dependency
513 resolution, if we need them */
515 Repodata
*data
= r
->data
;
518 Log (LOG_PLAIN
) << "solvable " << s
<< " name " << pkgname
<< endLog
;
521 /* store short description attribute */
522 repodata_set_str(data
, handle
, SOLVABLE_SUMMARY
, pkgdata
.sdesc
.c_str());
523 /* store long description attribute */
524 repodata_set_str(data
, handle
, SOLVABLE_DESCRIPTION
, pkgdata
.ldesc
.c_str());
526 /* store source-package attribute */
527 const std::string sname
= pkgdata
.spkg
.packageName();
529 repodata_set_id(data
, handle
, SOLVABLE_SOURCENAME
, pool_str2id(pool
, sname
.c_str(), 1));
531 repodata_set_void(data
, handle
, SOLVABLE_SOURCENAME
);
532 /* solvable:sourceevr may also be available from spkg but assumed to be same
533 as evr for the moment */
535 /* store source-package id */
536 /* (If the source-package hasn't been seen yet, we don't know what it's Id
537 will be. That gets fixed up later.) */
540 Id spkg_attr
= pool_str2id(pool
, "solvable:sourceid", 1);
541 repodata_set_id(data
, handle
, spkg_attr
, pkgdata
.spkg_id
.id
);
544 /* we could store packagesource information as attributes ...
547 size SOLVABLE_DOWNLOADSIZE
548 pathname SOLVABLE_MEDIAFILE
549 site SOLVABLE_MEDIABASE
550 checksum SOLVABLE_CHECKSUM
552 ... but for the moment, we just store a pointer to a packagesource object
554 Id psrc_attr
= pool_str2id(pool
, "solvable:packagesource", 1);
555 packagesource
*psrc
= new packagesource(pkgdata
.archive
);
556 repodata_set_num(data
, handle
, psrc_attr
, (intptr_t)psrc
);
558 /* store stability level attribute */
559 Id stability_attr
= pool_str2id(pool
, "solvable:stability", 1);
560 repodata_set_num(data
, handle
, stability_attr
, pkgdata
.stability
);
563 repodata_internalize(data
);
565 /* debug: verify the attributes we've just set get retrieved correctly */
566 SolvableVersion sv
= SolvableVersion(s
, pool
);
567 const std::string check_sdesc
= sv
.SDesc();
568 if (pkgdata
.sdesc
.compare(check_sdesc
) != 0) {
569 Log (LOG_PLAIN
) << pkgname
<< " has sdesc mismatch: '" << pkgdata
.sdesc
<< "' and '"
570 << check_sdesc
<< "'" << endLog
;
572 if (!sname
.empty()) {
573 SolvableVersion check_spkg
= sv
.sourcePackage();
574 Solvable
*check_spkg_solvable
= pool_id2solvable(pool
, check_spkg
.id
);
575 std::string check_sname
= pool_id2str(pool
, check_spkg_solvable
->name
);
576 if (sname
.compare(check_sname
) != 0) {
577 Log (LOG_PLAIN
) << pkgname
<< " has spkg mismatch: '" << pkgdata
.spkg
.packageName()
578 << "' and '" << check_sname
<< "'" << endLog
;
581 packagesource
*check_archive
= sv
.source();
582 if (check_archive
!= psrc
)
583 Log (LOG_PLAIN
) << pkgname
<< " has archive mismatch: " << psrc
584 << " and " << check_archive
<< endLog
;
585 package_stability_t check_stability
= sv
.Stability();
586 if (check_stability
!= pkgdata
.stability
) {
587 Log (LOG_PLAIN
) << pkgname
<< " has stability mismatch: " << pkgdata
.stability
588 << " and " << check_stability
<< endLog
;
592 return SolvableVersion(s
, pool
);
596 SolverPool::internalize()
598 /* Make attribute data available to queries */
599 for (RepoList::iterator i
= repos
.begin();
603 repodata_internalize(i
->second
->data
);
608 SolverPool::is_test_package(SolvableVersion sv
)
610 Solvable
*solvable
= pool_id2solvable(pool
, sv
.id
);
612 for (RepoList::iterator i
= repos
.begin();
616 if (solvable
->repo
== i
->second
->repo
)
617 return i
->second
->test
;
624 SolverTasks::setTasks()
626 // go through all packages, adding changed ones to the solver task list
630 for (packagedb::packagecollection::iterator p
= db
.packages
.begin ();
631 p
!= db
.packages
.end (); ++p
)
633 packagemeta
*pkg
= p
->second
;
635 switch (pkg
->get_action())
637 case packagemeta::NoChange_action
: // skip/keep
638 // keep and skip need attention only when they differ from the
642 if (!pkg
->picked() && pkg
->installed
!= pkg
->default_version
)
643 add(pkg
->installed
, taskKeep
); // keep
644 else if (pkg
->isBlacklisted(pkg
->installed
))
646 // if installed (with no action selected), but blacklisted,
647 // force a distupgrade of this package
648 add(pkg
->installed
, taskForceDistUpgrade
);
651 else if (pkg
->default_version
)
652 add(pkg
->default_version
, taskSkip
); // skip
656 case packagemeta::Install_action
:
658 add(pkg
->desired
, taskInstall
); // install/upgrade
663 // empty desired means "any version", it doesn't matter which one
664 // we use as taskInstallAny only match on the provides name
666 add(pkg
->curr
, taskInstallAny
);
668 add(pkg
->exp
, taskInstallAny
);
672 case packagemeta::Uninstall_action
:
673 add(pkg
->installed
, taskUninstall
); // uninstall
676 case packagemeta::Reinstall_action
:
677 add(pkg
->installed
, taskReinstall
); // reinstall
681 // only install action makes sense for source packages
682 if (pkg
->srcpicked())
685 add(pkg
->desired
.sourcePackage(), taskInstall
);
687 add(pkg
->installed
.sourcePackage(), taskInstall
);
693 SolverPool::use_test_packages(bool use_test_packages
)
695 // Give repos containing test packages higher priority than normal
696 // if wanted, otherwise lower priority.
697 SolvRepo::priority_t p
= use_test_packages
? SolvRepo::priorityNormal
: SolvRepo::priorityLow
;
698 for (RepoList::iterator i
= repos
.begin();
703 i
->second
->setPriority(p
);
707 // ---------------------------------------------------------------------------
708 // implements class SolverSolution
710 // A wrapper around the libsolv solver
711 // ---------------------------------------------------------------------------
713 SolverSolution::SolverSolution(SolverPool
&_pool
) : pool(_pool
), solv(NULL
)
718 SolverSolution::~SolverSolution()
724 SolverSolution::clear()
735 SolverSolution::trans2db() const
738 // First reset all packages to the "no changes" state
741 // Now make changes according to trans. transErase requires some
742 // care; it could either be a "plain" uninstall, or it could be
743 // paired with a transInstall for an upgrade/downgrade or reinstall.
744 for (SolverTransactionList::const_iterator i
= trans
.begin();
745 i
!= trans
.end(); i
++)
747 const packageversion
& pv
= i
->version
;
748 packagemeta
*pkg
= db
.findBinary(PackageSpecification(pv
.Name()));
750 // Can't happen - throw an exception?
752 Log (LOG_PLAIN
) << "Can't happen. No packagemeta for "
753 << pv
.Name() << endLog
;
758 case SolverTransaction::transInstall
:
759 if (pv
.Type() == package_binary
)
761 if (pkg
->get_action() == packagemeta::Uninstall_action
)
762 pkg
->set_action(packagemeta::Reinstall_action
, pv
);
764 pkg
->set_action(packagemeta::Install_action
, pv
);
766 pkg
->default_version
= pv
;
768 else // source package
771 case SolverTransaction::transErase
:
772 // Only relevant if pkg is still in its "no change" state
773 if (pkg
->get_action() == packagemeta::NoChange_action
)
775 pkg
->set_action(packagemeta::Uninstall_action
, packageversion());
776 pkg
->default_version
= packageversion();
786 SolverSolution::db2trans()
791 for (packagedb::packagecollection::iterator p
= db
.packages
.begin ();
792 p
!= db
.packages
.end (); ++p
)
794 packagemeta
*pkg
= p
->second
;
795 if ((pkg
->get_action() == packagemeta::Install_action
) ||
796 (pkg
->get_action() == packagemeta::Reinstall_action
))
798 trans
.push_back(SolverTransaction(pkg
->desired
, SolverTransaction::transInstall
));
800 trans
.push_back(SolverTransaction(pkg
->installed
, SolverTransaction::transErase
));
802 else if (pkg
->get_action() == packagemeta::Uninstall_action
)
803 trans
.push_back(SolverTransaction(pkg
->installed
, SolverTransaction::transErase
));
805 if (pkg
->srcpicked())
808 trans
.push_back(SolverTransaction(pkg
->desired
.sourcePackage(), SolverTransaction::transInstall
));
810 trans
.push_back(SolverTransaction(pkg
->installed
.sourcePackage(), SolverTransaction::transInstall
));
816 std::ostream
&operator<<(std::ostream
&stream
,
817 SolverTransaction::transType type
)
821 case SolverTransaction::transInstall
:
824 case SolverTransaction::transErase
:
834 SolverSolution::tasksToJobs(SolverTasks
&tasks
, updateMode update
, Queue
&job
)
836 // solver accepts a queue containing pairs of (cmd, id) tasks
837 // cmd is job and selection flags ORed together
838 for (SolverTasks::taskList::const_iterator i
= tasks
.tasks
.begin();
839 i
!= tasks
.tasks
.end();
842 const SolvableVersion
&sv
= (*i
).first
;
846 case SolverTasks::taskInstall
:
847 queue_push2(&job
, SOLVER_INSTALL
| SOLVER_SOLVABLE
, sv
.id
);
849 case SolverTasks::taskInstallAny
:
850 queue_push2(&job
, SOLVER_INSTALL
| SOLVER_SOLVABLE_PROVIDES
, sv
.name_id());
852 case SolverTasks::taskUninstall
:
853 queue_push2(&job
, SOLVER_ERASE
| SOLVER_SOLVABLE
, sv
.id
);
855 case SolverTasks::taskReinstall
:
856 // we don't know how to ask solver for this, so we just add the erase
859 case SolverTasks::taskKeep
:
860 queue_push2(&job
, SOLVER_LOCK
| SOLVER_SOLVABLE
, sv
.id
);
862 case SolverTasks::taskSkip
:
863 queue_push2(&job
, SOLVER_LOCK
| SOLVER_SOLVABLE_NAME
, sv
.name_id());
865 case SolverTasks::taskForceDistUpgrade
:
866 queue_push2(&job
, SOLVER_DISTUPGRADE
| SOLVER_SOLVABLE
, sv
.id
);
869 Log (LOG_PLAIN
) << "unknown task " << (*i
).second
<< endLog
;
873 // Ask solver to update packages
880 // Update to best version
881 queue_push2(&job
, SOLVER_UPDATE
| SOLVER_SOLVABLE_ALL
, 0);
885 // Bring installed, non-orphaned packages in sync with the ones in the
887 queue_push2(&job
, SOLVER_DISTUPGRADE
| SOLVER_SOLVABLE_ALL
, 0);
891 // Ask solver to check dependencies of installed packages.
892 queue_push2(&job
, SOLVER_VERIFY
| SOLVER_SOLVABLE_ALL
, 0);
896 SolverSolution::update(SolverTasks
&tasks
, updateMode update
, bool use_test_packages
)
898 Log (LOG_PLAIN
) << "solving: " << tasks
.tasks
.size() << " tasks," <<
899 " update: " << (update
? "yes" : "no") << "," <<
900 " use test packages: " << (use_test_packages
? "yes" : "no") << endLog
;
902 pool
.use_test_packages(use_test_packages
);
905 tasksToJobs(tasks
, update
, job
);
908 solv
= solver_create(pool
.pool
);
914 SolverSolution::solve()
916 solver_set_flag(solv
, SOLVER_FLAG_ALLOW_VENDORCHANGE
, 1);
917 solver_set_flag(solv
, SOLVER_FLAG_ALLOW_DOWNGRADE
, 0);
918 solver_set_flag(solv
, SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE
, 1);
919 solver_set_flag(solv
, SOLVER_FLAG_DUP_ALLOW_DOWNGRADE
, 1);
920 solver_solve(solv
, &job
);
922 int pcnt
= solver_problem_count(solv
);
923 solver_printdecisions(solv
);
925 solutionToTransactionList();
931 SolverSolution::solutionToTransactionList()
933 // get transactions for solution
934 Transaction
*t
= solver_create_transaction(solv
);
935 transaction_order(t
, 0);
936 transaction_print(t
);
938 // massage into SolverTransactions form
940 for (int i
= 0; i
< t
->steps
.count
; i
++)
942 Id id
= t
->steps
.elements
[i
];
943 SolverTransaction::transType tt
= type(t
, i
);
944 if (tt
!= SolverTransaction::transIgnore
)
945 trans
.push_back(SolverTransaction(SolvableVersion(id
, pool
.pool
), tt
));
951 dumpTransactionList();
956 SolverSolution::augmentTasks(SolverTasks
&tasks
)
958 // add install and remove tasks for anything marked as reinstall
959 for (SolverTasks::taskList::const_iterator i
= tasks
.tasks
.begin();
960 i
!= tasks
.tasks
.end();
963 const SolvableVersion
&sv
= (*i
).first
;
965 if (sv
&& (((*i
).second
) == SolverTasks::taskReinstall
))
967 trans
.push_back(SolverTransaction(SolvableVersion(sv
.id
, pool
.pool
),
968 SolverTransaction::transErase
));
969 trans
.push_back(SolverTransaction(SolvableVersion(sv
.id
, pool
.pool
),
970 SolverTransaction::transInstall
));
976 SolverSolution::addSource(bool include_source
)
978 // if include_source mode is on, also install source for everything we are
982 // (this uses indicies into the vector, as iterators might become
983 // invalidated by doing push_back)
984 size_t n
= trans
.size();
985 for (size_t i
= 0; i
< n
; i
++)
987 if (trans
[i
].type
== SolverTransaction::transInstall
)
989 SolvableVersion src_version
= trans
[i
].version
.sourcePackage();
991 trans
.push_back(SolverTransaction(src_version
,
992 SolverTransaction::transInstall
));
999 SolverSolution::dumpTransactionList() const
1003 size_t width_name
= 0;
1004 size_t width_version
= 0;
1006 for (SolverTransactionList::const_iterator i
= trans
.begin ();
1010 width_name
= std::max(width_name
, i
->version
.Name().length()+1);
1011 width_version
= std::max(width_version
, i
->version
.Canonical_version().length()+1);
1014 Log (LOG_PLAIN
) << "Augmented Transaction List:" << endLog
;
1015 for (SolverTransactionList::const_iterator i
= trans
.begin ();
1019 Log (LOG_PLAIN
) << std::setw(4) << std::distance(trans
.begin(), i
)
1020 << std::setw(8) << i
->type
<< " "
1022 << std::setw(width_name
) << i
->version
.Name()
1023 << std::setw(width_version
) << i
->version
.Canonical_version() << endLog
;
1027 Log (LOG_PLAIN
) << "Augmented Transaction List: is empty" << endLog
;
1030 void SolverSolution::applyDefaultProblemSolutions()
1032 // adjust the task list with the default solutions
1033 int pcnt
= solver_problem_count(solv
);
1034 for (Id problem
= 1; problem
<= pcnt
; problem
++)
1036 int scnt
= solver_solution_count(solv
, problem
);
1037 solver_take_solution(solv
, problem
, scnt
, &job
);
1042 Log (LOG_PLAIN
) << "default solutions did not solve all problems!" << endLog
;
1045 const SolverTransactionList
&
1046 SolverSolution::transactions() const
1051 // Construct a string reporting the problems and solutions
1053 SolverSolution::report() const
1057 int pcnt
= solver_problem_count(solv
);
1058 for (Id problem
= 1; problem
<= pcnt
; problem
++)
1060 r
+= "Problem " + std::to_string(problem
) + "/" + std::to_string(pcnt
);
1063 Id probr
= solver_findproblemrule(solv
, problem
);
1064 Id dep
, source
, target
;
1065 SolverRuleinfo type
= solver_ruleinfo(solv
, probr
, &source
, &target
, &dep
);
1066 if (source
== db
.basepkg
.id
)
1067 r
+= "package " + std::string(pool_dep2str(pool
.pool
, dep
)) + " is a Base package and is therefore required";
1069 r
+= solver_problemruleinfo2str(solv
, type
, source
, target
, dep
);
1072 int scnt
= solver_solution_count(solv
, problem
);
1073 for (Id solution
= 1; solution
<= scnt
; solution
++)
1075 r
+= "Solution " + std::to_string(solution
) + "/" + std::to_string(scnt
);
1076 if (solution
== scnt
) r
+= " (default)";
1081 while ((element
= solver_next_solutionelement(solv
, problem
, solution
, element
, &p
, &rp
)) != 0)
1084 if (p
== db
.basepkg
.id
)
1085 r
+= "allow deinstallation of Base packages";
1087 r
+= solver_solutionelement2str(solv
, p
, rp
);
1093 // since package arch isn't set usefully at the moment, remove all ".any" from
1094 // package names in the problem report string.
1095 std::string any
= ".any";
1097 while ((pos
= r
.find(any
)) != std::string::npos
)
1099 r
.replace(pos
, any
.length(), "");
1105 // helper function to map transaction type
1106 SolverTransaction::transType
1107 SolverSolution::type(Transaction
*trans
, int pos
)
1109 Id tt
= transaction_type(trans
, trans
->steps
.elements
[pos
],
1110 SOLVER_TRANSACTION_SHOW_ACTIVE
);
1112 // if active side of transaction is nothing, ask again for passive side of
1114 if (tt
== SOLVER_TRANSACTION_IGNORE
)
1115 tt
= transaction_type(trans
, trans
->steps
.elements
[pos
], 0);
1119 case SOLVER_TRANSACTION_INSTALL
:
1120 case SOLVER_TRANSACTION_REINSTALL
:
1121 case SOLVER_TRANSACTION_UPGRADE
:
1122 case SOLVER_TRANSACTION_DOWNGRADE
:
1123 return SolverTransaction::transInstall
;
1124 case SOLVER_TRANSACTION_ERASE
:
1125 case SOLVER_TRANSACTION_REINSTALLED
:
1126 case SOLVER_TRANSACTION_UPGRADED
:
1127 case SOLVER_TRANSACTION_DOWNGRADED
:
1128 return SolverTransaction::transErase
;
1130 Log (LOG_PLAIN
) << "unknown transaction type " << std::hex
<< tt
<< endLog
;
1131 case SOLVER_TRANSACTION_CHANGE
:
1132 case SOLVER_TRANSACTION_CHANGED
:
1133 case SOLVER_TRANSACTION_IGNORE
:
1134 return SolverTransaction::transIgnore
;