From 570c27f2adbe47eb9799fbdfa52e2b4d9d32bf42 Mon Sep 17 00:00:00 2001
From: Robert Ancell <robert.ancell@canonical.com>
Date: Wed, 23 May 2018 17:03:36 +1200
Subject: [PATCH 1/2] aptcc: Only autoremove packages that relate to the
 current transaction

The previous code removed all orphaned packages on the system, which is
more aggressive than the 'autoremove' flag is supposed to do. The updated
code only removes newly orphaned packages after the transaction.
---
 backends/aptcc/apt-cache-file.cpp |  5 +++++
 backends/aptcc/apt-cache-file.h   |  5 +++++
 backends/aptcc/apt-intf.cpp       | 28 +++++++++++++++++++++-------
 backends/aptcc/apt-intf.h         |  2 +-
 4 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/backends/aptcc/apt-cache-file.cpp b/backends/aptcc/apt-cache-file.cpp
index e060b123d..5ae93552e 100644
--- a/backends/aptcc/apt-cache-file.cpp
+++ b/backends/aptcc/apt-cache-file.cpp
@@ -264,6 +264,11 @@ void AptCacheFile::buildPkgRecords()
     m_packageRecords = new pkgRecords(*this);
 }
 
+bool AptCacheFile::isGarbage(const pkgCache::PkgIterator &pkg)
+{
+    return (*this)[pkg].Garbage;
+}
+
 bool AptCacheFile::doAutomaticRemove()
 {
     pkgDepCache::ActionGroup group(*this);
diff --git a/backends/aptcc/apt-cache-file.h b/backends/aptcc/apt-cache-file.h
index a22a3a598..1ca862bb2 100644
--- a/backends/aptcc/apt-cache-file.h
+++ b/backends/aptcc/apt-cache-file.h
@@ -81,6 +81,11 @@ public:
       */
     inline pkgDepCache* GetDepCache() { BuildCaches(); BuildPolicy(); BuildDepCache(); return DCache; }
 
+    /**
+     * Checks if the package is garbage (not depended on)
+     */
+    bool isGarbage(const pkgCache::PkgIterator &pkg);
+
     /**
      * DoAutomaticRemove - Remove all automatic unused packages
      *
diff --git a/backends/aptcc/apt-intf.cpp b/backends/aptcc/apt-intf.cpp
index 8cf30ad77..cb6f1cce7 100644
--- a/backends/aptcc/apt-intf.cpp
+++ b/backends/aptcc/apt-intf.cpp
@@ -2156,6 +2156,16 @@ bool AptIntf::runTransaction(const PkgList &install, const PkgList &remove, cons
         const bool preserveAuto;
     };
 
+    // Calculate existing garbage before the transaction
+    PkgList initial_garbage;
+    if (autoremove) {
+        for (pkgCache::PkgIterator pkg = (*m_cache)->PkgBegin(); ! pkg.end(); ++pkg) {
+            const pkgCache::VerIterator &ver = m_cache->findCandidateVer(pkg);
+            if (!ver.end() && m_cache->isGarbage(pkg))
+                initial_garbage.push_back(ver);
+        }
+    }
+
     // new scope for the ActionGroup
     {
         pkgDepCache::ActionGroup group(*m_cache);
@@ -2196,6 +2206,15 @@ bool AptIntf::runTransaction(const PkgList &install, const PkgList &remove, cons
         }
     }
 
+    // Remove new garbage that is created
+    if (autoremove) {
+        for (pkgCache::PkgIterator pkg = (*m_cache)->PkgBegin(); ! pkg.end(); ++pkg) {
+            const pkgCache::VerIterator &ver = m_cache->findCandidateVer(pkg);
+            if (!ver.end() && !initial_garbage.contains(pkg) && m_cache->isGarbage(pkg))
+                m_cache->tryToRemove (Fix, ver);
+        }
+    }
+
     // Prepare for the restart thing
     struct stat restartStatStart;
     if (g_file_test(REBOOT_REQUIRED, G_FILE_TEST_EXISTS)) {
@@ -2204,7 +2223,7 @@ bool AptIntf::runTransaction(const PkgList &install, const PkgList &remove, cons
 
     // If we are simulating the install packages
     // will just calculate the trusted packages
-    const auto ret = installPackages(flags, autoremove);
+    const auto ret = installPackages(flags);
 
     if (g_file_test(REBOOT_REQUIRED, G_FILE_TEST_EXISTS)) {
         struct stat restartStat;
@@ -2233,17 +2252,12 @@ bool AptIntf::runTransaction(const PkgList &install, const PkgList &remove, cons
  * This displays the informative messages describing what is going to
  * happen and then calls the download routines
  */
-bool AptIntf::installPackages(PkBitfield flags, bool autoremove)
+bool AptIntf::installPackages(PkBitfield flags)
 {
     bool simulate = pk_bitfield_contain(flags, PK_TRANSACTION_FLAG_ENUM_SIMULATE);
     PkBackend *backend = PK_BACKEND(pk_backend_job_get_backend(m_job));
 
     //cout << "installPackages() called" << endl;
-    // Try to auto-remove packages
-    if (autoremove && !m_cache->doAutomaticRemove()) {
-        // TODO
-        return false;
-    }
 
     // check for essential packages!!!
     if (m_cache->isRemovingEssentialPackages()) {
diff --git a/backends/aptcc/apt-intf.h b/backends/aptcc/apt-intf.h
index a924fbf43..0473ecc0d 100644
--- a/backends/aptcc/apt-intf.h
+++ b/backends/aptcc/apt-intf.h
@@ -217,7 +217,7 @@ public:
     /**
       *  Download and install packages
       */
-    bool installPackages(PkBitfield flags, bool autoremove);
+    bool installPackages(PkBitfield flags);
 
     /**
      *  Check which package provides the codec
-- 
2.17.1

