]> git.saurik.com Git - apt.git/commitdiff
do not restore selections for already purged packages
authorDavid Kalnischkies <david@kalnischkies.de>
Wed, 24 Aug 2016 19:57:53 +0000 (21:57 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Wed, 24 Aug 2016 20:37:41 +0000 (22:37 +0200)
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
test/integration/framework
test/integration/test-apt-get-autoremove

index b0700bcc6cea4cfc54524a2cca525cb456c3e85f..a2c7770b3ab6e53b984114254b757e5b294a3947 100644 (file)
@@ -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<decltype(approvedStates.Remove())>::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!");
 
index d40c9f356ae27a8d6ed1fac9dd2a7b0cf11263d9..0daf776f58ba24ae197ee7def285dd8beb99c1d0 100644 (file)
@@ -1989,7 +1989,7 @@ testaptautotestnodpkgwarning() {
                if expr match "$2" '^-dy\?' >/dev/null 2>&1; then return; fi # download-only mode
                shift
        done
-       testfailure grep '^dpkg: warning:.*ignor.*' "${TMPWORKINGDIRECTORY}/rootdir/tmp-before/${TESTCALL}.output"
+       testfailure grep '^dpkg: warning:.*\(ignor\|unknown\).*' "${TMPWORKINGDIRECTORY}/rootdir/tmp-before/${TESTCALL}.output"
 }
 
 aptautotest_aptget_install() { testaptautotestnodpkgwarning "$@"; }
index cfee748af4048a417878696ab93d2b66de4f1d69..8af864acb4c0f5382dc34ec1df23f70cbd0b75bc 100755 (executable)
@@ -152,3 +152,6 @@ Remv foo-multi2-1 [1]
 Remv foo-multi2-2 [1]
 Remv foo-plus-1 [1]
 Remv foo-plus-2 [1]' apt autoremove -s
+
+testdpkgstatus 'pi' '1' 'unrelated'
+testsuccess apt purge unrelated -y