summaryrefslogtreecommitdiff
path: root/apt-private/private-cacheset.cc
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2020-05-26 19:19:38 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2020-05-27 11:15:25 +0200
commit572810e9f321237873d1536c88991d7825c6f1db (patch)
treed9c5b07bc2d4ee4030214aef620a044bd1a6a6ad /apt-private/private-cacheset.cc
parent5eff00606c0c55cb6e456e521c8c4059e37264a0 (diff)
Allow =version and /release selector on virtual packages
We already have code for figuring out if a virtual package is only provided by a single provider (and otherwise show a list) we can auto-select for the user, so we can adapt that to work with versioned provides as well and while at it also release selectors. The code tries to keep ABI backward compatible and hence turns relatively ugly as we need a parameter (the selector) to be passed around without adding a parameter or new virtual methods.
Diffstat (limited to 'apt-private/private-cacheset.cc')
-rw-r--r--apt-private/private-cacheset.cc162
1 files changed, 119 insertions, 43 deletions
diff --git a/apt-private/private-cacheset.cc b/apt-private/private-cacheset.cc
index 2a5afac7b..2d85aaf4f 100644
--- a/apt-private/private-cacheset.cc
+++ b/apt-private/private-cacheset.cc
@@ -1,5 +1,6 @@
#include <config.h>
+#include <apt-pkg/cacheset.h>
#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/cachefile.h>
#include <apt-pkg/cachefilter.h>
@@ -102,8 +103,21 @@ pkgCache::VerIterator CacheSetHelperVirtuals::canNotGetVersion(
pkgCacheFile &Cache,
pkgCache::PkgIterator const &Pkg)
{
- if (select == NEWEST || select == CANDIDATE || select == ALL)
- virtualPkgs.insert(Pkg);
+ switch (select)
+ {
+ case VERSIONNUMBER:
+ case RELEASE:
+ case INSTALLED:
+ case CANDIDATE:
+ case NEWEST:
+ case ALL:
+ virtualPkgs.insert(Pkg);
+ break;
+ case CANDANDINST:
+ case CANDINST:
+ case INSTCAND:
+ break;
+ }
return CacheSetHelper::canNotGetVersion(select, Cache, Pkg);
}
void CacheSetHelperVirtuals::canNotFindVersion(
@@ -230,10 +244,11 @@ void CacheSetHelperAPTGet::showVersionSelection(pkgCache::PkgIterator const &Pkg
{
switch (select)
{
- case RELEASE:
case VERSIONNUMBER:
if (pattern == Ver.VerStr())
return;
+ /* fall through */
+ case RELEASE:
selectedByRelease.push_back(make_pair(Ver, pattern));
break;
default:
@@ -258,7 +273,9 @@ bool CacheSetHelperAPTGet::showVirtualPackageErrors(pkgCacheFile &Cache)
if (Cache[OPkg].CandidateVerIter(Cache) == I.OwnerVer())
{
- c1out << " " << OPkg.FullName(true) << " " << I.OwnerVer().VerStr();
+ c1out << " " << OPkg.FullName(true) << ' ' << I.OwnerVer().VerStr();
+ if (I->ProvideVersion != 0)
+ c1out << " (= " << I.ProvideVersion() << ")";
if (Cache[OPkg].Install() == true && Cache[OPkg].NewInstall() == false)
c1out << _(" [Installed]");
c1out << std::endl;
@@ -268,8 +285,12 @@ bool CacheSetHelperAPTGet::showVirtualPackageErrors(pkgCacheFile &Cache)
// if we found no candidate which provide this package, show non-candidates
if (provider == 0)
for (I = Pkg.ProvidesList(); I.end() == false; ++I)
- c1out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr()
- << _(" [Not candidate version]") << std::endl;
+ {
+ c1out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr();
+ if (I->ProvideVersion != 0)
+ c1out << " (= " << I.ProvideVersion() << ")";
+ c1out << _(" [Not candidate version]") << std::endl;
+ }
else
out << _("You should explicitly select one to install.") << std::endl;
} else {
@@ -305,6 +326,10 @@ pkgCache::VerIterator CacheSetHelperAPTGet::canNotGetVersion(enum VerSelector co
return canNotFindNewestVer(Cache, Pkg);
case CANDIDATE:
return canNotFindCandidateVer(Cache, Pkg);
+ case VERSIONNUMBER:
+ return canNotFindVersionNumber(Cache, Pkg, getLastVersionMatcher());
+ case RELEASE:
+ return canNotFindVersionRelease(Cache, Pkg, getLastVersionMatcher());
default:
return APT::CacheSetHelper::canNotGetVersion(select, Cache, Pkg);
}
@@ -324,6 +349,34 @@ void CacheSetHelperAPTGet::canNotFindVersion(enum VerSelector const select, APT:
}
}
+pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindVersionNumber(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg, std::string const &verstr)
+{
+ APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::VERSIONNUMBER);
+ if (not verset.empty())
+ return *(verset.begin());
+ else if (ShowError)
+ {
+ auto const V = canNotGetVerFromVersionNumber(Cache, Pkg, verstr);
+ if (not V.end())
+ return V;
+ virtualPkgs.insert(Pkg);
+ }
+ return pkgCache::VerIterator(Cache, 0);
+}
+pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindVersionRelease(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg, std::string const &verstr)
+{
+ APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::RELEASE);
+ if (not verset.empty())
+ return *(verset.begin());
+ else if (ShowError)
+ {
+ auto const V = canNotGetVerFromRelease(Cache, Pkg, verstr);
+ if (not V.end())
+ return V;
+ virtualPkgs.insert(Pkg);
+ }
+ return pkgCache::VerIterator(Cache, 0);
+}
pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg)
{
APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::CANDIDATE);
@@ -368,49 +421,72 @@ pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindNewestVer(pkgCacheFile &Ca
APT::VersionSet CacheSetHelperAPTGet::tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg,
CacheSetHelper::VerSelector const select)
{
- /* This is a pure virtual package and there is a single available
- candidate providing it. */
- if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0)
- return APT::VersionSet();
-
- pkgCache::PkgIterator Prov;
- bool found_one = false;
- for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; ++P) {
- pkgCache::VerIterator const PVer = P.OwnerVer();
- pkgCache::PkgIterator const PPkg = PVer.ParentPkg();
+ /* If this is a virtual package see if we have a single matching provider
+ (ignoring multiple matches from the same package due to e.g. M-A) */
+ if (Pkg->ProvidesList == 0)
+ return APT::VersionSet{};
- /* Ignore versions that are not a candidate. */
- if (Cache[PPkg].CandidateVer != PVer)
- continue;
+ auto const oldShowError = showErrors(false);
+ APT::VersionVector verset;
+ auto const lastmatcher = getLastVersionMatcher();
+ for (auto P = Pkg.ProvidesList(); not P.end(); ++P)
+ {
+ auto V = P.OwnerVer();
+ switch (select)
+ {
+ case RELEASE:
+ for (auto File = V.FileList(); not File.end(); ++File)
+ if (lastmatcher == File.File().Archive() || lastmatcher == File.File().Codename())
+ {
+ verset.push_back(V);
+ break;
+ }
+ break;
+ case VERSIONNUMBER:
+ if (P->ProvideVersion != 0 && lastmatcher == P.ProvideVersion())
+ verset.push_back(V);
+ break;
+ default:
+ if (Cache[V.ParentPkg()].CandidateVerIter(Cache) == V)
+ verset.push_back(V);
+ break;
+ }
+ }
+ // do not change the candidate if we have more than one option for this package
+ if (select == VERSIONNUMBER || select == RELEASE)
+ for (auto const &V : verset)
+ if (std::count_if(verset.begin(), verset.end(), [Pkg = V.ParentPkg()](auto const &v) { return v.ParentPkg() == Pkg; }) == 1)
+ Cache->SetCandidateVersion(V);
+ showErrors(oldShowError);
- if (found_one == false) {
- Prov = PPkg;
- found_one = true;
- } else if (PPkg != Prov) {
- // same group, so it's a foreign package
- if (PPkg->Group == Prov->Group) {
- // do we already have the requested arch?
- if (strcmp(Pkg.Arch(), Prov.Arch()) == 0 ||
- strcmp(Prov.Arch(), "all") == 0 ||
- unlikely(strcmp(PPkg.Arch(), Prov.Arch()) == 0)) // packages have only on candidate, but just to be sure
- continue;
- // see which architecture we prefer more and switch to it
- std::vector<std::string> archs = APT::Configuration::getArchitectures();
- if (std::find(archs.begin(), archs.end(), PPkg.Arch()) < std::find(archs.begin(), archs.end(), Prov.Arch()))
- Prov = PPkg;
+ pkgCache::VerIterator Choosen;
+ for (auto const &Ver : verset)
+ {
+ if (Choosen.end())
+ Choosen = Ver;
+ else
+ {
+ auto const ChoosenPkg = Choosen.ParentPkg();
+ auto const AltPkg = Ver.ParentPkg();
+ // seeing two different packages makes it not simple anymore
+ if (ChoosenPkg->Group != AltPkg->Group)
+ return APT::VersionSet{};
+ // do we already have the requested arch?
+ if (strcmp(Pkg.Arch(), ChoosenPkg.Arch()) == 0 ||
+ strcmp(ChoosenPkg.Arch(), "all") == 0)
continue;
- }
- found_one = false; // we found at least two
- break;
+ // see which architecture we prefer more and switch to it
+ std::vector<std::string> archs = APT::Configuration::getArchitectures();
+ if (std::find(archs.begin(), archs.end(), AltPkg.Arch()) < std::find(archs.begin(), archs.end(), ChoosenPkg.Arch()))
+ Choosen = Ver;
}
}
+ if (Choosen.end())
+ return APT::VersionSet{};
- if (found_one == true) {
- ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"),
- Prov.FullName(true).c_str(), Pkg.FullName(true).c_str());
- return APT::VersionSet::FromPackage(Cache, Prov, select, *this);
- }
- return APT::VersionSet();
+ ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"),
+ Choosen.ParentPkg().FullName(true).c_str(), Pkg.FullName(true).c_str());
+ return { Choosen };
}
pkgCache::PkgIterator CacheSetHelperAPTGet::canNotFindPkgName(pkgCacheFile &Cache, std::string const &str)
{