Browse Source

protect only the latest same-source providers from autoremove

Traditionally all providers are protected providing something as apt
can't know which of them is actually really providing the functionality
for the user ensuring that we don't propose the removal of used stuff,
but that is of course also keeping stuff around which could be removed.

That can cause the collection of multiple old providers until the
provided package is itself no longer needed (e.g. out-of-tree kernel
modules). We combat this by marking providers only from the newest
source package version so that old providers built by older versions of
the same source package can be garbage collected.
tags/debian/1.3_pre1
David Kalnischkies 5 years ago
parent
commit
a0ed43f732
2 changed files with 70 additions and 5 deletions
  1. +34
    -5
      apt-pkg/depcache.cc
  2. +36
    -0
      test/integration/test-apt-get-autoremove

+ 34
- 5
apt-pkg/depcache.cc View 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


+ 36
- 0
test/integration/test-apt-get-autoremove View File

@@ -108,3 +108,39 @@ testdpkgnotinstalled 'po-debconf' 'debhelper'
testmarkedauto
testsuccess aptget install debhelper --solver apt -y -o Debug::pkgDepCache::Marker=1
testmarkedauto 'po-debconf'

insertinstalledpackage 'bar' 'all' '1' 'Depends: foo-provider'
insertinstalledpackage 'foo-multi1-1' 'all' '1' 'Provides: foo-provider
Source: foo-multi (1)'
insertinstalledpackage 'foo-multi1-2' 'all' '1' 'Provides: foo-provider
Source: foo-multi (2)'
insertinstalledpackage 'foo-multi1-3' 'all' '1' 'Provides: foo-provider
Source: foo-multi (3)'
insertinstalledpackage 'foo-multi2-1' 'all' '1' 'Provides: foo-provider
Source: foo-multi (1)'
insertinstalledpackage 'foo-multi2-2' 'all' '1' 'Provides: foo-provider
Source: foo-multi (2)'
insertinstalledpackage 'foo-multi2-3' 'all' '1' 'Provides: foo-provider
Source: foo-multi (3)'
insertinstalledpackage 'foo-plus-1' 'all' '1' 'Provides: foo-provider
Source: foo-plus (1)'
insertinstalledpackage 'foo-plus-2' 'all' '1' 'Provides: foo-provider
Source: foo-plus (2)'
insertinstalledpackage 'foo-plus-3' 'all' '1' 'Provides: foo-provider
Source: foo-plus (3)'
insertinstalledpackage 'foo-single-1' 'all' '1' 'Provides: foo-provider'
insertinstalledpackage 'foo-single-2' 'all' '1' 'Provides: foo-provider'

testsuccess aptmark auto 'foo-*'
testsuccessequal 'Reading package lists...
Building dependency tree...
Reading state information...
The following packages will be REMOVED:
foo-multi1-1 foo-multi1-2 foo-multi2-1 foo-multi2-2 foo-plus-1 foo-plus-2
0 upgraded, 0 newly installed, 6 to remove and 0 not upgraded.
Remv foo-multi1-1 [1]
Remv foo-multi1-2 [1]
Remv foo-multi2-1 [1]
Remv foo-multi2-2 [1]
Remv foo-plus-1 [1]
Remv foo-plus-2 [1]' apt autoremove -s

Loading…
Cancel
Save