]> git.saurik.com Git - apt.git/commitdiff
save and restore selection states before/after calling dpkg
authorDavid Kalnischkies <david@kalnischkies.de>
Sun, 3 Jul 2016 12:39:16 +0000 (14:39 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Wed, 10 Aug 2016 21:18:04 +0000 (23:18 +0200)
dpkg decides certain things on its own based on selections and
especially if we want to call --pending on purge/remove actions, we need
to ensure a clean slate or otherwise we surprise the user by removing
packages we weren't allowed to remove by the user in this run (the
selection might be an overarching plan for the not-yet "future").

Ideally dpkg would have some kind of temporal selection interface for
this case, but it hasn't, so we make it temporal with the risk of
loosing state if we don't manage to restore them.

apt-pkg/deb/dpkgpm.cc
apt-pkg/statechanges.cc
test/integration/test-apt-get-autoremove

index c82a09b0983d8e6f4b2f112454e583aca305c6df..38285d14b34cc7741bc2e7b534cd11e95e4f0ba6 100644 (file)
@@ -19,6 +19,7 @@
 #include <apt-pkg/install-progress.h>
 #include <apt-pkg/packagemanager.h>
 #include <apt-pkg/strutl.h>
+#include <apt-pkg/statechanges.h>
 #include <apt-pkg/cacheiterators.h>
 #include <apt-pkg/macros.h>
 #include <apt-pkg/pkgcache.h>
@@ -208,6 +209,14 @@ pkgCache::VerIterator FindNowVersion(const pkgCache::PkgIterator &Pkg)
    return Ver;
 }
                                                                        /*}}}*/
+static pkgCache::VerIterator FindToBeRemovedVersion(pkgCache::PkgIterator const &Pkg)/*{{{*/
+{
+   auto const PV = Pkg.CurrentVer();
+   if (PV.end() == false)
+      return PV;
+   return FindNowVersion(Pkg);
+}
+                                                                       /*}}}*/
 
 // DPkgPM::pkgDPkgPM - Constructor                                     /*{{{*/
 // ---------------------------------------------------------------------
@@ -1342,6 +1351,28 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
         List.erase(std::next(List.begin(), notconfidx), List.end());
    }
 
+   APT::StateChanges currentStates;
+   if (_config->FindB("dpkg::selection::current::saveandrestore", true))
+   {
+      for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
+        if (Pkg->CurrentVer == 0)
+           continue;
+        else if (Pkg->SelectedState == pkgCache::State::Purge)
+           currentStates.Purge(FindToBeRemovedVersion(Pkg));
+        else if (Pkg->SelectedState == pkgCache::State::DeInstall)
+           currentStates.Remove(FindToBeRemovedVersion(Pkg));
+      if (currentStates.empty() == false)
+      {
+        APT::StateChanges cleanStates;
+        for (auto && P: currentStates.Remove())
+           cleanStates.Install(P);
+        for (auto && P: currentStates.Purge())
+           cleanStates.Install(P);
+        if (cleanStates.Save(false) == false)
+           return _error->Error("Couldn't clean the currently selected dpkg states");
+      }
+   }
+
    d->stdin_is_dev_null = false;
 
    // create log
@@ -1505,12 +1536,8 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
            {
               pkgCache::VerIterator PkgVer;
               std::string name = I->Pkg.Name();
-              if (Op == Item::Remove || Op == Item::Purge) 
-               {
-                 PkgVer = I->Pkg.CurrentVer();
-                  if(PkgVer.end() == true)
-                     PkgVer = FindNowVersion(I->Pkg);
-               }
+              if (Op == Item::Remove || Op == Item::Purge)
+                 PkgVer = FindToBeRemovedVersion(I->Pkg);
               else
                  PkgVer = Cache[I->Pkg].InstVerIter(Cache);
               if (strcmp(I->Pkg.Arch(), "none") == 0)
@@ -1714,6 +1741,9 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
    StopPtyMagic();
    CloseLog();
 
+   if (currentStates.Save(false) == false)
+      _error->Error("Couldn't restore dpkg selection states which were present before this interaction!");
+
    if (pkgPackageManager::SigINTStop)
        _error->Warning(_("Operation was interrupted before it could finish"));
 
index ed8f9f5249a41681fe635fa326b5d415b7a9f731..35af45538089029a9f4e933b30e0bd00bb8c1a58 100644 (file)
@@ -25,7 +25,8 @@ public:
 #define APT_GETTERSETTER(Name, Container) \
 void StateChanges::Name(pkgCache::VerIterator const &Ver) \
 { \
-   Container.push_back(Ver); \
+   if (Ver.end() == false) \
+      Container.push_back(Ver); \
 }\
 APT::VersionVector& StateChanges::Name() \
 { \
index 17dba9aeced2cba40113d7662bc14a37c1e37d74..cfee748af4048a417878696ab93d2b66de4f1d69 100755 (executable)
@@ -18,6 +18,8 @@ testmarkedauto 'po-debconf'
 testsuccess aptget remove debhelper -y
 testdpkgnotinstalled 'debhelper'
 testdpkginstalled 'po-debconf' 'unrelated'
+echo 'unrelated purge' | dpkg --set-selections
+testdpkgstatus 'pi' '1' 'unrelated'
 
 AUTOREMOVE='apt autoremove'
 if [ -n "$SUDO_USER" ]; then
@@ -49,14 +51,17 @@ testdpkginstalled 'po-debconf'
 echo 'APT::NeverAutoRemove { "^po-debconf$"; };' > rootdir/etc/apt/apt.conf.d/00autoremove
 testsuccess aptget autoremove -y
 testdpkginstalled 'po-debconf'
+testdpkgstatus 'pi' '1' 'unrelated'
 
 echo 'APT::NeverAutoRemove { "^po-.*$"; };' > rootdir/etc/apt/apt.conf.d/00autoremove
 testsuccess aptget autoremove -y
 testdpkginstalled "po-debconf"
+testdpkgstatus 'pi' '1' 'unrelated'
 
 rm rootdir/etc/apt/apt.conf.d/00autoremove
 testsuccess aptget autoremove -y
 testdpkgnotinstalled 'po-debconf'
+testdpkgstatus 'pi' '1' 'unrelated'
 testmarkedauto
 
 sed rootdir/var/log/apt/history.log -e '/^Commandline: / d' \
@@ -71,7 +76,8 @@ Remove: debhelper:i386 (8.0.0)
 Remove: po-debconf:i386 (1.0.16)'
 
 testsuccess aptget install debhelper -y
-testdpkginstalled 'unrelated' 'debhelper' 'po-debconf'
+testdpkgstatus 'pi' '1' 'unrelated'
+testdpkginstalled 'debhelper' 'po-debconf'
 testsuccess aptmark auto debhelper
 
 testmarkedauto 'debhelper' 'po-debconf'
@@ -105,9 +111,11 @@ Reading state information...
 
 testsuccess aptget autoremove debhelper -y --allow-change-held-packages
 testdpkgnotinstalled 'po-debconf' 'debhelper'
+testdpkgstatus 'pi' '1' 'unrelated'
 testmarkedauto
 testsuccess aptget install debhelper --solver apt -y -o Debug::pkgDepCache::Marker=1
 testmarkedauto 'po-debconf'
+testdpkgstatus 'pi' '1' 'unrelated'
 
 insertinstalledpackage 'bar' 'all' '1' 'Depends: foo-provider'
 insertinstalledpackage 'foo-multi1-1' 'all' '1' 'Provides: foo-provider