]> git.saurik.com Git - apt.git/commitdiff
simulate all package manager actions explicitly
authorDavid Kalnischkies <david@kalnischkies.de>
Thu, 28 Jul 2016 09:43:36 +0000 (11:43 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Wed, 10 Aug 2016 21:51:34 +0000 (23:51 +0200)
If a planner lets actions to be figured out by dpkg in pending calls
these actions aren't mentioned in a simulation. While that might be
a good thing for debugging, it would be a change in behavior and
especially if a planner avoids explicit removals could be confusing for
users. As such we perform the same 'trick' as in the dpkg implementation
by performing explicitly what would be done by the pending calls.

To save us some work and avoid desyncs we perform a layer violation by
using deb/ code in the generic simulation – and further we perform ugly
dynamic_cast to avoid breaking the ABI for nothing; aptitude is the only
other user of the simulation class according to codesearch.d.n and for
that our little trick works. It just isn't working if you happen to
extend pkgSimulate or otherwise manage to call the protected Go methods
directly – which isn't very realistic/practical.

apt-pkg/algorithms.cc
apt-pkg/algorithms.h
apt-pkg/deb/dpkgpm.cc
apt-pkg/deb/dpkgpm.h
apt-pkg/packagemanager.cc
apt-pkg/packagemanager.h

index b173979c3a4f5eaf25dcef28c488de9e0a8ddb1f..65c5ff85d9f89a229999738a74045e8a01833fd2 100644 (file)
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/cacheiterators.h>
 #include <apt-pkg/prettyprinters.h>
+#include <apt-pkg/dpkgpm.h>
 
 #include <string.h>
 #include <string>
 #include <cstdlib>
 #include <iostream>
+#include <utility>
 
 #include <apti18n.h>
                                                                        /*}}}*/
 using namespace std;
 
+class APT_HIDDEN pkgSimulatePrivate
+{
+public:
+   std::vector<pkgDPkgPM::Item> List;
+};
 // Simulate::Simulate - Constructor                                    /*{{{*/
 // ---------------------------------------------------------------------
 /* The legacy translations here of input Pkg iterators is obsolete, 
    this is not necessary since the pkgCaches are fully shared now. */
 pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
-                           d(NULL), iPolicy(Cache),
+                           d(new pkgSimulatePrivate()), iPolicy(Cache),
                            Sim(&Cache->GetCache(),&iPolicy),
                            group(Sim)
 {
@@ -58,6 +65,7 @@ pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
 pkgSimulate::~pkgSimulate()
 {
    delete[] Flags;
+   delete d;
 }
                                                                        /*}}}*/
 // Simulate::Describe - Describe a package                             /*{{{*/
@@ -90,7 +98,14 @@ void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candid
 // Simulate::Install - Simulate unpacking of a package                 /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
+bool pkgSimulate::Install(PkgIterator iPkg,string File)
+{
+   if (iPkg.end() || File.empty())
+      return false;
+   d->List.emplace_back(pkgDPkgPM::Item::Install, iPkg, File);
+   return true;
+}
+bool pkgSimulate::RealInstall(PkgIterator iPkg,string /*File*/)
 {
    // Adapt the iterator
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
@@ -137,6 +152,13 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
    install the package.. For some investigations it may be necessary 
    however. */
 bool pkgSimulate::Configure(PkgIterator iPkg)
+{
+   if (iPkg.end())
+      return false;
+   d->List.emplace_back(pkgDPkgPM::Item::Configure, iPkg);
+   return true;
+}
+bool pkgSimulate::RealConfigure(PkgIterator iPkg)
 {
    // Adapt the iterator
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
@@ -187,6 +209,13 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
 // ---------------------------------------------------------------------
 /* */
 bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
+{
+   if (iPkg.end())
+      return false;
+   d->List.emplace_back(Purge ? pkgDPkgPM::Item::Purge : pkgDPkgPM::Item::Remove, iPkg);
+   return true;
+}
+bool pkgSimulate::RealRemove(PkgIterator iPkg,bool Purge)
 {
    // Adapt the iterator
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
@@ -232,6 +261,38 @@ void pkgSimulate::ShortBreaks()
    cout << ']' << endl;
 }
                                                                        /*}}}*/
+bool pkgSimulate::Go2(APT::Progress::PackageManager *)                 /*{{{*/
+{
+   if (pkgDPkgPM::ExpandPendingCalls(d->List, Cache) == false)
+      return false;
+   for (auto && I : d->List)
+      switch (I.Op)
+      {
+        case pkgDPkgPM::Item::Install:
+           if (RealInstall(I.Pkg, I.File) == false)
+              return false;
+           break;
+        case pkgDPkgPM::Item::Configure:
+           if (RealConfigure(I.Pkg) == false)
+              return false;
+           break;
+        case pkgDPkgPM::Item::Remove:
+           if (RealRemove(I.Pkg, false) == false)
+              return false;
+           break;
+        case pkgDPkgPM::Item::Purge:
+           if (RealRemove(I.Pkg, true) == false)
+              return false;
+           break;
+        case pkgDPkgPM::Item::ConfigurePending:
+        case pkgDPkgPM::Item::TriggersPending:
+        case pkgDPkgPM::Item::RemovePending:
+        case pkgDPkgPM::Item::PurgePending:
+           return _error->Error("Internal error, simulation encountered unexpected pending item");
+      }
+   return true;
+}
+                                                                       /*}}}*/
 // ApplyStatus - Adjust for non-ok packages                            /*{{{*/
 // ---------------------------------------------------------------------
 /* We attempt to change the state of the all packages that have failed
index c1a26587dcc994bf16a5566f84a4a9cadec6726a..5148ff19d10b6c145ef7fe16a8957f141b021c0b 100644 (file)
@@ -52,9 +52,10 @@ using std::ostream;
 #endif
 
 
+class pkgSimulatePrivate;
 class pkgSimulate : public pkgPackageManager                           /*{{{*/
 {
-   void * const d;
+   pkgSimulatePrivate * const d;
    protected:
 
    class Policy : public pkgDepCache::Policy
@@ -81,9 +82,16 @@ class pkgSimulate : public pkgPackageManager                         /*{{{*/
    virtual bool Configure(PkgIterator Pkg) APT_OVERRIDE;
    virtual bool Remove(PkgIterator Pkg,bool Purge) APT_OVERRIDE;
 
+   // FIXME: trick to avoid ABI break for virtual reimplementation; fix on next ABI break
+public:
+   APT_HIDDEN bool Go2(APT::Progress::PackageManager * progress);
+
 private:
    APT_HIDDEN void ShortBreaks();
    APT_HIDDEN void Describe(PkgIterator iPkg,std::ostream &out,bool Current,bool Candidate);
+   APT_HIDDEN bool RealInstall(PkgIterator Pkg,std::string File);
+   APT_HIDDEN bool RealConfigure(PkgIterator Pkg);
+   APT_HIDDEN bool RealRemove(PkgIterator Pkg,bool Purge);
 
    public:
 
index d14155d01616f4b0ee4c1f489f468606c5d25141..4a49774f8a574fedd88fe3039d5d800d7607937a 100644 (file)
@@ -1297,37 +1297,34 @@ static void cleanUpTmpDir(char * const tmpdir)                          /*{{{*/
  * through to human readable (and i10n-able)
  * names and calculates a percentage for each step.
  */
-bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
+static bool ItemIsEssential(pkgDPkgPM::Item const &I)
+{
+   static auto const cachegen = _config->Find("pkgCacheGen::Essential");
+   if (cachegen == "none" || cachegen == "native")
+      return true;
+   if (unlikely(I.Pkg.end()))
+      return true;
+   return (I.Pkg->Flags & pkgCache::Flag::Essential) != 0;
+}
+bool pkgDPkgPM::ExpandPendingCalls(std::vector<Item> &List, pkgDepCache &Cache)
 {
-   // we remove the last configures (and after that removes) from the list here
-   // as they will be covered by the pending calls, so explicit calls are busy work
-   decltype(List)::const_iterator::difference_type explicitIdx =
-      std::distance(List.cbegin(),
-           _config->FindB("Dpkg::ExplicitLastConfigure", false) ? List.cend() :
-           std::find_if_not(
-              std::find_if_not(List.crbegin(), List.crend(), [](Item const &i) { return i.Op == Item::Configure; }),
-              List.crend(), [](Item const &i) { return i.Op == Item::Remove || i.Op == Item::Purge; }).base());
-
-   // explicitely remove everything for hookscripts and progress building
    {
       std::unordered_set<decltype(pkgCache::Package::ID)> alreadyRemoved;
       for (auto && I : List)
         if (I.Op == Item::Remove || I.Op == Item::Purge)
            alreadyRemoved.insert(I.Pkg->ID);
-      decltype(List) AppendList;
+      std::remove_reference<decltype(List)>::type AppendList;
       for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
         if (Cache[Pkg].Delete() && alreadyRemoved.insert(Pkg->ID).second == true)
            AppendList.emplace_back(Cache[Pkg].Purge() ? Item::Purge : Item::Remove, Pkg);
       std::move(AppendList.begin(), AppendList.end(), std::back_inserter(List));
    }
-
-   // explicitely configure everything for hookscripts and progress building
    {
       std::unordered_set<decltype(pkgCache::Package::ID)> alreadyConfigured;
       for (auto && I : List)
         if (I.Op == Item::Configure)
            alreadyConfigured.insert(I.Pkg->ID);
-      decltype(List) AppendList;
+      std::remove_reference<decltype(List)>::type AppendList;
       for (auto && I : List)
         if (I.Op == Item::Install && alreadyConfigured.insert(I.Pkg->ID).second == true)
            AppendList.emplace_back(Item::Configure, I.Pkg);
@@ -1336,15 +1333,21 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
            AppendList.emplace_back(Item::Configure, Pkg);
       std::move(AppendList.begin(), AppendList.end(), std::back_inserter(List));
    }
+   return true;
+}
+bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
+{
+   // we remove the last configures (and after that removes) from the list here
+   // as they will be covered by the pending calls, so explicit calls are busy work
+   decltype(List)::const_iterator::difference_type explicitIdx =
+      std::distance(List.cbegin(),
+           _config->FindB("Dpkg::ExplicitLastConfigure", false) ? List.cend() :
+           std::find_if_not(
+              std::find_if_not(List.crbegin(), List.crend(), [](Item const &i) { return i.Op == Item::Configure; }),
+              List.crend(), [](Item const &i) { return i.Op == Item::Remove || i.Op == Item::Purge; }).base());
 
-   auto const ItemIsEssential = [](pkgDPkgPM::Item const &I) {
-      static auto const cachegen = _config->Find("pkgCacheGen::Essential");
-      if (cachegen == "none" || cachegen == "native")
-        return true;
-      if (unlikely(I.Pkg.end()))
-        return true;
-      return (I.Pkg->Flags & pkgCache::Flag::Essential) != 0;
-   };
+   // explicitely remove&configure everything for hookscripts and progress building
+   ExpandPendingCalls(List, Cache);
 
    auto const StripAlreadyDoneFromPending = [&](APT::VersionVector & Pending) {
       Pending.erase(std::remove_if(Pending.begin(), Pending.end(), [&](pkgCache::VerIterator const &Ver) {
index 07c99aeadd45f1193ae97f80cf80c3db4a70f27a..193754644d44ad19b527beba48385334300cdb1e 100644 (file)
@@ -76,7 +76,8 @@ class pkgDPkgPM : public pkgPackageManager
    // progress reporting
    unsigned int PackagesDone;
    unsigned int PackagesTotal;
-  
+
+   public:
    struct Item
    {
       enum Ops {Install, Configure, Remove, Purge, ConfigurePending, TriggersPending,
@@ -86,8 +87,8 @@ class pkgDPkgPM : public pkgPackageManager
       Item(Ops Op,PkgIterator Pkg,std::string File = "") : Op(Op),
             File(File), Pkg(Pkg) {};
       Item() {};
-      
    };
+   protected:
    std::vector<Item> List;
 
    // Helpers
@@ -126,7 +127,7 @@ class pkgDPkgPM : public pkgPackageManager
    virtual bool Remove(PkgIterator Pkg,bool Purge = false) APT_OVERRIDE;
 
    virtual bool Go(APT::Progress::PackageManager *progress) APT_OVERRIDE;
-   virtual bool Go(int StatusFd=-1) APT_OVERRIDE;
+   APT_DEPRECATED_MSG("Use overload with explicit progress manager") virtual bool Go(int StatusFd=-1) APT_OVERRIDE;
 
    virtual void Reset() APT_OVERRIDE;
    
@@ -134,6 +135,8 @@ class pkgDPkgPM : public pkgPackageManager
 
    pkgDPkgPM(pkgDepCache *Cache);
    virtual ~pkgDPkgPM();
+
+   APT_HIDDEN static bool ExpandPendingCalls(std::vector<Item> &List, pkgDepCache &Cache);
 };
 
 void SigINT(int sig);
index 7fdd0393f33473b22b980959db98de0fd279d7ad..3d9c44555f0a67981be1577340dd6cd8c4979500 100644 (file)
@@ -1148,7 +1148,12 @@ pkgPackageManager::DoInstallPostFork(int statusFd)
 pkgPackageManager::OrderResult 
 pkgPackageManager::DoInstallPostFork(APT::Progress::PackageManager *progress)
 {
-   bool goResult = Go(progress);
+   bool goResult;
+   auto simulation = dynamic_cast<pkgSimulate*>(this);
+   if (simulation == nullptr)
+      goResult = Go(progress);
+   else
+      goResult = simulation->Go2(progress);
    if(goResult == false) 
       return Failed;
    
index 25b6ee7c9bed2bf12fa24b2576ff24f8f5d600fa..5046e2dc0d55b08ccfefdd5a797ef80cdfece9a0 100644 (file)
@@ -99,7 +99,7 @@ class pkgPackageManager : protected pkgCache::Namespace
    virtual bool Configure(PkgIterator /*Pkg*/) {return false;};
    virtual bool Remove(PkgIterator /*Pkg*/,bool /*Purge*/=false) {return false;};
    virtual bool Go(APT::Progress::PackageManager * /*progress*/) {return true;};
-   virtual bool Go(int /*statusFd*/=-1) {return true;};
+   APT_DEPRECATED_MSG("Use overload with explicit progress manager") virtual bool Go(int /*statusFd*/=-1) {return true;};
 
    virtual void Reset() {};