From 70ff288b98a7aae2c2808112015d34f76f2d5114 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 24 Aug 2016 21:57:53 +0200 Subject: do not restore selections for already purged packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In most cases apt was already skipping the (re)setting of packages as to be removed/purged if dpkg had told us that it already did, but we haven't dealt with it in the most obvious of the cases: Selections set for packages we touched in this operation which either restores selections even dpkg would have overridden or e.g. tries to restore a purge selection for a package which was just purged – does not happen with apt itself as it isn't using selections in this way, but higher frontends like aptitude do. The result in the later case is a warning printed by dpkg that we try to set selections for an unknown package, which is harmless per se, but can be confusing for users and we really shouldn't cause warnings in dpkg if we can help it. Reported-By: Guillem Jover on IRC --- apt-pkg/deb/dpkgpm.cc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index b0700bcc6..a2c7770b3 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -1339,10 +1339,16 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) std::distance(List.cbegin(), List.cend()); ExpandPendingCalls(List, Cache); - auto const StripAlreadyDoneFromPending = [&](APT::VersionVector & Pending) { + /* if dpkg told us that it has already done everything to the package we wanted it to do, + we shouldn't ask it for "more" later. That can e.g. happen if packages without conffiles + are purged as they will have pass through the purge states on remove already */ + auto const StripAlreadyDoneFrom = [&](APT::VersionVector & Pending) { Pending.erase(std::remove_if(Pending.begin(), Pending.end(), [&](pkgCache::VerIterator const &Ver) { auto const PN = Ver.ParentPkg().FullName(); - return PackageOps[PN].size() <= PackageOpsDone[PN]; + auto const POD = PackageOpsDone.find(PN); + if (POD == PackageOpsDone.end()) + return false; + return PackageOps[PN].size() <= POD->second; }), Pending.end()); }; @@ -1701,7 +1707,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) else if (I->Op == Item::RemovePending) { ++I; - StripAlreadyDoneFromPending(approvedStates.Remove()); + StripAlreadyDoneFrom(approvedStates.Remove()); if (approvedStates.Remove().empty()) continue; } @@ -1710,7 +1716,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) ++I; // explicit removes of packages without conffiles passthrough the purge states instantly, too. // Setting these non-installed packages up for purging generates 'unknown pkg' warnings from dpkg - StripAlreadyDoneFromPending(approvedStates.Purge()); + StripAlreadyDoneFrom(approvedStates.Purge()); if (approvedStates.Purge().empty()) continue; std::remove_reference::type approvedRemoves; @@ -1962,8 +1968,8 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) if (d->dpkg_error.empty() == false) { // no point in reseting packages we already completed removal for - StripAlreadyDoneFromPending(approvedStates.Remove()); - StripAlreadyDoneFromPending(approvedStates.Purge()); + StripAlreadyDoneFrom(approvedStates.Remove()); + StripAlreadyDoneFrom(approvedStates.Purge()); APT::StateChanges undo; auto && undoRem = approvedStates.Remove(); std::move(undoRem.begin(), undoRem.end(), std::back_inserter(undo.Install())); @@ -1973,6 +1979,9 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) if (undo.Save(false) == false) _error->Error("Couldn't revert dpkg selection for approved remove/purge after an error was encountered!"); } + + StripAlreadyDoneFrom(currentStates.Remove()); + StripAlreadyDoneFrom(currentStates.Purge()); if (currentStates.Save(false) == false) _error->Error("Couldn't restore dpkg selection states which were present before this interaction!"); -- cgit v1.2.3