diff options
-rw-r--r-- | CMake/config.h.in | 1 | ||||
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | apt-pkg/cachefilter.cc | 95 | ||||
-rw-r--r-- | apt-pkg/init.cc | 91 | ||||
-rw-r--r-- | doc/examples/configure-index | 5 | ||||
-rwxr-xr-x | test/integration/test-bug-632221-cross-dependency-satisfaction | 2 | ||||
-rw-r--r-- | test/libapt/cachefilter_test.cc | 97 |
7 files changed, 246 insertions, 51 deletions
diff --git a/CMake/config.h.in b/CMake/config.h.in index 6f39e2f58..7b068864c 100644 --- a/CMake/config.h.in +++ b/CMake/config.h.in @@ -63,6 +63,7 @@ #cmakedefine CONF_DIR "${CONF_DIR}" #cmakedefine LIBEXEC_DIR "${LIBEXEC_DIR}" #cmakedefine BIN_DIR "${BIN_DIR}" +#cmakedefine DPKG_DATADIR "${DPKG_DATADIR}" /* Group of the root user */ #cmakedefine ROOT_GROUP "${ROOT_GROUP}" diff --git a/CMakeLists.txt b/CMakeLists.txt index 0afc73c0c..f40e389ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -172,6 +172,12 @@ set(PACKAGE ${PROJECT_NAME}) set(PACKAGE_MAIL "APT Development Team <deity@lists.debian.org>") set(PACKAGE_VERSION "1.4~beta3") +if (NOT DEFINED DPKG_DATADIR) + execute_process(COMMAND perl -MDpkg -e "print $Dpkg::DATADIR;" + OUTPUT_VARIABLE DPKG_DATADIR_CMD OUTPUT_STRIP_TRAILING_WHITESPACE) + message(STATUS "Found dpkg data dir: ${DPKG_DATADIR_CMD}") + set(DPKG_DATADIR "${DPKG_DATADIR_CMD}" CACHE PATH "dpkg data directory") +endif() if (NOT DEFINED COMMON_ARCH) execute_process(COMMAND dpkg-architecture -qDEB_HOST_ARCH OUTPUT_VARIABLE COMMON_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) 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) { diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index 292d75071..8b25ca100 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -20,6 +20,11 @@ #include <string.h> #include <cstdlib> +#include <fstream> +#include <sstream> +#include <string> +#include <unordered_map> +#include <vector> #include <apti18n.h> /*}}}*/ @@ -30,6 +35,89 @@ const char *pkgVersion = PACKAGE_VERSION; const char *pkgLibVersion = Stringfy(APT_PKG_MAJOR) "." Stringfy(APT_PKG_MINOR) "." Stringfy(APT_PKG_RELEASE); +namespace APT { + APT_HIDDEN extern std::unordered_map<std::string, std::vector<std::string>> ArchToTupleMap; +} + +// Splits by whitespace. There may be continous spans of whitespace - they +// will be considered as one. +static std::vector<std::string> split(std::string const & s) +{ + std::vector<std::string> vec; + std::istringstream iss(s); + iss.imbue(std::locale::classic()); + for(std::string current_s; iss >> current_s; ) + vec.push_back(current_s); + return vec; +} + + +// pkgInitArchTupleMap - Initialize the architecture tuple map /*{{{*/ +// --------------------------------------------------------------------- +/* This initializes */ +static bool pkgInitArchTupleMap() +{ + auto tuplepath = _config->FindFile("Dir::dpkg::tupletable", DPKG_DATADIR "/tupletable"); + auto tripletpath = _config->FindFile("Dir::dpkg::triplettable", DPKG_DATADIR "/triplettable"); + auto cpupath = _config->FindFile("Dir::dpkg::cputable", DPKG_DATADIR "/cputable"); + + // Load a list of CPUs + std::vector<std::string> cpus; + std::ifstream cputable(cpupath); + for (std::string cpuline; std::getline(cputable, cpuline); ) + { + if (cpuline[0] == '#' || cpuline[0] == '\0') + continue; + auto cpurow = split(cpuline); + auto cpu = APT::String::Strip(cpurow.at(0)); + + cpus.push_back(cpu); + } + if (!cputable.eof()) + return _error->Error("Error reading the CPU table"); + + // Load the architecture tuple + std::ifstream tupletable; + if (FileExists(tuplepath)) + tupletable.open(tuplepath); + else if (FileExists(tripletpath)) + tupletable.open(tripletpath); + else + return _error->Error("Cannot find dpkg tuplet or triplet table"); + + APT::ArchToTupleMap.clear(); + for (std::string tupleline; std::getline(tupletable, tupleline); ) + { + if (tupleline[0] == '#' || tupleline[0] == '\0') + continue; + + std::vector<std::string> tuplerow = split(tupleline); + + auto tuple = APT::String::Strip(tuplerow.at(0)); + auto arch = APT::String::Strip(tuplerow.at(1)); + + if (tuple.find("<cpu>") == tuple.npos && arch.find("<cpu>") == arch.npos) + { + APT::ArchToTupleMap.insert({arch, VectorizeString(tuple, '-')}); + } + else + { + for (auto && cpu : cpus) + { + auto mytuple = SubstVar(tuple, std::string("<cpu>"), cpu); + auto myarch = SubstVar(arch, std::string("<cpu>"), cpu); + + APT::ArchToTupleMap.insert({myarch, VectorizeString(mytuple, '-')}); + } + } + } + if (!tupletable.eof()) + return _error->Error("Error reading the Tuple table"); + + return true; +} + /*}}}*/ + // pkgInitConfig - Initialize the configuration class /*{{{*/ // --------------------------------------------------------------------- @@ -193,6 +281,9 @@ bool pkgInitSystem(Configuration &Cnf,pkgSystem *&Sys) if (Sys == 0) return _error->Error(_("Unable to determine a suitable packaging system type")); } + + if (pkgInitArchTupleMap() == false) + return false; return Sys->Initialize(Cnf); } diff --git a/doc/examples/configure-index b/doc/examples/configure-index index 7ce5aef51..653bdec1e 100644 --- a/doc/examples/configure-index +++ b/doc/examples/configure-index @@ -751,3 +751,8 @@ translation::compress "<STRING>"; sources::extensions "<STRING>"; packages::extensions "<STRING>"; dir::filelistdir "<STRING>"; + +// Internal code. +dir::dpkg::tupletable "<FILE>"; +dir::dpkg::triplettable "<FILE>"; +dir::dpkg::cputable "<FILE>"; diff --git a/test/integration/test-bug-632221-cross-dependency-satisfaction b/test/integration/test-bug-632221-cross-dependency-satisfaction index 066e29d99..d52652cad 100755 --- a/test/integration/test-bug-632221-cross-dependency-satisfaction +++ b/test/integration/test-bug-632221-cross-dependency-satisfaction @@ -21,7 +21,7 @@ insertpackage 'unstable' 'foreigner' 'amd64,armel' '1.0' 'Multi-Arch: foreign' insertpackage 'unstable' 'arm-stuff' 'armel' '1.0' insertpackage 'unstable' 'linux-stuff' 'amd64,armel' '1.0' -insertsource 'unstable' 'apt' 'any' '0.8.15' 'Build-Depends: doxygen, libc6-dev, libc6-dev:native, cool:any, amdboot:amd64, foreigner, libfwibble-dev, arm-stuff [any-armel] | linux-stuff [ linux-any]' +insertsource 'unstable' 'apt' 'any' '0.8.15' 'Build-Depends: doxygen, libc6-dev, libc6-dev:native, cool:any, amdboot:amd64, foreigner, libfwibble-dev, arm-stuff [eabi-any-any-arm gnueabi-any-arm] | linux-stuff [ linux-any]' insertsource 'unstable' 'forbidden-no' 'any' '1' 'Build-Depends: amdboot:any' insertsource 'unstable' 'forbidden-same' 'any' '1' 'Build-Depends: libc6:any' diff --git a/test/libapt/cachefilter_test.cc b/test/libapt/cachefilter_test.cc index 28924b758..08812e0dc 100644 --- a/test/libapt/cachefilter_test.cc +++ b/test/libapt/cachefilter_test.cc @@ -1,6 +1,7 @@ #include <config.h> #include <apt-pkg/cachefilter.h> +#include <apt-pkg/fileutl.h> #include <string> @@ -9,17 +10,22 @@ TEST(CacheFilterTest, ArchitectureSpecification) { { - SCOPED_TRACE("Pattern is any-armhf"); - APT::CacheFilter::PackageArchitectureMatchesSpecification ams("any-armhf"); - EXPECT_TRUE(ams("armhf")); - EXPECT_FALSE(ams("armel")); - EXPECT_TRUE(ams("linux-armhf")); - EXPECT_FALSE(ams("linux-armel")); - EXPECT_TRUE(ams("kfreebsd-armhf")); - EXPECT_TRUE(ams("gnu-linux-armhf")); - EXPECT_FALSE(ams("gnu-linux-armel")); - EXPECT_TRUE(ams("gnu-kfreebsd-armhf")); - EXPECT_TRUE(ams("musl-linux-armhf")); + SCOPED_TRACE("Pattern is *"); + // * should be treated like any + APT::CacheFilter::PackageArchitectureMatchesSpecification ams("*"); + EXPECT_TRUE(ams("sparc")); + EXPECT_TRUE(ams("amd64")); + EXPECT_TRUE(ams("kfreebsd-amd64")); + } + { + SCOPED_TRACE("Pattern is any-i386"); + APT::CacheFilter::PackageArchitectureMatchesSpecification ams("any-i386"); + EXPECT_TRUE(ams("i386")); + EXPECT_FALSE(ams("amd64")); + EXPECT_TRUE(ams("linux-i386")); + EXPECT_FALSE(ams("linux-amd64")); + EXPECT_TRUE(ams("kfreebsd-i386")); + EXPECT_TRUE(ams("musl-linux-i386")); } { SCOPED_TRACE("Pattern is linux-any"); @@ -29,11 +35,9 @@ TEST(CacheFilterTest, ArchitectureSpecification) EXPECT_TRUE(ams("linux-armhf")); EXPECT_TRUE(ams("linux-armel")); EXPECT_FALSE(ams("kfreebsd-armhf")); - EXPECT_TRUE(ams("gnu-linux-armhf")); - EXPECT_TRUE(ams("gnu-linux-armel")); - EXPECT_FALSE(ams("gnu-kfreebsd-armhf")); EXPECT_TRUE(ams("musl-linux-armhf")); } + if (FileExists(DPKG_DATADIR "/tupletable")) { SCOPED_TRACE("Pattern is gnu-any-any"); APT::CacheFilter::PackageArchitectureMatchesSpecification ams("gnu-any-any"); //really? @@ -42,11 +46,32 @@ TEST(CacheFilterTest, ArchitectureSpecification) EXPECT_TRUE(ams("linux-armhf")); EXPECT_TRUE(ams("linux-armel")); EXPECT_TRUE(ams("kfreebsd-armhf")); - EXPECT_TRUE(ams("gnu-linux-armhf")); - EXPECT_TRUE(ams("gnu-linux-armel")); - EXPECT_TRUE(ams("gnu-kfreebsd-armhf")); EXPECT_FALSE(ams("musl-linux-armhf")); } + if (FileExists(DPKG_DATADIR "/triplettable")) + { + SCOPED_TRACE("Pattern is gnueabi-any-any"); + APT::CacheFilter::PackageArchitectureMatchesSpecification ams("gnueabi-any-any"); //really? + EXPECT_TRUE(ams("linux-armel")); + EXPECT_TRUE(ams("armel")); + EXPECT_FALSE(ams("armhf")); + EXPECT_FALSE(ams("linux-armhf")); + EXPECT_FALSE(ams("musleabihf-linux-armhf")); + } + if (FileExists(DPKG_DATADIR "/triplettable")) + { + SCOPED_TRACE("Pattern is gnueabihf-any-any"); + APT::CacheFilter::PackageArchitectureMatchesSpecification ams("gnueabihf-any-any"); //really? + EXPECT_FALSE(ams("linux-armel")); + EXPECT_FALSE(ams("armel")); + EXPECT_TRUE(ams("armhf")); + EXPECT_TRUE(ams("linux-armhf")); + EXPECT_FALSE(ams("musleabihf-linux-armhf")); + } + + // Weird ones - armhf's tuple is actually eabihf-gnu-linux-arm + // armel's tuple is actually eabi-gnu-linux-arm + // x32's tuple is actually x32-gnu-linux-amd64 { SCOPED_TRACE("Architecture is armhf"); APT::CacheFilter::PackageArchitectureMatchesSpecification ams("armhf", false); @@ -54,13 +79,41 @@ TEST(CacheFilterTest, ArchitectureSpecification) EXPECT_FALSE(ams("armel")); EXPECT_TRUE(ams("linux-any")); EXPECT_FALSE(ams("kfreebsd-any")); - EXPECT_TRUE(ams("any-armhf")); - EXPECT_FALSE(ams("any-armel")); + EXPECT_TRUE(ams("any-arm")); EXPECT_TRUE(ams("linux-armhf")); EXPECT_FALSE(ams("kfreebsd-armhf")); - EXPECT_TRUE(ams("gnu-linux-armhf")); - EXPECT_FALSE(ams("gnu-linux-armel")); - EXPECT_FALSE(ams("gnu-kfreebsd-armhf")); EXPECT_FALSE(ams("musl-linux-armhf")); } + { + SCOPED_TRACE("Pattern is any-arm"); + APT::CacheFilter::PackageArchitectureMatchesSpecification ams("any-arm"); + EXPECT_TRUE(ams("armhf")); + EXPECT_TRUE(ams("armel")); + EXPECT_TRUE(ams("linux-armhf")); + EXPECT_TRUE(ams("linux-armel")); + EXPECT_TRUE(ams("musl-linux-armhf")); + EXPECT_TRUE(ams("uclibc-linux-armel")); + + EXPECT_FALSE(ams("arm64")); + EXPECT_FALSE(ams("linux-arm64")); + EXPECT_FALSE(ams("kfreebsd-arm64")); + EXPECT_FALSE(ams("musl-linux-arm64")); + } + { + SCOPED_TRACE("Pattern is any-amd64"); + APT::CacheFilter::PackageArchitectureMatchesSpecification ams("any-amd64"); + EXPECT_TRUE(ams("amd64")); + EXPECT_TRUE(ams("x32")); + EXPECT_TRUE(ams("linux-amd64")); + EXPECT_TRUE(ams("linux-x32")); + EXPECT_TRUE(ams("kfreebsd-amd64")); + EXPECT_TRUE(ams("musl-linux-amd64")); + EXPECT_TRUE(ams("uclibc-linux-amd64")); + + EXPECT_FALSE(ams("i386")); + EXPECT_FALSE(ams("linux-i386")); + EXPECT_FALSE(ams("kfreebsd-i386")); + EXPECT_FALSE(ams("musl-linux-i386")); + EXPECT_FALSE(ams("uclibc-linux-i386")); + } } |