summaryrefslogtreecommitdiff
path: root/apt-pkg/cachefilter.cc
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2017-01-17 00:08:16 +0100
committerJulian Andres Klode <jak@debian.org>2017-01-17 01:43:50 +0100
commit6ede8952f55a1bc356b42b1adc7b9bd504af943c (patch)
tree4cc3971fe0ad8ca7fc789f21033e4a1f89585d77 /apt-pkg/cachefilter.cc
parentc5b8afab0f409b06a63599ff1c5acb433f3957d4 (diff)
Read dpkg tables to handle architecture wildcards
Our implementation of wildcards was rudimentary. It worked for some common ones, but it was also broken: For example, armel matched any-armel, but should match any-arm. With this commit, we load the correct tables from dpkg. Supported are both triplets and quadruplet tables (the latter introduced in dpkg 1.18.11). There are some odd things we have to deal with in the cache filter for historical and API reasons: * The character "*" must be accepted as an alternative to any - in fact it may appear anywhere in the wildcard as we also allow fnmatch() style wildcard matching on the commandline. * The code might get passed an arch with a minus at the end, for example the cmdline "install apt:any-arm-" will first try to check if any-arm- is a valid architecture. We deal with this by rejecting any wildcard ending in a minus. * Triplets are actually implemented by extending them to faux quadruplets - by prepending a "base" component for the architecture tuple, and "any" if there is a wildcard component. Once we have constructed a wildcard, it is transformed into an fnmatch() expression for historical reasons. In the future, we should really get a tuple class and implement matching in a better, more explicit way. This does for now though - it passes all the test cases and accepts all things it should accept. Closes: #748936 Thanks: James Clarke <jrtc27@jrtc27.com> for the initial patch
Diffstat (limited to 'apt-pkg/cachefilter.cc')
-rw-r--r--apt-pkg/cachefilter.cc95
1 files changed, 67 insertions, 28 deletions
diff --git a/apt-pkg/cachefilter.cc b/apt-pkg/cachefilter.cc
index b1adf5de3..cc4cdf73c 100644
--- a/apt-pkg/cachefilter.cc
+++ b/apt-pkg/cachefilter.cc
@@ -14,7 +14,9 @@
#include <apt-pkg/strutl.h>
#include <apt-pkg/macros.h>
+#include <algorithm>
#include <string>
+#include <unordered_map>
#include <string.h>
#include <regex.h>
#include <fnmatch.h>
@@ -22,6 +24,9 @@
#include <apti18n.h>
/*}}}*/
namespace APT {
+
+APT_HIDDEN std::unordered_map<std::string, std::vector<std::string>> ArchToTupleMap;
+
namespace CacheFilter {
APT_CONST Matcher::~Matcher() {}
APT_CONST PackageMatcher::~PackageMatcher() {}
@@ -68,38 +73,72 @@ bool PackageNameMatchesFnmatch::operator() (pkgCache::GrpIterator const &Grp) {
return fnmatch(Pattern.c_str(), Grp.Name(), FNM_CASEFOLD) == 0;
}
/*}}}*/
-// Architecture matches <libc>-<kernel>-<cpu> specification /*{{{*/
+// Architecture matches <abi>-<libc>-<kernel>-<cpu> specification /*{{{*/
//----------------------------------------------------------------------
-/* The complete architecture, consisting of <libc>-<kernel>-<cpu>. */
-static std::string CompleteArch(std::string const &arch, bool const isPattern) {
- auto const found = arch.find('-');
- if (found != std::string::npos)
+
+static std::vector<std::string> ArchToTuple(std::string arch) {
+ // Strip leading linux- from arch if present
+ // dpkg says this may disappear in the future
+ if (APT::String::Startswith(arch, std::string("linux-")))
+ arch = arch.substr(6);
+
+ auto it = ArchToTupleMap.find(arch);
+ if (it != ArchToTupleMap.end())
+ {
+ std::vector<std::string> result = it->second;
+ // Hack in support for triplets
+ if (result.size() == 3)
+ result.emplace(result.begin(), "base");
+ return result;
+ } else
{
- // ensure that only -any- is replaced and not something like company-
- std::string complete = std::string("-").append(arch).append("-");
- size_t pos = 0;
- char const * const search = "-any-";
- auto const search_len = strlen(search) - 2;
- while((pos = complete.find(search, pos)) != std::string::npos) {
- complete.replace(pos + 1, search_len, "*");
- pos += 2;
+ return {};
+ }
+}
+
+static std::vector<std::string> PatternToTuple(std::string const &arch) {
+ std::vector<std::string> tuple = VectorizeString(arch, '-');
+ if (std::find(tuple.begin(), tuple.end(), std::string("any")) != tuple.end() ||
+ std::find(arch.begin(), arch.end(), '*') != arch.end()) {
+ while (tuple.size() < 4) {
+ tuple.emplace(tuple.begin(), "any");
+ }
+ return tuple;
+ } else
+ return ArchToTuple(arch);
+}
+
+/* The complete architecture, consisting of <abi>-<libc>-<kernel>-<cpu>. */
+static std::string CompleteArch(std::string const &arch, bool const isPattern) {
+ auto tuple = isPattern ? PatternToTuple(arch) : ArchToTuple(arch);
+
+ // Bah, the commandline will try and pass us stuff like amd64- -- we need
+ // that not to match an architecture, but the code below would turn it into
+ // a valid tuple. Let's just use an invalid tuple here.
+ if (APT::String::Endswith(arch, "-") || APT::String::Startswith(arch, "-"))
+ return "invalid-invalid-invalid-invalid";
+
+ if (tuple.empty()) {
+ // Fallback for unknown architectures
+ // Patterns never fail if they contain wildcards, so by this point, arch
+ // has no wildcards.
+ tuple = VectorizeString(arch, '-');
+ switch (tuple.size()) {
+ case 1:
+ tuple.emplace(tuple.begin(), "linux");
+ /* fall through */
+ case 2:
+ tuple.emplace(tuple.begin(), "gnu");
+ /* fall through */
+ case 3:
+ tuple.emplace(tuple.begin(), "base");
+ /* fall through */
+ break;
}
- complete = complete.substr(1, complete.size()-2);
- if (arch.find('-', found+1) != std::string::npos)
- // <libc>-<kernel>-<cpu> format
- return complete;
- // <kernel>-<cpu> format
- else if (isPattern)
- return "*-" + complete;
- else
- return "gnu-" + complete;
}
- else if (arch == "any")
- return "*-*-*";
- else if (isPattern)
- return "*-linux-" + arch;
- else
- return "gnu-linux-" + arch;
+
+ std::replace(tuple.begin(), tuple.end(), std::string("any"), std::string("*"));
+ return APT::String::Join(tuple, "-");
}
PackageArchitectureMatchesSpecification::PackageArchitectureMatchesSpecification(std::string const &pattern, bool const pisPattern) :
literal(pattern), complete(CompleteArch(pattern, pisPattern)), isPattern(pisPattern) {