#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>
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
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
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