From 76498d46855c88b90316e4369ac32050db9a9d23 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 26 Apr 2020 13:14:43 +0200 Subject: Split up MarkInstall into private helper methods Should be easier to move the code bits around then and it helps in documenting a bit what the blocks do and how they interact (or not). --- apt-pkg/depcache.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'apt-pkg/depcache.h') diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 17d9a9c3c..9f2fc3477 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -51,6 +51,12 @@ class OpProgress; class pkgVersioningSystem; +namespace APT +{ +template +class PackageContainer; +using PackageVector = PackageContainer>; +} // namespace APT class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace { @@ -511,6 +517,12 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace APT_HIDDEN bool IsModeChangeOk(ModeList const mode, PkgIterator const &Pkg, unsigned long const Depth, bool const FromUser); + + APT_HIDDEN bool MarkInstall_StateChange(PkgIterator const &Pkg, bool AutoInst, bool FromUser); + APT_HIDDEN bool MarkInstall_CollectDependencies(pkgCache::VerIterator const &PV, std::vector &toInstall, std::vector &toRemove); + APT_HIDDEN bool MarkInstall_RemoveConflictsIfNotUpgradeable(unsigned long Depth, std::vector &toRemove, APT::PackageVector &toUpgrade); + APT_HIDDEN bool MarkInstall_UpgradeOrRemoveConflicts(unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade); + APT_HIDDEN bool MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, std::vector &toInstall, APT::PackageVector *const toMoveAuto); }; #endif -- cgit v1.2.3-70-g09d2 From 347ea3f76ab263c729468e07b910ae027b66c9d8 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 27 Apr 2020 13:48:33 +0200 Subject: Fail earlier on impossible Conflicts in MarkInstall MarkDelete is not recursive as MarkInstall is and we can not conflict with ourselves anyhow, so we can move the unavoidable deletes before changing the state of the package in question avoiding the need for the state update in case of conflicts we can not deal with (e.g. the package conflicts with an explicit user request). --- apt-pkg/depcache.cc | 39 +++++++++++++++++++++++---------------- apt-pkg/depcache.h | 2 +- 2 files changed, 24 insertions(+), 17 deletions(-) (limited to 'apt-pkg/depcache.h') diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index b88e9ceb8..4b2da4b4b 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -1137,7 +1137,7 @@ bool pkgDepCache::MarkInstall_CollectDependencies(pkgCache::VerIterator const &P return true; } /*}}}*/ -bool pkgDepCache::MarkInstall_RemoveConflictsIfNotUpgradeable(unsigned long Depth, std::vector &toRemove, APT::PackageVector &toUpgrade) /*{{{*/ +bool pkgDepCache::MarkInstall_RemoveConflictsIfNotUpgradeable(pkgCache::VerIterator const &PV, unsigned long Depth, std::vector &toRemove, APT::PackageVector &toUpgrade) /*{{{*/ { /* Negative dependencies have no or-group If the dependency isn't versioned, we try if an upgrade might solve the problem. @@ -1167,7 +1167,7 @@ bool pkgDepCache::MarkInstall_RemoveConflictsIfNotUpgradeable(unsigned long Dept else { if(DebugAutoInstall == true) - std::clog << OutputInDepth(Depth) << " Removing: " << Pkg.Name() << " as upgrade is not an option\n"; + std::clog << OutputInDepth(Depth) << " Removing: " << Pkg.Name() << " as upgrade is not an option for " << PV.ParentPkg().FullName() << "(" << PV.VerStr() << ")\n"; if (not MarkDelete(Pkg, false, Depth + 1, false)) return false; } @@ -1340,32 +1340,39 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg, bool AutoInst, if (not IsInstallOk(Pkg, AutoInst, Depth, FromUser)) return false; + bool const AutoSolve = AutoInst && _config->Find("APT::Solver", "internal") == "internal"; + + std::vector toInstall, toRemove; + APT::PackageVector toUpgrade; + if (AutoSolve) + { + VerIterator const PV = P.CandidateVerIter(*this); + if (unlikely(PV.end())) + return false; + if (not MarkInstall_CollectDependencies(PV, toInstall, toRemove)) + return false; + + if (not MarkInstall_RemoveConflictsIfNotUpgradeable(PV, Depth, toRemove, toUpgrade)) + return false; + } + ActionGroup group(*this); if (not MarkInstall_StateChange(Pkg, AutoInst, FromUser)) return false; - if (not AutoInst || _config->Find("APT::Solver", "internal") != "internal") + if (not AutoSolve) return true; if (DebugMarker) - std::clog << OutputInDepth(Depth) << "MarkInstall " << APT::PrettyPkg(this, Pkg) << " FU=" << FromUser << std::endl; - - VerIterator const PV = P.InstVerIter(*this); - if (unlikely(PV.end())) - return false; - - std::vector toInstall, toRemove; - if (not MarkInstall_CollectDependencies(PV, toInstall, toRemove)) - return false; - - APT::PackageVector toUpgrade; - if (not MarkInstall_RemoveConflictsIfNotUpgradeable(Depth, toRemove, toUpgrade)) - return false; + std::clog << OutputInDepth(Depth) << "MarkInstall " << APT::PrettyPkg(this, Pkg) << " FU=" << FromUser << '\n'; if (not MarkInstall_UpgradeOrRemoveConflicts(Depth, ForceImportantDeps, toUpgrade)) return false; bool const MoveAutoBitToDependencies = [&]() { + VerIterator const PV = P.InstVerIter(*this); + if (unlikely(PV.end())) + return false; if (PV->Section == 0 || (P.Flags & Flag::Auto) == Flag::Auto) return false; VerIterator const CurVer = Pkg.CurrentVer(); diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 9f2fc3477..669514e3f 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -520,7 +520,7 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace APT_HIDDEN bool MarkInstall_StateChange(PkgIterator const &Pkg, bool AutoInst, bool FromUser); APT_HIDDEN bool MarkInstall_CollectDependencies(pkgCache::VerIterator const &PV, std::vector &toInstall, std::vector &toRemove); - APT_HIDDEN bool MarkInstall_RemoveConflictsIfNotUpgradeable(unsigned long Depth, std::vector &toRemove, APT::PackageVector &toUpgrade); + APT_HIDDEN bool MarkInstall_RemoveConflictsIfNotUpgradeable(pkgCache::VerIterator const &PV, unsigned long Depth, std::vector &toRemove, APT::PackageVector &toUpgrade); APT_HIDDEN bool MarkInstall_UpgradeOrRemoveConflicts(unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade); APT_HIDDEN bool MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, std::vector &toInstall, APT::PackageVector *const toMoveAuto); }; -- cgit v1.2.3-70-g09d2 From f76a8d331a81bc7b102bdd4e0f8363e8a59f64f6 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 27 Apr 2020 13:49:19 +0200 Subject: Propagate Protected flag to single-option dependencies If a package is protected and has a dependency satisfied only by a single package (or conflicts with a package) this package must be part of the solution and so we can help later actions not exploring dead ends by propagating the protected flag to these "pseudo-protected" packages. An (obscure) bug this can help prevent (to some extend) is shown in test-apt-never-markauto-sections by not causing irreversible autobit transfers. As a sideeffect it seems also to help our crude ShowBroken to display slightly more helpful messages involving the packages which are actually in conflict. --- apt-pkg/depcache.cc | 24 ++++++++++++++++++---- apt-pkg/depcache.h | 2 +- test/integration/test-apt-never-markauto-sections | 11 +++------- .../integration/test-bug-604222-new-and-autoremove | 3 ++- .../test-bug-735967-lib32-to-i386-unavailable | 4 ++-- .../test-explore-or-groups-in-markinstall | 4 +++- test/integration/test-multiarch-allowed | 11 ++++++---- 7 files changed, 38 insertions(+), 21 deletions(-) (limited to 'apt-pkg/depcache.h') diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 4b2da4b4b..03fc58f69 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -1170,6 +1170,8 @@ bool pkgDepCache::MarkInstall_RemoveConflictsIfNotUpgradeable(pkgCache::VerItera std::clog << OutputInDepth(Depth) << " Removing: " << Pkg.Name() << " as upgrade is not an option for " << PV.ParentPkg().FullName() << "(" << PV.VerStr() << ")\n"; if (not MarkDelete(Pkg, false, Depth + 1, false)) return false; + if (PkgState[PV.ParentPkg()->ID].Protect()) + MarkProtected(Pkg); } } } @@ -1177,7 +1179,7 @@ bool pkgDepCache::MarkInstall_RemoveConflictsIfNotUpgradeable(pkgCache::VerItera return true; } /*}}}*/ -bool pkgDepCache::MarkInstall_UpgradeOrRemoveConflicts(unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade) /*{{{*/ +bool pkgDepCache::MarkInstall_UpgradeOrRemoveConflicts(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade) /*{{{*/ { for (auto const &InstPkg : toUpgrade) if (not MarkInstall(InstPkg, true, Depth + 1, false, ForceImportantDeps)) @@ -1186,6 +1188,8 @@ bool pkgDepCache::MarkInstall_UpgradeOrRemoveConflicts(unsigned long Depth, bool std::clog << OutputInDepth(Depth) << " Removing: " << InstPkg.FullName() << " as upgrade is not possible\n"; if (not MarkDelete(InstPkg, false, Depth + 1, false)) return false; + if (PkgState[Pkg->ID].Protect()) + MarkProtected(InstPkg); } toUpgrade.clear(); return true; @@ -1200,6 +1204,7 @@ bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsign Dep.GlobOr(Start, End); if (std::any_of(Start, Dep, IsSatisfiedByInstalled)) continue; + bool const IsCriticalDep = Start.IsCritical(); /* Check if any ImportantDep() (but not Critical) were added * since we installed the package. Also check for deps that @@ -1208,7 +1213,7 @@ bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsign * package should follow that Recommends rather than causing the * dependency to be removed. (bug #470115) */ - if (Pkg->CurrentVer != 0 && not ForceImportantDeps && not Start.IsCritical()) + if (Pkg->CurrentVer != 0 && not ForceImportantDeps && not IsCriticalDep) { bool isNewImportantDep = true; bool isPreviouslySatisfiedImportantDep = false; @@ -1253,6 +1258,7 @@ bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsign } bool foundSolution = false; + bool thereIsOnlyOne1 = Start == End; do { if ((DepState[Start->ID] & DepCVer) != DepCVer) @@ -1261,6 +1267,7 @@ bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsign pkgCacheFile CacheFile(this); APT::VersionList verlist = APT::VersionList::FromDependency(CacheFile, Start, APT::CacheSetHelper::CANDIDATE); CompareProviders comp(Start); + bool thereIsOnlyOne2 = thereIsOnlyOne1 && verlist.size() == 1; do { @@ -1272,6 +1279,15 @@ bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsign if (DebugAutoInstall) std::clog << OutputInDepth(Depth) << "Installing " << InstPkg.Name() << " as " << Start.DepType() << " of " << Pkg.Name() << '\n'; + if (thereIsOnlyOne2 && PkgState[Pkg->ID].Protect() && IsCriticalDep) + { + if (not MarkInstall(InstPkg, false, Depth + 1, false, ForceImportantDeps)) + { + verlist.erase(InstVer); + continue; + } + MarkProtected(InstPkg); + } if (not MarkInstall(InstPkg, true, Depth + 1, false, ForceImportantDeps)) { verlist.erase(InstVer); @@ -1287,7 +1303,7 @@ bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsign if (foundSolution) break; } while (Start++ != End); - if (not foundSolution && End.IsCritical()) + if (not foundSolution && IsCriticalDep) { StateCache &State = PkgState[Pkg->ID]; if (not State.Protect()) @@ -1366,7 +1382,7 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg, bool AutoInst, if (DebugMarker) std::clog << OutputInDepth(Depth) << "MarkInstall " << APT::PrettyPkg(this, Pkg) << " FU=" << FromUser << '\n'; - if (not MarkInstall_UpgradeOrRemoveConflicts(Depth, ForceImportantDeps, toUpgrade)) + if (not MarkInstall_UpgradeOrRemoveConflicts(Pkg, Depth, ForceImportantDeps, toUpgrade)) return false; bool const MoveAutoBitToDependencies = [&]() { diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 669514e3f..339686b95 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -521,7 +521,7 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace APT_HIDDEN bool MarkInstall_StateChange(PkgIterator const &Pkg, bool AutoInst, bool FromUser); APT_HIDDEN bool MarkInstall_CollectDependencies(pkgCache::VerIterator const &PV, std::vector &toInstall, std::vector &toRemove); APT_HIDDEN bool MarkInstall_RemoveConflictsIfNotUpgradeable(pkgCache::VerIterator const &PV, unsigned long Depth, std::vector &toRemove, APT::PackageVector &toUpgrade); - APT_HIDDEN bool MarkInstall_UpgradeOrRemoveConflicts(unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade); + APT_HIDDEN bool MarkInstall_UpgradeOrRemoveConflicts(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade); APT_HIDDEN bool MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, std::vector &toInstall, APT::PackageVector *const toMoveAuto); }; diff --git a/test/integration/test-apt-never-markauto-sections b/test/integration/test-apt-never-markauto-sections index aa145d217..6ad89c506 100755 --- a/test/integration/test-apt-never-markauto-sections +++ b/test/integration/test-apt-never-markauto-sections @@ -27,7 +27,7 @@ testsuccess aptcache show nosection testfailure grep 'Section' rootdir/tmp/testsuccess.output testequal 'dpkg' aptmark showmanual -testsuccess aptget install mydesktop -y -o Debug::pkgProblemResolver=1 -o Debug::pkgDepCache::Marker=1 +testsuccess aptget install mydesktop -y -o Debug::pkgProblemResolver=1 -o Debug::pkgDepCache::Marker=1 -o Debug::pkgDepCache::AutoInstall=1 testmarkedmanual 'dpkg' 'mydesktop' testmarkedauto 'mydesktop-core' 'foreignpkg:i386' 'texteditor' 'browser' 'nosection' @@ -75,12 +75,7 @@ testsuccess aptmark auto nosection testmarkedauto 'browser' 'nosection' testmarkedmanual 'dpkg' 'foreignpkg:i386' -# nosection should be auto, not manual, but is marked as such by the resolver -# removing mydesktop-core temporally… the resolver should be figuring out here -# that there is no point of removing mydesktop-core as its an unavoidable -# dependency of the user-requested mydesktop - testsuccess aptget install mydesktop -y -o Debug::pkgProblemResolver=1 -o Debug::pkgDepCache::Marker=1 -o Debug::pkgDepCache::AutoInstall=1 -testmarkedmanual 'dpkg' 'foreignpkg:i386' 'mydesktop' 'nosection' -testmarkedauto 'browser' 'mydesktop-core' 'texteditor' +testmarkedmanual 'dpkg' 'foreignpkg:i386' 'mydesktop' +testmarkedauto 'browser' 'mydesktop-core' 'texteditor' 'nosection' diff --git a/test/integration/test-bug-604222-new-and-autoremove b/test/integration/test-bug-604222-new-and-autoremove index b8faf4fe6..6009ca0d2 100755 --- a/test/integration/test-bug-604222-new-and-autoremove +++ b/test/integration/test-bug-604222-new-and-autoremove @@ -88,12 +88,13 @@ rm -f rootdir/var/lib/apt/extended_states CONFLICTING='Reading package lists... Building dependency tree... MarkInstall dummy-archive:i386 < none -> 0.invalid.0 @un puN Ib > FU=1 - MarkInstall libavcodec52:i386 < none -> 4:0.5.2-6 @un uN > FU=0 MarkInstall libvtk5-dev:i386 < none -> 5.4.2-8 @un uN Ib > FU=0 MarkInstall libvtk5.4:i386 < none -> 5.4.2-8 @un uN > FU=0 MarkKeep libvtk5-dev:i386 < none -> 5.4.2-8 @un uN > FU=0 MarkKeep libvtk5-dev:i386 < none -> 5.4.2-8 @un uN > FU=0 + Ignore MarkGarbage of libavcodec52:i386 < none -> 4:0.5.2-6 @un puN > as its mode (Install) is protected MarkDelete libvtk5.4:i386 < none -> 5.4.2-8 @un ugN > FU=0 + Ignore MarkGarbage of libavcodec52:i386 < none -> 4:0.5.2-6 @un puN > as its mode (Install) is protected The following additional packages will be installed: libavcodec52 libopenal-dev The following NEW packages will be installed: diff --git a/test/integration/test-bug-735967-lib32-to-i386-unavailable b/test/integration/test-bug-735967-lib32-to-i386-unavailable index 16aee4340..9dbd17bfd 100755 --- a/test/integration/test-bug-735967-lib32-to-i386-unavailable +++ b/test/integration/test-bug-735967-lib32-to-i386-unavailable @@ -52,8 +52,8 @@ or been moved out of Incoming. The following information may help to resolve the situation: The following packages have unmet dependencies: - foo : Depends: libfoo but it is not installable -E: Unable to correct problems, you have held broken packages.' aptget install foo -s + libfoo : Depends: libfoo-bin but it is not installable +E: Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.' aptget install foo -s # activate multiarch configarchitecture 'amd64' 'i386' diff --git a/test/integration/test-explore-or-groups-in-markinstall b/test/integration/test-explore-or-groups-in-markinstall index f5898cfca..db97574bb 100755 --- a/test/integration/test-explore-or-groups-in-markinstall +++ b/test/integration/test-explore-or-groups-in-markinstall @@ -11,10 +11,12 @@ insertpackage 'unstable' 'unneeded' 'all' '1' insertpackage 'unstable' 'later' 'all' '1' insertpackage 'unstable' 'bad-level0' 'all' '1' 'Depends: unneeded, unknown' +insertpackage 'unstable' 'bad-level1' 'all' '1' 'Depends: bad-level0' insertfoos() { insertpackage 'unstable' "foo-${1}-level0" 'all' '1' "${2}: unknown | okay | later" insertpackage 'unstable' "foo-${1}-level1" 'all' '1' "${2}: bad-level0 | okay | later" + insertpackage 'unstable' "foo-${1}-level2" 'all' '1' "${2}: bad-level1 | okay | later" } insertfoos 'd' 'Depends' insertfoos 'r' 'Recommends' @@ -33,7 +35,7 @@ testsuccessheadequal() { } checkfoos() { msgmsg 'Install checks with foos dependency type' "$2" - for i in 0 1; do + for i in 0 1 2; do testsuccessheadequal 7 "Reading package lists... Building dependency tree... The following additional packages will be installed: diff --git a/test/integration/test-multiarch-allowed b/test/integration/test-multiarch-allowed index 98555bc73..b74853993 100755 --- a/test/integration/test-multiarch-allowed +++ b/test/integration/test-multiarch-allowed @@ -64,12 +64,15 @@ Conf foo:i386 (1 unstable [i386]) Conf needsfoo:i386 (1 unstable [i386])' aptget install needsfoo:i386 -s testfailureequal "$BADPREFIX The following packages have unmet dependencies: - needsfoo:i386 : Depends: foo:i386 but it is not going to be installed -E: Unable to correct problems, you have held broken packages." aptget install needsfoo:i386 foo:amd64 -s + foo : Conflicts: foo:i386 but 1 is to be installed + foo:i386 : Conflicts: foo but 1 is to be installed +E: Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages." aptget install needsfoo:i386 foo:amd64 -s testfailureequal "$BADPREFIX The following packages have unmet dependencies: - needsfoo : Depends: foo but it is not going to be installed -E: Unable to correct problems, you have held broken packages." aptget install needsfoo foo:i386 -s + foo : Conflicts: foo:i386 but 1 is to be installed + foo:i386 : Conflicts: foo but 1 is to be installed +E: Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages." aptget install needsfoo foo:i386 -s +exit solveableinsinglearch1() { testsuccessequal "Reading package lists... -- cgit v1.2.3-70-g09d2 From ae23e53f99ea0b7920744a7303fdee64796b7cce Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 27 Apr 2020 13:51:46 +0200 Subject: Protect a package while resolving in MarkInstall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strange things happen if while resolving the dependencies of a package said dependencies want to remove the package. The allow-scores test e.g. removed the preferred alternative in favor of the last one now that they were exclusive. In our or-group for Recommends we would "just" not statisfy the Recommends and for Depends we engage the ProblemResolver… --- apt-pkg/depcache.cc | 35 +++++++++++++++++----- apt-pkg/depcache.h | 4 +-- .../test-allow-scores-for-all-dependency-types | 34 ++++----------------- .../test-explore-or-groups-in-markinstall | 14 +++++++++ 4 files changed, 48 insertions(+), 39 deletions(-) (limited to 'apt-pkg/depcache.h') diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 2254a9b5d..7730aaf5b 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -1180,7 +1180,7 @@ bool pkgDepCache::MarkInstall_RemoveConflictsIfNotUpgradeable(pkgCache::VerItera return true; } /*}}}*/ -bool pkgDepCache::MarkInstall_UpgradeOrRemoveConflicts(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade) /*{{{*/ +bool pkgDepCache::MarkInstall_UpgradeOrRemoveConflicts(bool const propagateProctected, unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade) /*{{{*/ { for (auto const &InstPkg : toUpgrade) if (not MarkInstall(InstPkg, true, Depth + 1, false, ForceImportantDeps)) @@ -1189,14 +1189,14 @@ bool pkgDepCache::MarkInstall_UpgradeOrRemoveConflicts(PkgIterator const &Pkg, u std::clog << OutputInDepth(Depth) << " Removing: " << InstPkg.FullName() << " as upgrade is not possible\n"; if (not MarkDelete(InstPkg, false, Depth + 1, false)) return false; - if (PkgState[Pkg->ID].Protect()) + if (propagateProctected) MarkProtected(InstPkg); } toUpgrade.clear(); return true; } /*}}}*/ -bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, std::vector &toInstall, APT::PackageVector *const toMoveAuto) /*{{{*/ +bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, std::vector &toInstall, APT::PackageVector *const toMoveAuto, bool const propagateProctected) /*{{{*/ { auto const IsSatisfiedByInstalled = [&](auto const D) { return (DepState[D.ID] & DepInstall) == DepInstall; }; for (auto &&Dep : toInstall) @@ -1286,7 +1286,7 @@ bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsign if (DebugAutoInstall) std::clog << OutputInDepth(Depth) << "Installing " << InstPkg.FullName() << " as " << End.DepType() << " of " << Pkg.FullName() << '\n'; - if (IsCriticalDep && toUpgrade.size() == 1 && PkgState[Pkg->ID].Protect()) + if (propagateProctected && IsCriticalDep && toUpgrade.size() == 1) { if (not MarkInstall(InstPkg, false, Depth + 1, false, ForceImportantDeps)) continue; @@ -1303,9 +1303,9 @@ bool pkgDepCache::MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsign } if (not foundSolution && IsCriticalDep) { - StateCache &State = PkgState[Pkg->ID]; - if (not State.Protect()) + if (not propagateProctected) { + StateCache &State = PkgState[Pkg->ID]; RemoveSizes(Pkg); RemoveStates(Pkg); if (Pkg->CurrentVer != 0) @@ -1380,7 +1380,26 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg, bool AutoInst, if (DebugMarker) std::clog << OutputInDepth(Depth) << "MarkInstall " << APT::PrettyPkg(this, Pkg) << " FU=" << FromUser << '\n'; - if (not MarkInstall_UpgradeOrRemoveConflicts(Pkg, Depth, ForceImportantDeps, toUpgrade)) + class ScopedProtected + { + pkgDepCache::StateCache &P; + bool const already; + + public: + ScopedProtected(pkgDepCache::StateCache &p) : P{p}, already{P.Protect()} + { + if (not already) + P.iFlags |= Protected; + } + ~ScopedProtected() + { + if (not already) + P.iFlags &= (~Protected); + } + operator bool() noexcept { return already; } + } propagateProctected{PkgState[Pkg->ID]}; + + if (not MarkInstall_UpgradeOrRemoveConflicts(propagateProctected, Depth, ForceImportantDeps, toUpgrade)) return false; bool const MoveAutoBitToDependencies = [&]() { @@ -1400,7 +1419,7 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg, bool AutoInst, }(); APT::PackageVector toMoveAuto; - if (not MarkInstall_InstallDependencies(Pkg, Depth, ForceImportantDeps, toInstall, MoveAutoBitToDependencies ? &toMoveAuto : nullptr)) + if (not MarkInstall_InstallDependencies(Pkg, Depth, ForceImportantDeps, toInstall, MoveAutoBitToDependencies ? &toMoveAuto : nullptr, propagateProctected)) return false; if (MoveAutoBitToDependencies) diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 339686b95..1579fedbe 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -521,8 +521,8 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace APT_HIDDEN bool MarkInstall_StateChange(PkgIterator const &Pkg, bool AutoInst, bool FromUser); APT_HIDDEN bool MarkInstall_CollectDependencies(pkgCache::VerIterator const &PV, std::vector &toInstall, std::vector &toRemove); APT_HIDDEN bool MarkInstall_RemoveConflictsIfNotUpgradeable(pkgCache::VerIterator const &PV, unsigned long Depth, std::vector &toRemove, APT::PackageVector &toUpgrade); - APT_HIDDEN bool MarkInstall_UpgradeOrRemoveConflicts(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade); - APT_HIDDEN bool MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, std::vector &toInstall, APT::PackageVector *const toMoveAuto); + APT_HIDDEN bool MarkInstall_UpgradeOrRemoveConflicts(bool const propagateProtected, unsigned long Depth, bool const ForceImportantDeps, APT::PackageVector &toUpgrade); + APT_HIDDEN bool MarkInstall_InstallDependencies(PkgIterator const &Pkg, unsigned long Depth, bool const ForceImportantDeps, std::vector &toInstall, APT::PackageVector *const toMoveAuto, bool const propagateProtected); }; #endif diff --git a/test/integration/test-allow-scores-for-all-dependency-types b/test/integration/test-allow-scores-for-all-dependency-types index 9b300b7a7..b8a9ed3ea 100755 --- a/test/integration/test-allow-scores-for-all-dependency-types +++ b/test/integration/test-allow-scores-for-all-dependency-types @@ -116,42 +116,18 @@ Conf baz (2 unversioned [amd64])' aptget install baz -st unversioned testsuccessequal 'Reading package lists... Building dependency tree... The following additional packages will be installed: - foo -The following packages will be REMOVED: bar -The following NEW packages will be installed: - baz -The following packages will be upgraded: - foo -1 upgraded, 1 newly installed, 1 to remove and 0 not upgraded. -Remv bar [1] -Inst foo [1] (2 versioned [amd64]) -Inst baz (2 versioned [amd64]) -Conf foo (2 versioned [amd64]) -Conf baz (2 versioned [amd64])' aptget install baz -st versioned - -testsuccessequal 'Reading package lists... -Building dependency tree... -The following NEW packages will be installed: - baz -0 upgraded, 1 newly installed, 0 to remove and 2 not upgraded. -Inst baz (2 unversioned [amd64]) -Conf baz (2 unversioned [amd64])' aptget install baz -st unversioned -testsuccessequal 'Reading package lists... -Building dependency tree... -The following additional packages will be installed: - foo The following packages will be REMOVED: - bar + foo The following NEW packages will be installed: baz The following packages will be upgraded: - foo + bar 1 upgraded, 1 newly installed, 1 to remove and 0 not upgraded. -Remv bar [1] -Inst foo [1] (2 versioned [amd64]) +Remv foo [1] +Inst bar [1] (2 versioned [amd64]) Inst baz (2 versioned [amd64]) -Conf foo (2 versioned [amd64]) +Conf bar (2 versioned [amd64]) Conf baz (2 versioned [amd64])' aptget install baz -st versioned # recreating the exact situation is hard, so we pull tricks to get the score diff --git a/test/integration/test-explore-or-groups-in-markinstall b/test/integration/test-explore-or-groups-in-markinstall index 259155854..5669e47b3 100755 --- a/test/integration/test-explore-or-groups-in-markinstall +++ b/test/integration/test-explore-or-groups-in-markinstall @@ -15,6 +15,10 @@ insertpackage 'unstable' 'bad-level0' 'all' '1' 'Depends: unneeded, unknown' insertpackage 'unstable' 'bad-level1' 'all' '1' 'Depends: bad-level0' insertpackage 'unstable' 'bad-upgrade-level0' 'all' '2' 'Depends: unneeded, unknown' insertpackage 'unstable' 'bad-upgrade-level1' 'all' '2' 'Depends: bad-upgrade-level0 (>= 2)' +insertpackage 'unstable' 'bad-conflict-level0' 'all' '1' 'Depends: unneeded +Conflicts: bad-conflict-level2' +insertpackage 'unstable' 'bad-conflict-level1' 'all' '1' 'Depends: bad-conflict-level0' +insertpackage 'unstable' 'bad-conflict-level2' 'all' '1' 'Depends: bad-conflict-level1' insertinstalledpackage 'upgrade' 'all' '1' insertinstalledpackage 'bad-upgrade' 'all' '1' @@ -29,6 +33,8 @@ insertfoos() { insertpackage 'unstable' "foo-${1}-upgrade-level0" 'all' '1' "${2}: bad-upgrade (>= 2) | okay | upgrade (>= 2) | later" insertpackage 'unstable' "foo-${1}-upgrade-level1" 'all' '1' "${2}: bad-upgrade-level0 (>= 2) | bad-upgrade-level0 (>= 2) | bad-level0 | okay | upgrade (>= 2) | later" insertpackage 'unstable' "foo-${1}-upgrade-level2" 'all' '1' "${2}: bad-upgrade-level1 (>= 2) | bad-upgrade-level1 (>= 2) | bad-level1 | okay | upgrade (>= 2) | later" + + insertpackage 'unstable' "foo-${1}-conflict" 'all' '1' "${2}: unknown | bad-conflict-level2 | okay | later" } insertfoos 'd' 'Depends' insertfoos 'r' 'Recommends' @@ -65,6 +71,14 @@ The following packages will be upgraded: upgrade 1 upgraded, 1 newly installed, 0 to remove and $((2-${level})) not upgraded." apt install foo-${1}-upgrade-level${level} -s done + + testsuccessheadequal 7 "Reading package lists... +Building dependency tree... +The following additional packages will be installed: + okay +The following NEW packages will be installed: + foo-${1}-conflict okay +0 upgraded, 2 newly installed, 0 to remove and 3 not upgraded." apt install foo-${1}-conflict -s } checkfoos 'd' 'Depends' checkfoos 'r' 'Recommends' -- cgit v1.2.3-70-g09d2