]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/depcache.cc
protect only the latest same-source providers from autoremove
[apt.git] / apt-pkg / depcache.cc
index eb8f6460d1454fe2995c3e1de7c05ce6d2be1aaf..1301cbdf910426c4f9bbf3bf9d485a7ac2afaa53 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/versionmatch.h>
+#include <apt-pkg/version.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/strutl.h>
@@ -1927,10 +1928,11 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &Pkg,
         continue;
 
       // handle the virtual part first
+      APT::VersionVector providers;
       for(auto Prv = T.ProvidesList(); Prv.end() == false; ++Prv)
       {
         auto PP = Prv.OwnerPkg();
-        if (PkgState[PP->ID].Marked || IsPkgInBoringState(PP, PkgState))
+        if (IsPkgInBoringState(PP, PkgState))
            continue;
 
         // we want to ignore provides from uninteresting versions
@@ -1939,10 +1941,37 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &Pkg,
         if (unlikely(PV.end()) || PV != Prv.OwnerVer() || D.IsSatisfied(Prv) == false)
            continue;
 
-        if (debug_autoremove)
-           std::clog << "Following dep: " << APT::PrettyDep(this, D)
-              << ", provided by " << PP.FullName() << " " << PV.VerStr() << std::endl;
-        MarkPackage(PP, PV, follow_recommends, follow_suggests);
+        providers.emplace_back(PV);
+      }
+      if (providers.empty() == false)
+      {
+        // sort providers by source version so that only the latest versioned
+        // binary package of a source package is marked instead of all
+        std::sort(providers.begin(), providers.end(),
+           [](pkgCache::VerIterator const &A, pkgCache::VerIterator const &B) {
+              auto const nameret = strcmp(A.SourcePkgName(), B.SourcePkgName());
+              if (nameret != 0)
+                 return nameret < 0;
+              auto const verret = A.Cache()->VS->CmpVersion(A.SourceVerStr(), B.SourceVerStr());
+              if (verret != 0)
+                 return verret > 0;
+              return strcmp(A.ParentPkg().Name(), B.ParentPkg().Name()) < 0;
+        });
+        auto const prvsize = providers.size();
+        providers.erase(std::unique(providers.begin(), providers.end(),
+           [](pkgCache::VerIterator const &A, pkgCache::VerIterator const &B) {
+              return strcmp(A.SourcePkgName(), B.SourcePkgName()) == 0 &&
+                 strcmp(A.SourceVerStr(), B.SourceVerStr()) != 0;
+           }), providers.end());
+        for (auto && PV: providers)
+        {
+           auto const PP = PV.ParentPkg();
+           if (debug_autoremove)
+              std::clog << "Following dep: " << APT::PrettyDep(this, D)
+                 << ", provided by " << PP.FullName() << " " << PV.VerStr()
+                 << " (" << providers.size() << "/" << prvsize << ")"<< std::endl;
+           MarkPackage(PP, PV, follow_recommends, follow_suggests);
+        }
       }
 
       // now deal with the real part of the package