diff options
| author | Julian Andres Klode <jak@debian.org> | 2025-03-09 13:29:29 +0000 |
|---|---|---|
| committer | Julian Andres Klode <jak@debian.org> | 2025-03-09 13:29:29 +0000 |
| commit | 153bbf448f91eb347574624890c36f97cd168b53 (patch) | |
| tree | 8f5f98fbe27ac7060b38e545eb43317215f1ae89 | |
| parent | 1e7f123ea59d6ae3af74725d4dab846f81d122e8 (diff) | |
| parent | 6c112f9860c1730237029f4e23d40bf658d73704 (diff) | |
Merge branch 'transaction' into 'main'
Run 3.0 solver if internal is unsuccessful or we have apport for automatic solver evaluation
See merge request apt-team/apt!446
| -rw-r--r-- | apt-pkg/depcache.cc | 87 | ||||
| -rw-r--r-- | apt-pkg/depcache.h | 39 | ||||
| -rw-r--r-- | apt-private/private-install.cc | 312 | ||||
| -rw-r--r-- | doc/examples/configure-index | 2 | ||||
| -rw-r--r-- | test/integration/framework | 2 | ||||
| -rwxr-xr-x | test/integration/test-bug-745046-candidate-propagation-fails | 1 | ||||
| -rwxr-xr-x | test/integration/test-release-candidate-switching | 1 | ||||
| -rwxr-xr-x | test/integration/test-solver3-evaluation | 239 |
8 files changed, 597 insertions, 86 deletions
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 970b4c01d..f7f508f85 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -110,6 +110,7 @@ struct pkgDepCache::Private std::unique_ptr<InRootSetFunc> inRootSetFunc; std::unique_ptr<APT::CacheFilter::Matcher> IsAVersionedKernelPackage, IsProtectedKernelPackage; std::string machineID; + unsigned long iUpgradeCount{0}; }; pkgDepCache::pkgDepCache(pkgCache *const pCache, Policy *const Plcy) : group_level(0), Cache(pCache), PkgState(0), DepState(0), iUsrSize(0), iDownloadSize(0), iInstCount(0), iDelCount(0), iKeepCount(0), @@ -148,6 +149,7 @@ bool pkgDepCache::CheckConsistency(char const *const msgtag) /*{{{*/ auto const origUsrSize = iUsrSize; auto const origDownloadSize = iDownloadSize; auto const origInstCount = iInstCount; + auto const origUpgradeCount = d->iUpgradeCount; auto const origDelCount = iDelCount; auto const origKeepCount = iKeepCount; auto const origBrokenCount = iBrokenCount; @@ -208,6 +210,7 @@ bool pkgDepCache::CheckConsistency(char const *const msgtag) /*{{{*/ iUsrSize = origUsrSize; iDownloadSize = origDownloadSize; iInstCount = origInstCount; + d->iUpgradeCount = origUpgradeCount; iDelCount = origDelCount; iKeepCount = origKeepCount; iBrokenCount = origBrokenCount; @@ -632,7 +635,11 @@ void pkgDepCache::AddStates(const PkgIterator &Pkg, bool const Invert) else if (State.Mode == ModeKeep) iKeepCount += Add; else if (State.Mode == ModeInstall) + { iInstCount += Add; + if (Pkg->CurrentVer != 0 && State.Status > 0) + d->iUpgradeCount += Add; + } } /*}}}*/ // DepCache::BuildGroupOrs - Generate the Or group dep data /*{{{*/ @@ -762,6 +769,7 @@ void pkgDepCache::PerformDependencyPass(OpProgress * const Prog) iUsrSize = 0; iDownloadSize = 0; iInstCount = 0; + d->iUpgradeCount = 0; iDelCount = 0; iKeepCount = 0; iBrokenCount = 0; @@ -2650,3 +2658,82 @@ unsigned long long pkgDepCache::BootSize(bool initrdOnly) return std::accumulate(sizes, sizes + MAX_ARTEFACT, off_t{0}) * BootCount * 110 / 100; } /*}}}*/ +// pkgDepCache::UpgradeCount /*{{{*/ +unsigned long pkgDepCache::UpgradeCount() +{ + return d->iUpgradeCount; +} + /*}}}*/ +// pkgDepCache::Transaction /*{{{*/ +struct pkgDepCache::Transaction::Private +{ + template <typename T> + static T *copyArray(T *array, size_t count) + { + auto out = new T[count]; + memcpy(&out[0], &array[0], sizeof(T) * count); + return out; + } + // State information + pkgDepCache &cache; + Behavior behavior; + std::unique_ptr<StateCache[]> PkgState{copyArray(cache.PkgState, cache.GetCache().Head().PackageCount)}; + std::unique_ptr<unsigned char[]> DepState{copyArray(cache.DepState, cache.GetCache().Head().DependsCount)}; + signed long long iUsrSize{cache.iUsrSize}; + unsigned long long iDownloadSize{cache.iDownloadSize}; + unsigned long iInstCount{cache.iInstCount}; + unsigned long iUpgradeCount{cache.d->iUpgradeCount}; + unsigned long iDelCount{cache.iDelCount}; + unsigned long iKeepCount{cache.iKeepCount}; + unsigned long iBrokenCount{cache.iBrokenCount}; + unsigned long iPolicyBrokenCount{cache.iPolicyBrokenCount}; + unsigned long iBadCount{cache.iBadCount}; + + void rollback() + { + memcpy(&cache.PkgState[0], &PkgState[0], sizeof(PkgState[0]) * cache.GetCache().Head().PackageCount); + memcpy(&cache.DepState[0], &DepState[0], sizeof(DepState[0]) * cache.GetCache().Head().DependsCount); + + cache.iUsrSize = iUsrSize; + cache.iDownloadSize = iDownloadSize; + cache.iInstCount = iInstCount; + cache.d->iUpgradeCount = iUpgradeCount; + cache.iDelCount = iDelCount; + cache.iKeepCount = iKeepCount; + cache.iBrokenCount = iBrokenCount; + cache.iPolicyBrokenCount = iPolicyBrokenCount; + cache.iBadCount = iBadCount; + } +}; + +pkgDepCache::Transaction::Transaction(pkgDepCache &cache, Behavior behavior) : d(new Private{cache, behavior}) {} + +void pkgDepCache::Transaction::temporaryRollback() +{ + d->rollback(); +} + +void pkgDepCache::Transaction::commit() +{ + d.reset(); +} + +void pkgDepCache::Transaction::rollback() +{ + if (d == nullptr) + return; + + temporaryRollback(); + d.reset(); +} + +pkgDepCache::Transaction::~Transaction() +{ + if (not d) + return; + if (d->behavior == Behavior::ROLLBACK || (d->behavior == Behavior::AUTO && d->cache.iBrokenCount > d->iBrokenCount)) + rollback(); + else + commit(); +} + /*}}}*/ diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 39d34d3e4..bab524853 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -267,6 +267,42 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace bool InstallSuggests; }; + /** + * \brief Perform changes to the depcache atomically. + * + * The default policy for a transaction is to rollback if the number of broken packages + * increased, otherwise to commit. Call commit() or rollback() to override the default + * policy. + */ + class APT_PUBLIC Transaction final + { + struct Private; + std::unique_ptr<Private> d; + + public: + enum class Behavior + { + COMMIT, + ROLLBACK, + AUTO, + }; + + explicit Transaction(pkgDepCache &cache, Behavior behavior); + /** \brief Commit the transaction immediately */ + void commit(); + /** \brief Rollback the transaction immediately */ + void rollback(); + /** \brief Like rollback, but can be called multiple times. + * + * You can for example create a new transaction, then temporarily + * rollback to the state before the previous transaction in that + * transaction. + */ + void temporaryRollback(); + /** \brief Commit or rollback the transaction based on default policy */ + ~Transaction(); + }; + private: /** The number of open "action groups"; certain post-action * operations are suppressed if this number is > 0. @@ -274,6 +310,8 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace int group_level; friend class ActionGroup; + friend class Transaction; + public: int IncreaseActionGroupLevel(); int DecreaseActionGroupLevel(); @@ -479,6 +517,7 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace inline unsigned long DelCount() {return iDelCount;}; inline unsigned long KeepCount() {return iKeepCount;}; inline unsigned long InstCount() {return iInstCount;}; + unsigned long UpgradeCount(); inline unsigned long BrokenCount() {return iBrokenCount;}; inline unsigned long PolicyBrokenCount() {return iPolicyBrokenCount;}; inline unsigned long BadCount() {return iBadCount;}; diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index 208a27749..29e23a57e 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -28,6 +28,7 @@ #include <iostream> #include <map> #include <set> +#include <sstream> #include <vector> #include <langinfo.h> #include <sys/statvfs.h> @@ -45,7 +46,7 @@ /*}}}*/ class pkgSourceList; -bool CheckNothingBroken(CacheFile &Cache) /*{{{*/ +static bool CheckNothingBroken(std::ostream &out, CacheFile &Cache) /*{{{*/ { // Now we check the state of the packages, if (Cache->BrokenCount() == 0) @@ -55,11 +56,11 @@ bool CheckNothingBroken(CacheFile &Cache) /*{{{*/ if (_error->PendingError() && _config->Find("APT::Solver") == "dump") return false; - c1out << - _("Some packages could not be installed. This may mean that you have\n" + out << _("Some packages could not be installed. This may mean that you have\n" "requested an impossible situation or if you are using the unstable\n" "distribution that some required packages have not yet been created\n" - "or been moved out of Incoming.") << std::endl; + "or been moved out of Incoming.") + << std::endl; /* if (Packages == 1) { @@ -71,15 +72,68 @@ bool CheckNothingBroken(CacheFile &Cache) /*{{{*/ } */ - c1out << _("The following information may help to resolve the situation:") << std::endl; - c1out << std::endl; - ShowBroken(c1out,Cache,false); + out << _("The following information may help to resolve the situation:") << std::endl; + out << std::endl; + ShowBroken(out, Cache, false); if (_error->PendingError() == true) return false; else return _error->Error(_("Broken packages")); } +bool CheckNothingBroken(CacheFile &Cache) +{ + return CheckNothingBroken(c1out, Cache); +} /*}}}*/ +// WriteApportReport - Write an apport bug report /*{{{*/ +// --------------------------------------------------------------------- +static void WriteApportReport(pkgCacheFile &Cache, std::string &title, std::vector<std::string> const &errors, int mode, bool distUpgrade) +{ + auto dumpfile = flCombine(_config->FindDir("Dir::Log"), "edsp.log"); + auto crashfile = flCombine(_config->FindDir("Dir::Apport", "/var/crash"), "apt-edsp." + std::to_string(getuid()) + ".crash"); + auto apt = Cache->FindPkg("apt"); + if (access(flNotFile(dumpfile).c_str(), W_OK) != 0 || access(flNotFile(crashfile).c_str(), W_OK) != 0) + return; + OpTextProgress Progress(*_config); + Progress.OverallProgress(0, 100, 50, _("Writing error report")); + FileFd edspDump(dumpfile, + FileFd::Exclusive | FileFd::Create | FileFd::WriteOnly | FileFd::BufferedWrite); + int edspFlags = 0; + if (mode || distUpgrade) + edspFlags |= EDSP::Request::UPGRADE_ALL; + if (mode & APT::Upgrade::FORBID_REMOVE_PACKAGES) + edspFlags |= EDSP::Request::FORBID_REMOVE; + if (mode & APT::Upgrade::FORBID_INSTALL_NEW_PACKAGES) + edspFlags |= EDSP::Request::FORBID_NEW_INSTALL; + + EDSP::WriteRequest(Cache, edspDump, edspFlags, &Progress); + EDSP::WriteScenario(Cache, edspDump, &Progress); + edspDump.Close(); + + Progress.OverallProgress(50, 100, 50, _("Writing error report")); + + std::ofstream crash(crashfile, std::ios::out | std::ios::trunc); + chmod(crashfile.c_str(), 0600); + time_t now = time(NULL); + char ctime_buf[26]; // need at least 26 bytes according to ctime(3) + crash << "ProblemType: AptSolver\n" + << "Architecture: " << _config->Find("APT::Architecture") << "\n" + << "Date: " << ctime_r(&now, ctime_buf) + << "Package: apt " << (apt.end() || apt.CurrentVer().end() ? "" : apt.CurrentVer().VerStr()) << "\n" + << "Title: " << title << "\n" + << "SourcePackage: apt\n"; + + crash << "ErrorMessage:\n"; + for (auto &error : errors) + crash << " " << error << "\n"; + + crash << "AptSolverDump:\n"; + std::ifstream toCopy(edspDump.Name()); + for (std::string line; std::getline(toCopy, line);) + crash << " " << line << "\n"; + crash.close(); +} + // InstallPackages - Actually download and install the packages /*{{{*/ // --------------------------------------------------------------------- /* This displays the informative messages describing what is going to @@ -836,85 +890,171 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector<PseudoPkg TryToInstall InstallAction(Cache, Fix.get(), BrokenFix); TryToRemove RemoveAction(Cache, Fix.get()); APT::PackageSet UpgradablePackages; - - { - unsigned short const order[] = { MOD_REMOVE, MOD_INSTALL, 0 }; - - for (unsigned short i = 0; order[i] != 0; ++i) - { - if (order[i] == MOD_INSTALL) - InstallAction = std::for_each(verset[MOD_INSTALL].begin(), verset[MOD_INSTALL].end(), InstallAction); - else if (order[i] == MOD_REMOVE) - RemoveAction = std::for_each(verset[MOD_REMOVE].begin(), verset[MOD_REMOVE].end(), RemoveAction); - } - - { - APT::CacheSetHelper helper; - helper.PackageFrom(APT::CacheSetHelper::PATTERN, &UpgradablePackages, Cache, "?upgradable"); - } - - if (Fix != NULL && _config->FindB("APT::Get::AutoSolving", true) == true) - { - InstallAction.propagateReleaseCandidateSwitching(helper.selectedByRelease, c0out); - InstallAction.doAutoInstall(); - } - - if (_error->PendingError() == true) - { - return false; - } - - /* If we are in the Broken fixing mode we do not attempt to fix the - problems. This is if the user invoked install without -f and gave - packages */ - if (BrokenFix == true && Cache->BrokenCount() != 0) - { - c1out << _("You might want to run 'apt --fix-broken install' to correct these.") << std::endl; - ShowBroken(c1out,Cache,false); - return _error->Error(_("Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).")); - } - - if (Fix != NULL) - { - // Call the scored problem resolver - OpTextProgress Progress(*_config); - bool const distUpgradeMode = strcmp(CmdL.FileList[0], "dist-upgrade") == 0 || strcmp(CmdL.FileList[0], "full-upgrade") == 0; - - if (distUpgradeMode && _config->Find("Binary") == "apt") - _config->CndSet("APT::Get::AutomaticRemove::Kernels", _config->FindB("APT::Get::AutomaticRemove", true)); - - bool resolver_fail = false; - if (distUpgradeMode == true || UpgradeMode != APT::Upgrade::ALLOW_EVERYTHING) - resolver_fail = APT::Upgrade::Upgrade(Cache, UpgradeMode, &Progress); - else - resolver_fail = Fix->Resolve(true, &Progress); - - if (resolver_fail == false && Cache->BrokenCount() == 0) - return false; - } - - if (CheckNothingBroken(Cache) == false) - return false; - } - if (!DoAutomaticRemove(Cache)) - return false; - - // if nothing changed in the cache, but only the automark information - // we write the StateFile here, otherwise it will be written in - // cache.commit() - if (InstallAction.AutoMarkChanged > 0 && - Cache->DelCount() == 0 && Cache->InstCount() == 0 && - Cache->BadCount() == 0 && - _config->FindB("APT::Get::Simulate",false) == false) - Cache->writeStateFile(NULL); - - SortedPackageUniverse Universe(Cache); - for (auto const &Pkg: Universe) - if (Pkg->CurrentVer != 0 && not Cache[Pkg].Upgrade() && not Cache[Pkg].Delete() && - UpgradablePackages.find(Pkg) != UpgradablePackages.end()) - HeldBackPackages.push_back(Pkg); - - return true; + bool const distUpgradeMode = strcmp(CmdL.FileList[0], "dist-upgrade") == 0 || strcmp(CmdL.FileList[0], "full-upgrade") == 0; + + { + unsigned short const order[] = {MOD_REMOVE, MOD_INSTALL, 0}; + + for (unsigned short i = 0; order[i] != 0; ++i) + { + if (order[i] == MOD_INSTALL) + InstallAction = std::for_each(verset[MOD_INSTALL].begin(), verset[MOD_INSTALL].end(), InstallAction); + else if (order[i] == MOD_REMOVE) + RemoveAction = std::for_each(verset[MOD_REMOVE].begin(), verset[MOD_REMOVE].end(), RemoveAction); + } + + { + APT::CacheSetHelper helper; + helper.PackageFrom(APT::CacheSetHelper::PATTERN, &UpgradablePackages, Cache, "?upgradable"); + } + + // Record the state before we call the solver. + pkgDepCache::Transaction transaction(Cache, pkgDepCache::Transaction::Behavior::COMMIT); + auto runTheSolver = [&](std::ostream &out) -> bool + { + if (Fix != NULL && _config->FindB("APT::Get::AutoSolving", true) == true) + { + InstallAction.propagateReleaseCandidateSwitching(helper.selectedByRelease, c0out); + InstallAction.doAutoInstall(); + } + + if (_error->PendingError() == true) + { + return false; + } + + /* If we are in the Broken fixing mode we do not attempt to fix the + problems. This is if the user invoked install without -f and gave + packages */ + if (BrokenFix == true && Cache->BrokenCount() != 0) + { + out << _("You might want to run 'apt --fix-broken install' to correct these.") << std::endl; + ShowBroken(out, Cache, false); + return _error->Error(_("Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).")); + } + + if (Fix != NULL) + { + // Call the scored problem resolver + OpTextProgress Progress(*_config); + + if (distUpgradeMode && _config->Find("Binary") == "apt") + _config->CndSet("APT::Get::AutomaticRemove::Kernels", _config->FindB("APT::Get::AutomaticRemove", true)); + + bool resolver_fail = false; + if (distUpgradeMode == true || UpgradeMode != APT::Upgrade::ALLOW_EVERYTHING) + resolver_fail = APT::Upgrade::Upgrade(Cache, UpgradeMode, &Progress); + else + resolver_fail = Fix->Resolve(true, &Progress); + + if (resolver_fail == false && Cache->BrokenCount() == 0) + return false; + } + + if (CheckNothingBroken(out, Cache) == false) + return false; + + return true; + }; + + std::ostringstream out; + _error->PushToStack(); + auto res = runTheSolver(out); + + // 3.0 solver is a bit more strict and applies the rules to user provided arguments as well, so if you provide + // a removal request, but don't allow removals, it fails; or if you install something conflicting with an installed + // package during an `upgrade` run, that's the same problem. So if an upgrade restriction is set and we have + // arguments specified, don't try solver3. + auto invalidCombinations = UpgradeMode && (not verset[MOD_REMOVE].empty() || not verset[MOD_INSTALL].empty()); + // Fallback to 3.0 if we don't get a result or apport is installed + if (not invalidCombinations && _config->Find("APT::Solver", "internal") == "internal" && (not res || (not Cache->FindPkg("apport").end() && Cache->FindPkg("apport")->CurrentVer))) + { + auto internalBroken = Cache->BrokenCount(); + auto internalDel = Cache->DelCount(); + auto internalInst = Cache->InstCount(); + auto internalUpgrade = Cache->UpgradeCount(); + auto internalKeep = Cache->KeepCount(); + + // Create a nested transaction. When leaving this scope, we are back to the 'internal' result. + pkgDepCache::Transaction solver3(Cache, pkgDepCache::Transaction::Behavior::ROLLBACK); + transaction.temporaryRollback(); // Rollback to before internal solver made changes + + std::vector<std::string> errors; + _error->PushToStack(); + _config->Set("APT::Solver", "3.0"); + _config->CndSet("APT::Solver::RemoveManual", "true"); // otherwise we are always "worse" + std::ofstream solver3out; // empty out stream... + bool solver3Res = runTheSolver(solver3out); + + std::string str; + while (not _error->empty()) + if (_error->PopMessage(str)) + errors.push_back(str); + _config->Set("APT::Solver", "internal"); + _error->RevertToStack(); + // An error summary for apport. + std::string error; + if (solver3Res && Cache->BrokenCount()) + { + error = "Internal error: The 3.0 solver produced a broken cache"; + } + else if (not solver3Res || Cache->BrokenCount() || not errors.empty()) + { + if (res && not internalBroken) + error = "Failure: The 3.0 solver did not find a result"; + } + else if (not res) + { + // Commit the changes from the 3.0 solver. This in turn commits the 3.0 transaction into the internal + // transaction which sounds a bit awkward, but that's the way it goes: commit() is just delete the + // transaction stage so it can't rollback. + _error->Discard(); + _error->Audit(_("Result calculated by the 3.0 solver.")); + solver3.commit(); + res = true; + } + else if (std::make_tuple(Cache->DelCount(), -Cache->UpgradeCount(), Cache->KeepCount(), Cache->InstCount()) > std::make_tuple(internalDel, -internalUpgrade, internalKeep, internalInst)) + { + error = "Failure: The 3.0 solver produced a worse result"; + } + + if (res && not error.empty() && not Cache->FindPkg("apport").end() && Cache->FindPkg("apport")->CurrentVer) + { + pkgDepCache::Transaction dumpTransaction(Cache, pkgDepCache::Transaction::Behavior::ROLLBACK); + transaction.temporaryRollback(); // Rollback to before internal solver made changes so we can dump the OG request + WriteApportReport(Cache, error, errors, UpgradeMode, distUpgradeMode); + } + + if (not res && not errors.empty() && not _config->FindB("quiet::NoSolver3Explanation", false)) + _error->Error("The following information from --solver 3.0 may provide additional context:\n%s", APT::String::Join(errors, "\n").c_str()); + } + // If the 3.0 solver could not recover either, abort. + _error->MergeWithStack(); + if (not res) + { + c1out << out.str() << std::flush; + return false; + } + } + if (!DoAutomaticRemove(Cache)) + return false; + + // if nothing changed in the cache, but only the automark information + // we write the StateFile here, otherwise it will be written in + // cache.commit() + if (InstallAction.AutoMarkChanged > 0 && + Cache->DelCount() == 0 && Cache->InstCount() == 0 && + Cache->BadCount() == 0 && + _config->FindB("APT::Get::Simulate", false) == false) + Cache->writeStateFile(NULL); + + SortedPackageUniverse Universe(Cache); + for (auto const &Pkg : Universe) + if (Pkg->CurrentVer != 0 && not Cache[Pkg].Upgrade() && not Cache[Pkg].Delete() && + UpgradablePackages.find(Pkg) != UpgradablePackages.end()) + HeldBackPackages.push_back(Pkg); + + return true; } /*}}}*/ bool AddVolatileSourceFile(pkgSourceList *const SL, PseudoPkg &&pkg, std::vector<PseudoPkg> &VolatileCmdL)/*{{{*/ diff --git a/doc/examples/configure-index b/doc/examples/configure-index index 8476d733a..c36f922b6 100644 --- a/doc/examples/configure-index +++ b/doc/examples/configure-index @@ -33,6 +33,7 @@ quiet "<INT>" { NoUpdate "<BOOL>"; // never update progress information - included in -q=1 NoProgress "<BOOL>"; // disables the 0% → 100% progress on cache generation and stuff NoStatistic "<BOOL>"; // no "42 kB downloaded" stats in update + NoSolver3Explanation "<BOOL>"; // do not print solver3 explanations when used with internal solver ReleaseInfoChange "<BOOL>" // don't even print the notices if the info change is allowed { Origin "<BOOL>"; @@ -464,6 +465,7 @@ Dir "<DIR>" Boot "<DIR>"; Usr "<DIR>"; + Apport "<DIR>"; }; // Things that effect the APT dselect method diff --git a/test/integration/framework b/test/integration/framework index d2570b6b2..3f0290569 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -589,6 +589,8 @@ EOF echo 'DPkg::Path "";' >> aptconfig.conf echo 'Dir::Bin::ischroot "/bin/false";' >> aptconfig.conf + echo 'quiet::NoSolver3Explanation "true";' > rootdir/etc/apt/apt.conf.d/disable-solver3-context + # most tests just need one signed Release file, not both export APT_DONT_SIGN='Release.gpg' diff --git a/test/integration/test-bug-745046-candidate-propagation-fails b/test/integration/test-bug-745046-candidate-propagation-fails index 8475a4ea1..f4fc15e0e 100755 --- a/test/integration/test-bug-745046-candidate-propagation-fails +++ b/test/integration/test-bug-745046-candidate-propagation-fails @@ -17,6 +17,7 @@ setupaptarchive testfailureequal "Reading package lists... Building dependency tree... Selected version '2' (experimental [amd64]) for 'gedit' +Selected version '2' (experimental [amd64]) for 'gedit' Some packages could not be installed. This may mean that you have requested an impossible situation or if you are using the unstable distribution that some required packages have not yet been created diff --git a/test/integration/test-release-candidate-switching b/test/integration/test-release-candidate-switching index be5b3f997..52d3e5a12 100755 --- a/test/integration/test-release-candidate-switching +++ b/test/integration/test-release-candidate-switching @@ -424,6 +424,7 @@ E: Trivial Only specified but this is not a trivial operation." aptget install a testfailureequal "Reading package lists... Building dependency tree... Selected version '1.0' (experimental [all]) for 'uninstallablepkg' +Selected version '1.0' (experimental [all]) for 'uninstallablepkg' Some packages could not be installed. This may mean that you have requested an impossible situation or if you are using the unstable distribution that some required packages have not yet been created diff --git a/test/integration/test-solver3-evaluation b/test/integration/test-solver3-evaluation new file mode 100755 index 000000000..af12698b5 --- /dev/null +++ b/test/integration/test-solver3-evaluation @@ -0,0 +1,239 @@ +#!/bin/sh +set -e + +TESTDIR="$(readlink -f "$(dirname "$0")")" +. "$TESTDIR/framework" +setupenvironment +configarchitecture 'amd64' + +insertinstalledpackage 'apport' 'all' '3' + +insertpackage 'unstable' 'x' 'all' '3' 'Depends: a | b' +insertpackage 'unstable' 'y' 'all' '3' 'Depends: b | a' +insertpackage 'unstable' 'a' 'all' '3' 'Depends: c' +insertpackage 'unstable' 'b' 'all' '3' +insertpackage 'unstable' 'c' 'all' '3' + +setupaptarchive + +rm rootdir/etc/apt/apt.conf.d/disable-solver3-context +mkdir rootdir/var/log/apt + +testsuccess aptget install y x --solver internal -s -o Dir::Apport=var/crash + +testsuccess sed -i "s/^Date:.*/Date: Sun Mar 9 00:08:41 2025/" rootdir/var/crash/apt-edsp.$(id -u).crash + +testsuccessequal "ProblemType: AptSolver +Architecture: amd64 +Date: Sun Mar 9 00:08:41 2025 +Package: apt +Title: Failure: The 3.0 solver produced a worse result +SourcePackage: apt +ErrorMessage: +AptSolverDump: + Request: EDSP 0.5 + Architecture: amd64 + Architectures: amd64 + Machine-ID: 912e43bd1c1d4ba481f9f8ccab25f9ee + Install: x:amd64 y:amd64 + Solver: internal + + Package: a + Architecture: all + Version: 3 + APT-ID: 2 + Source: a + Source-Version: 3 + Priority: optional + Section: other + Size: 42 + APT-Release: + a=unstable,n=sid,c=main,b=all + APT-Pin: 500 + APT-Candidate: yes + Depends: c + + Package: b + Architecture: all + Version: 3 + APT-ID: 3 + Source: b + Source-Version: 3 + Priority: optional + Section: other + Size: 42 + APT-Release: + a=unstable,n=sid,c=main,b=all + APT-Pin: 500 + APT-Candidate: yes + + Package: c + Architecture: all + Version: 3 + APT-ID: 4 + Source: c + Source-Version: 3 + Priority: optional + Section: other + Size: 42 + APT-Release: + a=unstable,n=sid,c=main,b=all + APT-Pin: 500 + APT-Candidate: yes + + Package: x + Architecture: all + Version: 3 + APT-ID: 0 + Source: x + Source-Version: 3 + Priority: optional + Section: other + Size: 42 + APT-Release: + a=unstable,n=sid,c=main,b=all + APT-Pin: 500 + APT-Candidate: yes + Depends: a | b + + Package: y + Architecture: all + Version: 3 + APT-ID: 1 + Source: y + Source-Version: 3 + Priority: optional + Section: other + Size: 42 + APT-Release: + a=unstable,n=sid,c=main,b=all + APT-Pin: 500 + APT-Candidate: yes + Depends: b | a + + Package: apport + Architecture: all + Version: 3 + APT-ID: 5 + Source: apport + Source-Version: 3 + Priority: optional + Section: other + Installed: yes + APT-Pin: 100 + APT-Candidate: yes + " cat rootdir/var/crash/apt-edsp.$(id -u).crash + + +testsuccessequal "Request: EDSP 0.5 +Architecture: amd64 +Architectures: amd64 +Machine-ID: 912e43bd1c1d4ba481f9f8ccab25f9ee +Install: x:amd64 y:amd64 +Solver: internal + +Package: a +Architecture: all +Version: 3 +APT-ID: 2 +Source: a +Source-Version: 3 +Priority: optional +Section: other +Size: 42 +APT-Release: + a=unstable,n=sid,c=main,b=all +APT-Pin: 500 +APT-Candidate: yes +Depends: c + +Package: b +Architecture: all +Version: 3 +APT-ID: 3 +Source: b +Source-Version: 3 +Priority: optional +Section: other +Size: 42 +APT-Release: + a=unstable,n=sid,c=main,b=all +APT-Pin: 500 +APT-Candidate: yes + +Package: c +Architecture: all +Version: 3 +APT-ID: 4 +Source: c +Source-Version: 3 +Priority: optional +Section: other +Size: 42 +APT-Release: + a=unstable,n=sid,c=main,b=all +APT-Pin: 500 +APT-Candidate: yes + +Package: x +Architecture: all +Version: 3 +APT-ID: 0 +Source: x +Source-Version: 3 +Priority: optional +Section: other +Size: 42 +APT-Release: + a=unstable,n=sid,c=main,b=all +APT-Pin: 500 +APT-Candidate: yes +Depends: a | b + +Package: y +Architecture: all +Version: 3 +APT-ID: 1 +Source: y +Source-Version: 3 +Priority: optional +Section: other +Size: 42 +APT-Release: + a=unstable,n=sid,c=main,b=all +APT-Pin: 500 +APT-Candidate: yes +Depends: b | a + +Package: apport +Architecture: all +Version: 3 +APT-ID: 5 +Source: apport +Source-Version: 3 +Priority: optional +Section: other +Installed: yes +APT-Pin: 100 +APT-Candidate: yes +" cat rootdir/var/log/apt/edsp.log + +testfailureequal "Reading package lists... +Building dependency tree... +Package 'c' is not installed, so not removed +Solving dependencies... +Some packages could not be installed. This may mean that you have +requested an impossible situation or if you are using the unstable +distribution that some required packages have not yet been created +or been moved out of Incoming. +The following information may help to resolve the situation: + +The following packages have unmet dependencies: + a : Depends: c but it is not going to be installed +E: Unable to correct problems, you have held broken packages. +E: The following information from --solver 3.0 may provide additional context: + Unable to satisfy dependencies. Reached two conflicting decisions: + 1. a:amd64=3 is selected for install + 2. a:amd64 Depends c + but none of the choices are installable: + - c:amd64 is not selected for install" apt install -s a c- --solver internal |
