diff options
| author | Julian Andres Klode <jak@debian.org> | 2025-10-25 18:42:24 +0000 |
|---|---|---|
| committer | Julian Andres Klode <jak@debian.org> | 2025-10-25 18:42:24 +0000 |
| commit | 2698c1e186accebefa320ebacde7ec3c40c66c29 (patch) | |
| tree | 100d5321f364b389100928e927639e852c52ff48 | |
| parent | a92a5ecc465055027d9fbb899f359ec7eab110bd (diff) | |
| parent | 9d62eef571ffd1fd2df8b97884d3689fced27fb1 (diff) | |
Merge branch 'variants-submit' into 'main'
Merge Architecture variants from Ubuntu
See merge request apt-team/apt!526
| -rw-r--r-- | apt-pkg/acquire-item.cc | 54 | ||||
| -rw-r--r-- | apt-pkg/aptconfiguration.cc | 113 | ||||
| -rw-r--r-- | apt-pkg/aptconfiguration.h | 9 | ||||
| -rw-r--r-- | apt-pkg/cacheiterators.h | 10 | ||||
| -rw-r--r-- | apt-pkg/contrib/strutl.cc | 11 | ||||
| -rw-r--r-- | apt-pkg/contrib/strutl.h | 1 | ||||
| -rw-r--r-- | apt-pkg/deb/deblistparser.cc | 6 | ||||
| -rw-r--r-- | apt-pkg/deb/deblistparser.h | 4 | ||||
| -rw-r--r-- | apt-pkg/deb/debmetaindex.cc | 5 | ||||
| -rw-r--r-- | apt-pkg/init.cc | 17 | ||||
| -rw-r--r-- | apt-pkg/pkgcache.cc | 11 | ||||
| -rw-r--r-- | apt-pkg/pkgcache.h | 1 | ||||
| -rw-r--r-- | apt-pkg/pkgcachegen.cc | 29 | ||||
| -rw-r--r-- | apt-pkg/tagfile-keys.list | 1 | ||||
| -rw-r--r-- | apt-pkg/tagfile-order.c | 2 | ||||
| -rw-r--r-- | doc/examples/configure-index | 6 | ||||
| -rw-r--r-- | test/integration/framework | 11 | ||||
| -rwxr-xr-x | test/integration/test-architecture-variants | 244 | ||||
| -rw-r--r-- | test/integration/varianttable | 5 |
19 files changed, 520 insertions, 20 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index c692b5281..84f61b8bf 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -34,13 +34,13 @@ #include <algorithm> #include <array> #include <cerrno> -#include <ctime> #include <chrono> #include <cstddef> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> +#include <fstream> #include <iostream> #include <memory> #include <numeric> @@ -1598,6 +1598,48 @@ void pkgAcqMetaClearSig::QueueIndexes(bool const verify) /*{{{*/ componentsSeen.emplace(std::move(component)); } + auto variants = APT::Configuration::getArchitectureVariants(true); + std::set<IndexTarget *> supplantedTargets; + std::set<std::string> seenVariants; + if (hasReleaseFile) + { + // Figure out the variants that are standalone and supplant 'lesser' variants + for (auto &variant : variants) + { + // Check if the variant is standalone, that is, in the Architectures: field. + // FIXME: We should support Standalone-Architecture-Variants field here + if (not TransactionManager->MetaIndexParser->IsArchitectureSupported(variant.name)) + continue; + + seenVariants.insert(variant.name); + + // Iterate over all targets belonging to the architecture variant and then see if they + // supplant any other target. For example main/binary-amd64v3/Packages supplants main/binary-amd64/Packages + // but it won't supplant the contrib entry, or a Contents file. + for (auto &Target : IndexTargets) + { + if (Target.Option(IndexTarget::ARCHITECTURE) != variant.name) + continue; + + for (auto &BaseTarget : IndexTargets) + { + if (BaseTarget.Option(IndexTarget::IDENTIFIER) == Target.Option(IndexTarget::IDENTIFIER) && + BaseTarget.Option(IndexTarget::COMPONENT) == Target.Option(IndexTarget::COMPONENT) && + // Variants we already saw can never be supplanted here, because they are ordered by preference + seenVariants.find(BaseTarget.Option(IndexTarget::ARCHITECTURE)) == seenVariants.end() && + // BaseTarget is supplanted by Target on the architecture CPU + std::find(variant.supplants.begin(), variant.supplants.end(), BaseTarget.Option(IndexTarget::ARCHITECTURE)) != variant.supplants.end()) + { + if (_config->FindB("Debug::Acquire::Variants", false)) + std::clog << "Variant target " << Target.Description << " supplants target " << BaseTarget.Description << std::endl; + supplantedTargets.insert(&BaseTarget); + } + } + } + // + } + } + for (auto&& Target: IndexTargets) { // if we have seen a target which is created-by a target this one here is declared a @@ -1608,6 +1650,14 @@ void pkgAcqMetaClearSig::QueueIndexes(bool const verify) /*{{{*/ new CleanupItem(Owner, TransactionManager, Target); continue; } + + // If the target has been supplanted by a variant target, skip it. + if (supplantedTargets.find(&Target) != supplantedTargets.end()) + { + new CleanupItem(Owner, TransactionManager, Target); + continue; + } + // all is an implementation detail. Users shouldn't use this as arch // We need this support trickery here as e.g. Debian has binary-all files already, // but arch:all packages are still in the arch:any files, so we would waste precious @@ -3497,7 +3547,7 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *const Owner, pkgSourceList *const Sourc all repositories containing this file */ StoreFilename = QuoteString(Version.ParentPkg().Name(), "_:") + '_' + QuoteString(Version.VerStr(), "_:") + '_' + - QuoteString(Version.Arch(), "_:.") + + QuoteString(Version.ArchVariant().empty() ? Version.Arch() : Version.ArchVariant().data(), "_:.") + '.' += flExtension(poolfilename); Desc.URI = Index->ArchiveURI(poolfilename); diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc index 96ff8b285..a0164c6c3 100644 --- a/apt-pkg/aptconfiguration.cc +++ b/apt-pkg/aptconfiguration.cc @@ -24,6 +24,8 @@ #include <cstdio> #include <cstdlib> #include <cstring> +#include <fstream> +#include <optional> #include <string> #include <vector> #include <dirent.h> @@ -313,6 +315,117 @@ bool Configuration::checkLanguage(std::string Lang, bool const All) { return (std::find(langs.begin(), langs.end(), Lang) != langs.end()); } /*}}}*/ + +// getArchitectures - Return Vector of preferred Architectures /*{{{*/ + +static std::set<std::string> const &getCpuFlags() +{ + static std::set<std::string> flags; + if (not flags.empty()) + return flags; + + std::ifstream table(_config->FindFile("Dir::proc::cpuinfo", "/proc/cpuinfo")); + for (std::string line; std::getline(table, line);) + { + if (not APT::String::Startswith(line, "flags\t")) + continue; + + line = line.substr(line.find(':')); + line = line.substr(line.find_first_not_of(": ")); + if (flags.empty()) + for (auto &&flag : APT::String::Split(line)) + flags.insert(std::move(flag)); + else + { + // Remove flags not present in this CPU + auto split = APT::String::Split(line); + std::set<std::string> newSet{split.begin(), split.end()}; + for (auto it = flags.begin(); it != flags.end();) + if (newSet.find(*it) == newSet.end()) + it = flags.erase(it); + else + ++it; + } + } + return flags; +} +std::vector<Configuration::ArchitectureVariant> Configuration::getArchitectureVariants(bool cached) +{ + std::optional<std::vector<ArchitectureVariant>> static variants; + if (likely(cached) && variants) + return *variants; + + variants.emplace(); + + auto const configuredVariants = _config->FindVector("APT::Architecture-Variants"); + auto const architectures = getArchitectures(cached); + auto const autoDetect = configuredVariants.size() == 1 && configuredVariants.front() == "auto"; + auto const autoCpuFlags = getCpuFlags(); + auto tablepath = _config->FindFile("Dir::dpkg::varianttable", DPKG_DATADIR "/varianttable"); + std::ifstream table(tablepath); + auto isAutoVariant = [&](auto &var) + { + bool res = true; + for (auto want : var.cpuflags) + if (autoCpuFlags.find(want) == autoCpuFlags.end()) + { + if (_config->FindB("Debug::Acquire::Variants", false)) + std::clog << "variant auto: " << var.name << ": missing: " << want << "\n"; + res = false; + } + return res; + }; + for (std::string line; std::getline(table, line);) + { + if (line[0] == '#' || line[0] == '\0') + continue; + auto cols = APT::String::Split(line); + ArchitectureVariant var{cols[0], cols[1], VectorizeString(cols[2], ',')}; + // Skip disabled architectures. + if (std::find(architectures.begin(), architectures.end(), var.base) == architectures.end()) + { + continue; + } + // See if this variant is configured or we detect it as auto + bool enabled = std::find(configuredVariants.begin(), configuredVariants.end(), cols[0]) != configuredVariants.end() || (autoDetect && isAutoVariant(var)); + if (enabled) + variants->push_back(std::move(var)); + } + + if (not autoDetect) + for (auto &var : configuredVariants) + if (std::find_if(variants->begin(), variants->end(), [var](auto &v) + { return v.name == var; }) == variants->end()) + { + if (var == "auto") + _error->Warning("Invalid value for APT::Architecture-Variants: auto cannot be combined with explicit variants"); + else + _error->Warning("Invalid value for APT::Architecture-Variants: %s", var.c_str()); + } + + // Build the supplants table + for (auto var = variants->begin(); var != variants->end(); ++var) + { + var->supplants.push_back(var->base); + for (auto var2 = var + 1; var2 != variants->end(); ++var2) + if (var2->base == var->base) + var->supplants.push_back(var2->name); + } + + // Order variants by preference + std::sort(variants->begin(), variants->end(), [&](auto &a, auto &b) + { return std::find(configuredVariants.begin(), configuredVariants.end(), a.name) < std::find(configuredVariants.begin(), configuredVariants.end(), b.name); }); + if (_config->FindB("Debug::Acquire::Variants", false)) + { + std::clog << "Variants enabled:"; + for (auto &var : *variants) + std::clog << " " << var.name; + std::clog << std::endl; + } + + return *variants; +} + /*}}}*/ // getArchitectures - Return Vector of preferred Architectures /*{{{*/ std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) { std::vector<std::string> static archs; diff --git a/apt-pkg/aptconfiguration.h b/apt-pkg/aptconfiguration.h index 58c925b7f..c1979f3cc 100644 --- a/apt-pkg/aptconfiguration.h +++ b/apt-pkg/aptconfiguration.h @@ -131,6 +131,15 @@ namespace Configuration { /*{{{*/ /** \return Check usr is merged or produce error. */ APT_PUBLIC bool checkUsrMerged(); APT_PUBLIC std::string color(std::string const &colorName, std::string const &content = ""); + + struct ArchitectureVariant + { + std::string name; + std::string base; + std::vector<std::string> cpuflags; + std::vector<std::string> supplants{}; + }; + APT_HIDDEN std::vector<ArchitectureVariant> getArchitectureVariants(bool cached); #endif /*}}}*/ diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h index 45e45cc83..cc2179bf7 100644 --- a/apt-pkg/cacheiterators.h +++ b/apt-pkg/cacheiterators.h @@ -281,6 +281,16 @@ class APT_PUBLIC pkgCache::VerIterator : public Iterator<Version, VerIterator> { { return (static_cast<Version::Extra *>(Owner->Map.Data()) + S->d)->PhasedUpdatePercentage; } + inline void ArchVariant(map_stringitem_t variant) const + { + (static_cast<Version::Extra *>(Owner->Map.Data()) + S->d)->ArchVariant = variant; + } + inline std::string_view ArchVariant() const + { + if (auto I = (static_cast<Version::Extra *>(Owner->Map.Data()) + S->d)->ArchVariant) + return Owner->ViewString(I); + return {}; + } inline bool PhasedUpdatePercentage(unsigned int percentage) { if (percentage > 100) diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 651c985bd..b5200831a 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -138,6 +138,17 @@ size_t DisplayLength(string_view str) return len; } +// Splits by whitespace. There may be continuous spans of whitespace - they +// will be considered as one. +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; +} } } /*}}}*/ diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index 79b7c8bfa..c22b2dda2 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -48,6 +48,7 @@ namespace APT { APT_PUBLIC std::string Join(std::vector<std::string> list, const std::string_view &sep); // Returns string display length honoring multi-byte characters APT_PUBLIC size_t DisplayLength(std::string_view str); + APT_HIDDEN std::vector<std::string> Split(std::string const &str); } } diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index b62c1a84f..b98198430 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -215,6 +215,9 @@ bool debListParser::NewVersion(pkgCache::VerIterator &Ver) Ver->NextInSource = G->VersionsInSource; G->VersionsInSource = Ver.MapPointer(); + if (auto ArchVar = Section.Find(pkgTagSection::Key::Architecture_Variant); not ArchVar.empty()) + Ver.ArchVariant(StoreString(pkgCacheGenerator::MIXED, ArchVar)); + Ver->MultiArch = ParseMultiArch(true); // Archive Size Ver->Size = Section.FindULL(pkgTagSection::Key::Size); @@ -1017,6 +1020,9 @@ bool debListParser::SameVersion(uint32_t Hash, /*{{{*/ unsigned char MultiArch = ParseMultiArch(false); if (MultiArch != Ver->MultiArch) return false; + + if (ArchVariant() != Ver.ArchVariant()) + return false; // for all practical proposes (we can check): same version return true; } diff --git a/apt-pkg/deb/deblistparser.h b/apt-pkg/deb/deblistparser.h index 2a9108775..7ab6800c6 100644 --- a/apt-pkg/deb/deblistparser.h +++ b/apt-pkg/deb/deblistparser.h @@ -99,6 +99,10 @@ class APT_HIDDEN debListParser : public pkgCacheListParser { return Section.Find(pkgTagSection::Key::SHA256); } + std::string_view ArchVariant() const + { + return Section.Find(pkgTagSection::Key::Architecture_Variant); + } #endif }; diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc index c040b76b9..b85163654 100644 --- a/apt-pkg/deb/debmetaindex.cc +++ b/apt-pkg/deb/debmetaindex.cc @@ -1068,6 +1068,11 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/ auto veryforeign = _config->FindVector("APT::BarbarianArchitectures"); Values.reserve(Values.size() + veryforeign.size()); std::move(veryforeign.begin(), veryforeign.end(), std::back_inserter(Values)); + // Let's treat architecture variants as architectures for sources.list parsing + auto const &variants = APT::Configuration::getArchitectureVariants(true); + Values.reserve(Values.size() + variants.size()); + for (auto const &var : variants) + Values.push_back(var.name); } // all is a very special architecture users shouldn't be concerned with explicitly // but if the user does, do not override the choice diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index 61d45e37e..531cd258d 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -38,19 +38,6 @@ namespace APT { APT_HIDDEN extern std::unordered_map<std::string, std::vector<std::string>> ArchToTupleMap; } -// Splits by whitespace. There may be continuous 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 */ @@ -67,7 +54,7 @@ static bool pkgInitArchTupleMap() { if (cpuline[0] == '#' || cpuline[0] == '\0') continue; - auto cpurow = split(cpuline); + auto cpurow = APT::String::Split(cpuline); auto cpu = APT::String::Strip(cpurow.at(0)); cpus.emplace_back(cpu); @@ -90,7 +77,7 @@ static bool pkgInitArchTupleMap() if (tupleline[0] == '#' || tupleline[0] == '\0') continue; - std::vector<std::string> tuplerow = split(tupleline); + std::vector<std::string> tuplerow = APT::String::Split(tupleline); auto tuple = APT::String::Strip(tuplerow.at(0)); auto arch = APT::String::Strip(tuplerow.at(1)); diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 4101fb4e5..3377facac 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -193,6 +193,17 @@ bool pkgCache::ReMap(bool const &Errorchecks) list.append(","); list.append(arch); } + auto const variants = APT::Configuration::getArchitectureVariants(true); + if (not variants.empty()) + { + list.append(";"); + for (auto const &variant : variants) + { + if (list.back() != ';') + list.append(","); + list.append(variant.name); + } + } if (_config->Find("APT::Architecture") != StrP + HeaderP->Architecture || list != StrP + HeaderP->GetArchitectures()) return _error->Error(_("The package cache was built for different architectures: %s vs %s"), StrP + HeaderP->GetArchitectures(), list.c_str()); diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h index 7a9db3d20..042d928e1 100644 --- a/apt-pkg/pkgcache.h +++ b/apt-pkg/pkgcache.h @@ -724,6 +724,7 @@ struct pkgCache::Version struct pkgCache::Version::Extra { uint8_t PhasedUpdatePercentage; + map_stringitem_t ArchVariant; }; #endif /*}}}*/ diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index 3358441ee..f3c3c10a0 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -104,12 +104,23 @@ bool pkgCacheGenerator::Start() map_stringitem_t idxArchitectures; std::vector<std::string> archs = APT::Configuration::getArchitectures(); - if (archs.size() > 1) + auto const &variants = APT::Configuration::getArchitectureVariants(true); + if (archs.size() > 1 || not variants.empty()) { std::vector<std::string>::const_iterator a = archs.begin(); std::string list = *a; for (++a; a != archs.end(); ++a) list.append(",").append(*a); + if (not variants.empty()) + { + list.append(";"); + for (auto const &variant : variants) + { + if (list.back() != ';') + list.append(","); + list.append(variant.name); + } + } idxArchitectures = WriteStringInMap(list); if (unlikely(idxArchitectures == 0)) return false; @@ -383,11 +394,20 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator auto Hash = List.VersionHash(); std::string_view ListSHA256; + std::string_view ListArchVariant; bool const Debug = _config->FindB("Debug::pkgCacheGen", false); auto DebList = dynamic_cast<debListParser *>(&List); if (DebList != nullptr) ListSHA256 = DebList->SHA256(); + if (DebList != nullptr) + ListArchVariant = DebList->ArchVariant(); + + auto variants = _config->FindVector("APT::Architecture-Variants"); + // Always add "no variant" at the back of the list. If it's already configured earlier, that wins + if (variants.empty() || variants.back() != "") + variants.push_back(""); + if (Ver.end() == false) { /* We know the list is sorted so we use that fact in the search. @@ -426,6 +446,13 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator if (VF.end() == true) break; } + + // Variants are ordered by their index in the variant list. + if (std::find(variants.begin(), variants.end(), Ver.ArchVariant()) > std::find(variants.begin(), variants.end(), ListArchVariant)) + { + Res = 1; + break; + } } // proceed with the next till we have either the right // or we found another version (which will be lower) diff --git a/apt-pkg/tagfile-keys.list b/apt-pkg/tagfile-keys.list index d198ea0a5..8f5407354 100644 --- a/apt-pkg/tagfile-keys.list +++ b/apt-pkg/tagfile-keys.list @@ -81,3 +81,4 @@ Vcs-Svn Version ### APPEND BELOW, sort in with next ABI break ### Source-Version +Architecture-Variant diff --git a/apt-pkg/tagfile-order.c b/apt-pkg/tagfile-order.c index 7cf188c51..dbd45d6ac 100644 --- a/apt-pkg/tagfile-order.c +++ b/apt-pkg/tagfile-order.c @@ -9,6 +9,7 @@ static const char *iTFRewritePackageOrder[] = { "Package", "Package-Type", "Architecture", + "Architecture-Variant", "Subarchitecture", // NO_KEY: Used only by d-i "Version", // "Revision", // Obsolete (warning in dpkg) @@ -71,6 +72,7 @@ static const char *iTFRewriteSourceOrder[] = { "Format", "Binary", "Architecture", + "Architecture-Variant", "Version", "Priority", // "Class", // Obsolete alias for Priority, warning by dpkg diff --git a/doc/examples/configure-index b/doc/examples/configure-index index 1b050d0b9..f08026136 100644 --- a/doc/examples/configure-index +++ b/doc/examples/configure-index @@ -51,6 +51,7 @@ APT Audit "<BOOL>"; // display audit messages Architecture "<STRING>"; // debian architecture like amd64, i386, powerpc, armhf, mips, … Architectures "<LIST>"; // a list of (foreign) debian architectures, defaults to: dpkg --print-foreign-architectures + Architecture-Variants "<STRING_OR_LIST>"; // a list of variants or the string auto BarbarianArchitectures "<LIST>"; // a list of architectures considered too foreign to satisfy M-A:foreign Build-Essential "<LIST>"; // list of package names @@ -468,6 +469,9 @@ Dir "<DIR>" Boot "<DIR>"; Usr "<DIR>"; Apport "<DIR>"; + Proc "<DIR"> { + CpuInfo "<FILE>"; + }; }; // Things that effect the APT dselect method @@ -567,6 +571,7 @@ Debug Acquire::Transaction "<BOOL>"; Acquire::Progress "<BOOL>"; Acquire::Retries "<BOOL>"; // Debugging for retries, especially delays + Acquire::Variants "<BOOL>"; // Debugging for architecture variants aptcdrom "<BOOL>"; // Show found package files IdentCdrom "<BOOL>"; acquire::netrc "<BOOL>"; // netrc parser @@ -900,6 +905,7 @@ dir::filelistdir "<STRING>"; dir::dpkg::tupletable "<FILE>"; dir::dpkg::triplettable "<FILE>"; dir::dpkg::cputable "<FILE>"; +dir::dpkg::varianttable "<FILE>"; Rred::t "<BOOL>"; Rred::f "<BOOL>"; Rred::Compress "<STRING>"; diff --git a/test/integration/framework b/test/integration/framework index d95a1799a..7780ef835 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -547,6 +547,7 @@ exec fakeroot gdb --quiet -ex run '${DPKG:-dpkg}' --args '${DPKG:-dpkg}' --root= EOF chmod +x "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg" "${TMPWORKINGDIRECTORY}/rootdir/usr/bin/gdb-dpkg" echo "Dir::Bin::dpkg \"${TMPWORKINGDIRECTORY}/rootdir/usr/bin/dpkg\";" > rootdir/etc/apt/apt.conf.d/99dpkg + echo "Dir::dpkg::varianttable \"${TESTDIRECTORY}/varianttable\";" > rootdir/etc/apt/apt.conf.d/99variants # Set the solver for the test case. if [ "$APT_SOLVER" ]; then echo "APT::Solver \"$APT_SOLVER\";" >> aptconfig.conf @@ -1033,10 +1034,12 @@ insertpackage() { continue fi for arch in $(getarchitecturesfromcommalist "$ARCH"); do + local variant="${arch#*:}" + arch="${arch%:*}" if [ "$arch" = 'none' ]; then ARCHS="$(getarchitectures)" else - ARCHS="$arch" + ARCHS="$variant" fi for BUILDARCH in $ARCHS; do local PPATH="aptarchive/dists/${RELEASE}/${DISTSECTION}/binary-${BUILDARCH}" @@ -1054,8 +1057,9 @@ Size: 42" fi echo "Maintainer: Joe Sixpack <joe@example.org>" test "$arch" = 'none' || echo "Architecture: $arch" + test "$arch" = "$variant" || echo "Architecture-Variant: $variant" echo "Version: $VERSION -Filename: pool/${DISTSECTION}/${NAME}/${NAME}_${VERSION}_${arch}.deb" +Filename: pool/${DISTSECTION}/${NAME}/${NAME}_${VERSION}_${variant}.deb" test -z "$DEPENDENCIES" || printf "%b\n" "$DEPENDENCIES" echo "Description: $(printf '%s' "$DESCRIPTION" | head -n 1)" echo "Description-md5: $(printf '%s' "$DESCRIPTION" | md5sum | cut -d' ' -f 1)" @@ -1118,6 +1122,8 @@ insertinstalledpackage() { local FILE='rootdir/var/lib/dpkg/status' local INFO='rootdir/var/lib/dpkg/info' for arch in $(getarchitecturesfromcommalist "$ARCH"); do + local variant="${arch#*:}" + arch="${arch%:*}" echo "Package: $NAME Status: $STATUS Priority: $PRIORITY" >> "$FILE" @@ -1128,6 +1134,7 @@ Priority: $PRIORITY" >> "$FILE" Maintainer: Joe Sixpack <joe@example.org> Version: $VERSION" >> "$FILE" test "$arch" = 'none' || echo "Architecture: $arch" >> "$FILE" + test "$arch" = "$variant" || echo "Architecture-Variant: $variant" >> "$FILE" test -z "$DEPENDENCIES" || printf "%b\n" "$DEPENDENCIES" >> "$FILE" printf "%b\n" "Description: $DESCRIPTION" >> "$FILE" echo >> "$FILE" diff --git a/test/integration/test-architecture-variants b/test/integration/test-architecture-variants new file mode 100755 index 000000000..e116720c9 --- /dev/null +++ b/test/integration/test-architecture-variants @@ -0,0 +1,244 @@ +#!/bin/sh +set -e + +TESTDIR="$(readlink -f "$(dirname "$0")")" +. "$TESTDIR/framework" +setupenvironment +configarchitecture 'amd64' + +msgmsg "Test basic ordering scenarios" + +echo 'APT::Architecture-Variants { "amd64v3"; "amd64v2" }' > 'rootdir/etc/apt/apt.conf.d/variants' +insertpackage 'unstable' 'foo' 'amd64:amd64v2' '1' +insertpackage 'unstable' 'foo' 'amd64' '1' +insertpackage 'unstable' 'foo' 'amd64:amd64v3' '1' +setupaptarchive --no-update + +testsuccessequal "" aptget update -qq + +testsuccessequal "foo: + Installed: (none) + Candidate: 1 + Version table: + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v2 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages" aptcache policy foo +testsuccessequal "'file:${TMPWORKINGDIRECTORY}/aptarchive/pool/main/foo/foo_1_amd64v3.deb' foo_1_amd64v3.deb 42 " apt install --print-uris -qqq foo + +echo 'APT::Architecture-Variants { "amd64v2"; "amd64v3" }' > 'rootdir/etc/apt/apt.conf.d/variants' +testsuccessequal "foo: + Installed: (none) + Candidate: 1 + Version table: + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v2 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages" aptcache policy foo +testsuccessequal "'file:${TMPWORKINGDIRECTORY}/aptarchive/pool/main/foo/foo_1_amd64v2.deb' foo_1_amd64v2.deb 42 " apt install --print-uris -qqq foo +echo 'APT::Architecture-Variants { "amd64v3" }' > 'rootdir/etc/apt/apt.conf.d/variants' +testsuccessequal "foo: + Installed: (none) + Candidate: 1 + Version table: + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages" aptcache policy foo +testsuccessequal "'file:${TMPWORKINGDIRECTORY}/aptarchive/pool/main/foo/foo_1_amd64v3.deb' foo_1_amd64v3.deb 42 " apt install --print-uris -qqq foo + + +echo 'APT::Architecture-Variants { "amd64v3"; "amd64v2" }' > 'rootdir/etc/apt/apt.conf.d/variants' + +msgmsg "Test upgrade calculation: amd64v3 updates to amd64" + +insertpackage 'unstable' 'foo' 'amd64' '2' +insertinstalledpackage 'foo' 'amd64:amd64v3' '1' +setupaptarchive --no-update + +testsuccessequal "" aptget update -qq +testsuccessequal "foo: + Installed: 1 + Candidate: 2 + Version table: + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages + *** 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v2 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages" aptcache policy foo +testsuccessequal "'file:${TMPWORKINGDIRECTORY}/aptarchive/pool/main/foo/foo_2_amd64.deb' foo_2_amd64.deb 42 " apt dist-upgrade --print-uris -qqq + +msgmsg "Test upgrade calculation: amd64v3 updates to amd64v3 now" +insertpackage 'unstable' 'foo' 'amd64:amd64v3' '2' +setupaptarchive --no-update + +testsuccessequal "" aptget update -qq +testsuccessequal "foo: + Installed: 1 + Candidate: 2 + Version table: + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages + *** 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v2 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages" aptcache policy foo +testsuccessequal "'file:${TMPWORKINGDIRECTORY}/aptarchive/pool/main/foo/foo_2_amd64v3.deb' foo_2_amd64v3.deb 42 " apt dist-upgrade --print-uris -qqq + +msgmsg "Test standalone architecture variants" +sed -i 's/^Architectures:.*/Architectures: all amd64 amd64v3/' aptarchive/dists/unstable/Release +signreleasefiles +testsuccessequal "" aptget update -qq +testsuccessequal "foo: + Installed: 1 + Candidate: 2 + Version table: + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + *** 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy foo -o standalone=v3 +testsuccessequal "'file:${TMPWORKINGDIRECTORY}/aptarchive/pool/main/foo/foo_2_amd64v3.deb' foo_2_amd64v3.deb 42 " apt dist-upgrade --print-uris -qqq -o standalone=v3 + +sed -i 's/^Architectures:.*/Architectures: all amd64 amd64v3 amd64v2/' aptarchive/dists/unstable/Release +signreleasefiles +testsuccessequal "" aptget update -qq +testsuccessequal "foo: + Installed: 1 + Candidate: 2 + Version table: + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + *** 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy foo -o standalone=v3,v2 +testsuccessequal "'file:${TMPWORKINGDIRECTORY}/aptarchive/pool/main/foo/foo_2_amd64v3.deb' foo_2_amd64v3.deb 42 " apt dist-upgrade --print-uris -qqq -o standalone=v3,v2 + +sed -i 's/^Architectures:.*/Architectures: all amd64 amd64v2/' aptarchive/dists/unstable/Release +signreleasefiles +testsuccessequal "" aptget update -qq +# Notably v2 is now the standalone architecture so we need to fetch v3 and v2. +testsuccessequal "foo: + Installed: 1 + Candidate: 2 + Version table: + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + *** 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v2 Packages" aptcache policy foo -o standalone=v2 +testsuccessequal "'file:${TMPWORKINGDIRECTORY}/aptarchive/pool/main/foo/foo_2_amd64v3.deb' foo_2_amd64v3.deb 42 " apt dist-upgrade --print-uris -qqq -o standalone=v2 + +# amd64v2 is preferred now +sed -i 's/^Architectures:.*/Architectures: all amd64 amd64v3 amd64v2/' aptarchive/dists/unstable/Release +echo 'APT::Architecture-Variants { "amd64v2"; "amd64v3" }' > 'rootdir/etc/apt/apt.conf.d/variants' +signreleasefiles +testsuccessequal "" aptget update -qq +testsuccessequal "foo: + Installed: 1 + Candidate: 2 + Version table: + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v2 Packages + *** 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v3 Packages + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy foo -o standalone=v3,v2 -o pref=v2 +msgtest 'Test that amd64v2 is the candidate of the version 1' +testsuccessequal --nomsg "'file:${TMPWORKINGDIRECTORY}/aptarchive/pool/main/foo/foo_1_amd64v2.deb' foo_1_amd64v2.deb 42 " apt dist-upgrade --print-uris -qqq -o standalone=v3,v2 -o pref=v2 foo=1 + +msgmsg "Test automatic detection" +echo "flags : lm" > rootdir/cpuinfo +echo "flags : lm cmov cx8 fpu fxsr mmx syscall sse2 cx16 lahf_lm popcnt sse4_1 sse4_2 ssse3" >> rootdir/cpuinfo +echo 'APT::Architecture-Variants "auto";' > 'rootdir/etc/apt/apt.conf.d/variants' +echo 'Dir::Proc::CpuInfo "cpuinfo";'>> 'rootdir/etc/apt/apt.conf.d/variants' +testsuccessequal "" aptget update -qq +testsuccessequal "foo: + Installed: 1 + Candidate: 2 + Version table: + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages + *** 1 100 + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy foo -o auto=intersection + +echo "flags : lm cmov cx8 fpu fxsr mmx syscall sse2 cx16 lahf_lm popcnt sse4_1 sse4_2 ssse3" > rootdir/cpuinfo +echo 'APT::Architecture-Variants "auto";' > 'rootdir/etc/apt/apt.conf.d/variants' +echo 'Dir::Proc::CpuInfo "cpuinfo";'>> 'rootdir/etc/apt/apt.conf.d/variants' +testsuccessequal "" aptget update -qq +testsuccessequal "foo: + Installed: 1 + Candidate: 1 + Version table: + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v2 Packages + *** 1 100 + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy foo -o auto=v2 + +# Not a valid value for the auto field. +echo 'APT::Architecture-Variants "invalid";' > 'rootdir/etc/apt/apt.conf.d/variants' +echo 'Dir::Proc::CpuInfo "cpuinfo";'>> 'rootdir/etc/apt/apt.conf.d/variants' +testwarningequal "W: Invalid value for APT::Architecture-Variants: invalid" aptget update -qq +testwarningequal "foo: + Installed: 1 + Candidate: 2 + Version table: + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages + *** 1 100 + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status +W: Invalid value for APT::Architecture-Variants: invalid" aptcache policy foo -o auto=invalid + +# The unqualified one takes precedent +echo 'APT::Architecture-Variants "invalid";' > 'rootdir/etc/apt/apt.conf.d/variants' +echo 'APT::Architecture-Variants:: "amd64v2";' >> 'rootdir/etc/apt/apt.conf.d/variants' +echo 'Dir::Proc::CpuInfo "cpuinfo";'>> 'rootdir/etc/apt/apt.conf.d/variants' +testwarningequal "Variants enabled: +W: Invalid value for APT::Architecture-Variants: invalid" aptget update -qq -o debug::acquire::variants=1 +testwarningequal "foo: + Installed: 1 + Candidate: 2 + Version table: + 2 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages + *** 1 100 + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status +W: Invalid value for APT::Architecture-Variants: invalid" aptcache policy foo -o auto=invalid+v2 + + +echo 'APT::Architecture-Variants "auto,amd64v2";' > 'rootdir/etc/apt/apt.conf.d/variants' +echo 'Dir::Proc::CpuInfo "cpuinfo";'>> 'rootdir/etc/apt/apt.conf.d/variants' +testwarningequal "Variants enabled: amd64v2 +Variant target file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v2 Packages supplants target file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64 Packages +W: Invalid value for APT::Architecture-Variants: auto cannot be combined with explicit variants" aptget update -qq -o debug::acquire::variants=1 +testwarningequal "foo: + Installed: 1 + Candidate: 1 + Version table: + 1 500 + 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main amd64v2 Packages + *** 1 100 + 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status +W: Invalid value for APT::Architecture-Variants: auto cannot be combined with explicit variants" aptcache policy foo -o auto=auto,v2 diff --git a/test/integration/varianttable b/test/integration/varianttable new file mode 100644 index 000000000..29cccba93 --- /dev/null +++ b/test/integration/varianttable @@ -0,0 +1,5 @@ +# <variant> <arch> <flags> +amd64v4 amd64 lm,cmov,cx8,fpu,fxsr,mmx,syscall,sse2,cx16,lahf_lm,popcnt,sse4_1,sse4_2,ssse3,avx,avx2,bmi1,bmi2,f16c,fma,abm,movbe,xsave,avx512f,avx512bw,avx512cd,avx512dq,avx512vl +amd64v3 amd64 lm,cmov,cx8,fpu,fxsr,mmx,syscall,sse2,cx16,lahf_lm,popcnt,sse4_1,sse4_2,ssse3,avx,avx2,bmi1,bmi2,f16c,fma,abm,movbe,xsave +amd64v2 amd64 lm,cmov,cx8,fpu,fxsr,mmx,syscall,sse2,cx16,lahf_lm,popcnt,sse4_1,sse4_2,ssse3 +amd64v1 amd64 lm,cmov,cx8,fpu,fxsr,mmx,syscall,sse2 |
