From 9169cd5049bd7f0d5dcc56c40d567a766cf5b851 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 26 Jan 2018 16:15:13 +0100 Subject: Extend apt build-dep pkg/release to switch dep as needed apt install pkg/release follows versioned dependencies in the candidate switching if the current candidate does not satisfy the dependency, so for uniformity the same should be supported in build-dep. --- apt-private/private-install.cc | 12 +++++- apt-private/private-source.cc | 38 ++++++++++++++--- test/integration/test-apt-source-and-build-dep | 59 ++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index e1beb21c6..c9e45cc00 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -945,13 +945,21 @@ bool TryToInstall::propergateReleaseCandiateSwitching(std::listsecond.end() == true) + { + auto const pkgname = c->first.ParentPkg().FullName(true); + if (APT::String::Startswith(pkgname, "builddeps:")) + continue; ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"), - c->first.VerStr(), c->first.RelStr().c_str(), c->first.ParentPkg().FullName(true).c_str()); + c->first.VerStr(), c->first.RelStr().c_str(), pkgname.c_str()); + } else if (c->first.ParentPkg()->Group != c->second.ParentPkg()->Group) { + auto pkgname = c->second.ParentPkg().FullName(true); + if (APT::String::Startswith(pkgname, "builddeps:")) + pkgname.replace(0, strlen("builddeps"), "src"); pkgCache::VerIterator V = (*Cache)[c->first.ParentPkg()].CandidateVerIter(*Cache); ioprintf(out, _("Selected version '%s' (%s) for '%s' because of '%s'\n"), V.VerStr(), - V.RelStr().c_str(), V.ParentPkg().FullName(true).c_str(), c->second.ParentPkg().FullName(true).c_str()); + V.RelStr().c_str(), V.ParentPkg().FullName(true).c_str(), pkgname.c_str()); } } return Success; diff --git a/apt-private/private-source.cc b/apt-private/private-source.cc index 32651cfdb..a24493421 100644 --- a/apt-private/private-source.cc +++ b/apt-private/private-source.cc @@ -658,7 +658,15 @@ bool DoBuildDep(CommandLine &CmdL) StripMultiArch = true; std::ostringstream buildDepsPkgFile; - std::vector> pseudoPkgs; + struct PseudoPkg + { + std::string name; + std::string arch; + std::string release; + PseudoPkg(std::string const &n, std::string const &a, std::string const &r) : + name(n), arch(a), release(r) {} + }; + std::vector pseudoPkgs; // deal with the build essentials first { std::vector BuildDeps; @@ -675,7 +683,7 @@ bool DoBuildDep(CommandLine &CmdL) std::string const pseudo = "builddeps:essentials"; std::string const nativeArch = _config->Find("APT::Architecture"); WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, nativeArch, BuildDeps); - pseudoPkgs.emplace_back(pseudo, nativeArch); + pseudoPkgs.emplace_back(pseudo, nativeArch, ""); } // Read the source list @@ -703,7 +711,7 @@ bool DoBuildDep(CommandLine &CmdL) std::string const pseudo = std::string("builddeps:") + Src; WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch, GetBuildDeps(Last.get(), Src.c_str(), StripMultiArch, hostArch)); - pseudoPkgs.emplace_back(pseudo, pseudoArch); + pseudoPkgs.emplace_back(pseudo, pseudoArch, ""); } } else @@ -731,7 +739,13 @@ bool DoBuildDep(CommandLine &CmdL) std::string const pseudo = std::string("builddeps:") + Src; WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch, GetBuildDeps(Last, Src.c_str(), StripMultiArch, hostArch)); - pseudoPkgs.emplace_back(pseudo, pseudoArch); + std::string reltag = *I; + size_t found = reltag.find_last_of("/"); + if (found == std::string::npos) + reltag.clear(); + else + reltag.erase(0, found + 1); + pseudoPkgs.emplace_back(pseudo, pseudoArch, std::move(reltag)); } } @@ -745,12 +759,24 @@ bool DoBuildDep(CommandLine &CmdL) { pkgDepCache::ActionGroup group(Cache); TryToInstall InstallAction(Cache, &Fix, false); + std::list> candSwitch; + for (auto const &pkg: pseudoPkgs) + { + pkgCache::PkgIterator const Pkg = Cache->FindPkg(pkg.name, pkg.arch); + if (Pkg.end()) + continue; + if (pkg.release.empty()) + Cache->SetCandidateVersion(Pkg.VersionList()); + else + candSwitch.emplace_back(Pkg.VersionList(), pkg.release); + } + if (candSwitch.empty() == false) + InstallAction.propergateReleaseCandiateSwitching(candSwitch, c0out); for (auto const &pkg: pseudoPkgs) { - pkgCache::PkgIterator const Pkg = Cache->FindPkg(pkg.first, pkg.second); + pkgCache::PkgIterator const Pkg = Cache->FindPkg(pkg.name, pkg.arch); if (Pkg.end()) continue; - Cache->SetCandidateVersion(Pkg.VersionList()); InstallAction(Cache[Pkg].CandidateVerIter(Cache)); removeAgain.push_back(Pkg); } diff --git a/test/integration/test-apt-source-and-build-dep b/test/integration/test-apt-source-and-build-dep index 7f7457217..24790a578 100755 --- a/test/integration/test-apt-source-and-build-dep +++ b/test/integration/test-apt-source-and-build-dep @@ -14,6 +14,10 @@ insertpackage 'wheezy' 'build-essential' 'all' '1.0' # a "normal" package with source and binary insertpackage 'unstable' 'foo' 'all' '2.0' insertsource 'unstable' 'foo' 'all' '2.0' +insertpackage 'unstable' 'foo-common' 'all' '2.0' 'Source: foo (2.0)' +insertpackage 'experimental' 'foo' 'all' '5' 'Depends: foo-common (= 5)' +insertpackage 'experimental' 'foo-common' 'all' '5' 'Source: foo (5)' +insertsource 'experimental' 'foo-source' 'all' '42' 'Build-Depends: foo (= 5), baz' # binary packages with Source-field insertpackage 'unstable,testing' 'bin' 'i386' '3-2+b1' 'Source: bin (3-2)' @@ -40,6 +44,8 @@ insertsource 'wheezy' 'foo' 'all' '0.1' insertsource 'stable' 'baz' 'all' '1.0' insertsource 'unstable' 'baz' 'all' '2.0' insertsource 'unstable' 'baz' 'all' '1.5' +insertpackage 'unstable' 'baz' 'all' '2.0' +insertpackage 'experimental' 'baz' 'all' '5.0' # ensure we really have the situation we wanted (first 2.0 is foo above) testequal 'Version: 2.0 @@ -189,3 +195,56 @@ Need to get 0 B/43 B of source archives. Fetch source bin-backport" apt source bin/stable -s -q testsuccessequal "$(getbuilddep 'bin-backport' "Picking 'bin-backport' as source package instead of 'bin' Selected version '2-2' (stable) for bin-backport")" apt build-dep bin/stable -s + +testsuccess apt install foo/experimental -s +testfailure apt build-dep foo-source -s +testsuccessequal "Reading package lists... +Selected version '42' (experimental) for foo-source +Reading package lists... +Building dependency tree... +Selected version '5' (experimental [all]) for 'foo' because of 'src:foo-source' +Selected version '5' (experimental [all]) for 'foo-common' because of 'foo' +The following NEW packages will be installed: + baz build-essential foo foo-common +0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded. +Inst baz (2.0 unstable [all]) +Inst build-essential (1.0 wheezy [all]) +Inst foo-common (5 experimental [all]) +Inst foo (5 experimental [all]) +Conf baz (2.0 unstable [all]) +Conf build-essential (1.0 wheezy [all]) +Conf foo-common (5 experimental [all]) +Conf foo (5 experimental [all])" apt build-dep foo-source/experimental -s +testsuccessequal "Reading package lists... +Selected version '42' (experimental) for foo-source +Reading package lists... +Building dependency tree... +The following NEW packages will be installed: + baz build-essential foo foo-common +0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded. +Inst baz (5.0 experimental [all]) +Inst build-essential (1.0 wheezy [all]) +Inst foo-common (5 experimental [all]) +Inst foo (5 experimental [all]) +Conf baz (5.0 experimental [all]) +Conf build-essential (1.0 wheezy [all]) +Conf foo-common (5 experimental [all]) +Conf foo (5 experimental [all])" apt build-dep foo-source -t experimental -s +# this checks that mentioning the source pkg baz has no influence on the binary package baz +testsuccessequal "Reading package lists... +Selected version '42' (experimental) for foo-source +Selected version '2.0' (unstable) for baz +baz has no build depends. +Reading package lists... +Building dependency tree... +The following NEW packages will be installed: + baz build-essential foo foo-common +0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded. +Inst baz (5.0 experimental [all]) +Inst build-essential (1.0 wheezy [all]) +Inst foo-common (5 experimental [all]) +Inst foo (5 experimental [all]) +Conf baz (5.0 experimental [all]) +Conf build-essential (1.0 wheezy [all]) +Conf foo-common (5 experimental [all]) +Conf foo (5 experimental [all])" apt build-dep foo-source baz/unstable -t experimental -s -- cgit v1.2.3 From ce9223cc4e4ffcc43d17ae97ff8c57fb759a2c49 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 26 Jan 2018 23:33:25 +0100 Subject: Support release selector for volatile files as well The syntax is a bit awkward, but it is the same as for a package name and introducing another syntax wouldn't really help usability, so with apt install ./foo.deb/experimental you will get the dependencies of foo satisfied by your default release, but if this wouldn't satisfy the version requirements the candidate for this dependency is switched to the version from the experimental release. The same applies for apt build-dep ./foo.dsc/stable-backports which was the initial request. --- apt-private/private-install.cc | 80 +++++++++++++++++++++-- apt-private/private-install.h | 17 ++++- apt-private/private-source.cc | 70 +++++++++----------- apt-private/private-upgrade.cc | 3 +- test/integration/test-apt-install-file-reltag | 94 +++++++++++++++++++++++++++ 5 files changed, 214 insertions(+), 50 deletions(-) create mode 100755 test/integration/test-apt-install-file-reltag diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index c9e45cc00..4bb756b4f 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -564,16 +564,16 @@ static const unsigned short MOD_INSTALL = 2; bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, int UpgradeMode) { - std::vector VolatileCmdL; + std::vector VolatileCmdL; return DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, UpgradeMode); } -bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, int UpgradeMode) +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, int UpgradeMode) { std::map verset; std::set UnknownPackages; return DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, verset, UpgradeMode, UnknownPackages); } -bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, std::map &verset, int UpgradeMode, std::set &UnknownPackages) { // Enter the special broken fixing mode if the user specified arguments @@ -611,13 +611,18 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vectorFindPkg(I); + pkgCache::PkgIterator const P = Cache->FindPkg(I.name); if (P.end()) continue; // Set any version providing the .deb as the candidate. for (auto Prv = P.ProvidesList(); Prv.end() == false; Prv++) - Cache.GetDepCache()->SetCandidateVersion(Prv.OwnerVer()); + { + if (I.release.empty()) + Cache.GetDepCache()->SetCandidateVersion(Prv.OwnerVer()); + else + Cache.GetDepCache()->SetCandidateRelease(Prv.OwnerVer(), I.release); + } // via cacheset to have our usual virtual handling APT::VersionContainerInterface::FromPackage(&(verset[MOD_INSTALL]), Cache, P, APT::CacheSetHelper::CANDIDATE, helper); @@ -703,6 +708,68 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL)/*{{{*/ +{ + auto const ext = flExtension(pkg.name); + if (ext != "dsc" && FileExists(pkg.name + "/debian/control") == false) + return false; + std::vector files; + SL->AddVolatileFile(pkg.name, &files); + for (auto &&f: files) + VolatileCmdL.emplace_back(std::move(f), pkg.arch, pkg.release, pkg.index); + return true; + +} + /*}}}*/ +bool AddVolatileBinaryFile(pkgSourceList *const SL, PseudoPkg &&pkg, std::vector &VolatileCmdL)/*{{{*/ +{ + auto const ext = flExtension(pkg.name); + if (ext != "deb" && ext != "ddeb" && ext != "changes") + return false; + std::vector files; + SL->AddVolatileFile(pkg.name, &files); + for (auto &&f: files) + VolatileCmdL.emplace_back(std::move(f), pkg.arch, pkg.release, pkg.index); + return true; +} + /*}}}*/ +std::vector GetPseudoPackages(pkgSourceList *const SL, CommandLine &CmdL, bool (*Add)(pkgSourceList *const, PseudoPkg &&, std::vector &), std::string const &pseudoArch)/*{{{*/ +{ + std::vector VolatileCmdL; + std::remove_if(CmdL.FileList + 1, CmdL.FileList + 1 + CmdL.FileSize(), [&](char const *const I) { + if (I != nullptr && (I[0] == '/' || (I[0] == '.' && (I[1] == '\0' || (I[1] == '.' && (I[2] == '\0' || I[2] == '/')) || I[1] == '/')))) + { + PseudoPkg pkg(I, pseudoArch, "", SL->GetVolatileFiles().size()); + if (FileExists(I)) // this accepts directories and symlinks, too + { + if (Add(SL, std::move(pkg), VolatileCmdL)) + ; + else + _error->Error(_("Unsupported file %s given on commandline"), I); + return true; + } + else + { + auto const found = pkg.name.rfind("/"); + if (found == pkg.name.find("/")) + _error->Error(_("Unsupported file %s given on commandline"), I); + else + { + pkg.release = pkg.name.substr(found + 1); + pkg.name.erase(found); + if (Add(SL, std::move(pkg), VolatileCmdL)) + ; + else + _error->Error(_("Unsupported file %s given on commandline"), I); + } + return true; + } + } + return false; + }); + return VolatileCmdL; +} + /*}}}*/ // DoInstall - Install packages from the command line /*{{{*/ // --------------------------------------------------------------------- /* Install named packages */ @@ -721,8 +788,7 @@ struct PkgIsExtraInstalled { bool DoInstall(CommandLine &CmdL) { CacheFile Cache; - std::vector VolatileCmdL; - Cache.GetSourceList()->AddVolatileFiles(CmdL, &VolatileCmdL); + auto VolatileCmdL = GetPseudoPackages(Cache.GetSourceList(), CmdL, AddVolatileBinaryFile, ""); // then open the cache if (Cache.OpenForInstall() == false || diff --git a/apt-private/private-install.h b/apt-private/private-install.h index 2d27756c9..07aa582be 100644 --- a/apt-private/private-install.h +++ b/apt-private/private-install.h @@ -17,9 +17,22 @@ class pkgProblemResolver; APT_PUBLIC bool DoInstall(CommandLine &Cmd); -bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, +struct PseudoPkg +{ + std::string name; + std::string arch; + std::string release; + ssize_t index; + PseudoPkg(std::string const &n, std::string const &a, std::string const &r) : name(n), arch(a), release(r), index(-1) {} + PseudoPkg(std::string const &n, std::string const &a, std::string const &r, ssize_t i) : name(n), arch(a), release(r), index(i) {} +}; +std::vector GetPseudoPackages(pkgSourceList *const SL, CommandLine &CmdL, bool (*Add)(pkgSourceList *const, PseudoPkg &&, std::vector &), std::string const &pseudoArch); +bool AddVolatileBinaryFile(pkgSourceList *const SL, PseudoPkg &&pkg, std::vector &VolatileCmdL); +bool AddVolatileSourceFile(pkgSourceList *const SL, PseudoPkg &&pkg, std::vector &VolatileCmdL); + +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, std::map &verset, int UpgradeMode, std::set &UnknownPackages); -bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, int UpgradeMode); +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, int UpgradeMode); bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, int UpgradeMode); APT_PUBLIC bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, diff --git a/apt-private/private-source.cc b/apt-private/private-source.cc index a24493421..c8a48a74a 100644 --- a/apt-private/private-source.cc +++ b/apt-private/private-source.cc @@ -636,15 +636,6 @@ static void WriteBuildDependencyPackage(std::ostringstream &buildDepsPkgFile, } bool DoBuildDep(CommandLine &CmdL) { - CacheFile Cache; - std::vector VolatileCmdL; - Cache.GetSourceList()->AddVolatileFiles(CmdL, &VolatileCmdL); - - _config->Set("APT::Install-Recommends", false); - - if (CmdL.FileSize() <= 1 && VolatileCmdL.empty()) - return _error->Error(_("Must specify at least one package to check builddeps for")); - bool StripMultiArch; std::string hostArch = _config->Find("APT::Get::Host-Architecture"); if (hostArch.empty() == false) @@ -656,16 +647,18 @@ bool DoBuildDep(CommandLine &CmdL) } else StripMultiArch = true; + auto const nativeArch = _config->Find("APT::Architecture"); + std::string const pseudoArch = hostArch.empty() ? nativeArch : hostArch; + + CacheFile Cache; + auto VolatileCmdL = GetPseudoPackages(Cache.GetSourceList(), CmdL, AddVolatileSourceFile, pseudoArch); + + _config->Set("APT::Install-Recommends", false); + + if (CmdL.FileSize() <= 1 && VolatileCmdL.empty()) + return _error->Error(_("Must specify at least one package to check builddeps for")); std::ostringstream buildDepsPkgFile; - struct PseudoPkg - { - std::string name; - std::string arch; - std::string release; - PseudoPkg(std::string const &n, std::string const &a, std::string const &r) : - name(n), arch(a), release(r) {} - }; std::vector pseudoPkgs; // deal with the build essentials first { @@ -681,7 +674,6 @@ bool DoBuildDep(CommandLine &CmdL) BuildDeps.push_back(rec); } std::string const pseudo = "builddeps:essentials"; - std::string const nativeArch = _config->Find("APT::Architecture"); WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, nativeArch, BuildDeps); pseudoPkgs.emplace_back(pseudo, nativeArch, ""); } @@ -690,34 +682,34 @@ bool DoBuildDep(CommandLine &CmdL) if (Cache.BuildSourceList() == false) return false; pkgSourceList *List = Cache.GetSourceList(); - std::string const pseudoArch = hostArch.empty() ? _config->Find("APT::Architecture") : hostArch; - // FIXME: Avoid volatile sources == cmdline assumption { auto const VolatileSources = List->GetVolatileFiles(); - if (VolatileSources.size() == VolatileCmdL.size()) + for (auto &&pkg : VolatileCmdL) { - for (size_t i = 0; i < VolatileSources.size(); ++i) + if (unlikely(pkg.index == -1)) { - auto const Src = VolatileCmdL[i]; - if (DirectoryExists(Src)) - ioprintf(c1out, _("Note, using directory '%s' to get the build dependencies\n"), Src.c_str()); - else - ioprintf(c1out, _("Note, using file '%s' to get the build dependencies\n"), Src.c_str()); - std::unique_ptr Last(VolatileSources[i]->CreateSrcParser()); - if (Last == nullptr) - return _error->Error(_("Unable to find a source package for %s"), Src.c_str()); - - std::string const pseudo = std::string("builddeps:") + Src; - WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch, - GetBuildDeps(Last.get(), Src.c_str(), StripMultiArch, hostArch)); - pseudoPkgs.emplace_back(pseudo, pseudoArch, ""); + _error->Error(_("Unable to find a source package for %s"), pkg.name.c_str()); + continue; + } + if (DirectoryExists(pkg.name)) + ioprintf(c1out, _("Note, using directory '%s' to get the build dependencies\n"), pkg.name.c_str()); + else + ioprintf(c1out, _("Note, using file '%s' to get the build dependencies\n"), pkg.name.c_str()); + std::unique_ptr Last(VolatileSources[pkg.index]->CreateSrcParser()); + if (Last == nullptr) + { + _error->Error(_("Unable to find a source package for %s"), pkg.name.c_str()); + continue; } + + auto pseudo = std::string("builddeps:") + pkg.name; + WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch, + GetBuildDeps(Last.get(), pkg.name.c_str(), StripMultiArch, hostArch)); + pkg.name = std::move(pseudo); + pseudoPkgs.push_back(std::move(pkg)); } - else - return _error->Error("Implementation error: Volatile sources (%lu) and" - "commandline elements (%lu) do not match!", VolatileSources.size(), - VolatileCmdL.size()); + VolatileCmdL.clear(); } bool const WantLock = _config->FindB("APT::Get::Print-URIs", false) == false; diff --git a/apt-private/private-upgrade.cc b/apt-private/private-upgrade.cc index 989f6b0c1..aeaf5066b 100644 --- a/apt-private/private-upgrade.cc +++ b/apt-private/private-upgrade.cc @@ -19,8 +19,7 @@ static bool UpgradeHelper(CommandLine &CmdL, int UpgradeFlags) { CacheFile Cache; - std::vector VolatileCmdL; - Cache.GetSourceList()->AddVolatileFiles(CmdL, &VolatileCmdL); + auto VolatileCmdL = GetPseudoPackages(Cache.GetSourceList(), CmdL, AddVolatileBinaryFile, ""); if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false) return false; diff --git a/test/integration/test-apt-install-file-reltag b/test/integration/test-apt-install-file-reltag new file mode 100755 index 000000000..afbf9bef9 --- /dev/null +++ b/test/integration/test-apt-install-file-reltag @@ -0,0 +1,94 @@ +#!/bin/sh +set -e + +TESTDIR="$(readlink -f "$(dirname "$0")")" +. "$TESTDIR/framework" + +setupenvironment +configarchitecture 'i386' + +insertpackage 'unstable' 'foo' 'all' '2' 'Depends: foo-common (= 2)' +insertpackage 'unstable' 'foo-common' 'all' '2' +insertpackage 'unstable' 'baz' 'all' '1' +insertpackage 'experimental' 'foo' 'all' '5' 'Depends: foo-common (= 5)' +insertpackage 'experimental' 'foo-common' 'all' '5' 'Source: foo (5)' +insertpackage 'experimental' 'baz' 'all' '2' +setupaptarchive + +insertinstalledpackage 'build-essential' 'all' '1' + +cat > foobar.dsc < +Build-Depends: foo (= 5), baz +Standards-Version: 4.1.3 +EOF +buildsimplenativepackage 'foobar2' 'all' '1' 'unstable' 'Depends: foo (= 5), baz' + +ln -s "$(readlink -f ./incoming/foobar2_1_all.deb)" foobar.deb +mkdir -p foobar +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt build-dep "$(readlink -f ./foobar.dsc)" -s +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt install "$(readlink -f ./foobar.deb)" -s +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt build-dep ./foobar.dsc -s +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt install ./foobar.deb -s +cd foobar +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt build-dep ../foobar.dsc -s +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt install ../foobar.deb -s +cd .. + +SUCCESSDSC='The following NEW packages will be installed: + baz foo foo-common +0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded. +Inst baz (1 unstable [all]) +Inst foo-common (5 experimental [all]) +Inst foo (5 experimental [all]) +Conf baz (1 unstable [all]) +Conf foo-common (5 experimental [all]) +Conf foo (5 experimental [all])' +SUCCESSDEB='The following additional packages will be installed: + baz foo foo-common +The following NEW packages will be installed: + baz foo foo-common foobar2 +0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded. +Inst baz (1 unstable [all]) +Inst foo-common (5 experimental [all]) +Inst foo (5 experimental [all]) +Inst foobar2 (1 local-deb [all]) +Conf baz (1 unstable [all]) +Conf foo-common (5 experimental [all]) +Conf foo (5 experimental [all]) +Conf foobar2 (1 local-deb [all])' +testsuccessequal "Note, using file '$(readlink -f ./foobar.dsc)' to get the build dependencies +$SUCCESSDSC" apt build-dep "$(readlink -f ./foobar.dsc)/experimental" -s -q=2 +testsuccessequal "Reading package lists... +Building dependency tree... +Note, selecting 'foobar2' instead of '$(readlink -f ./foobar.deb)' +$SUCCESSDEB" apt install "$(readlink -f ./foobar.deb)/experimental" -s +testsuccessequal "Note, using file './foobar.dsc' to get the build dependencies +$SUCCESSDSC" apt build-dep ./foobar.dsc/experimental -sq=2 +testsuccessequal "Reading package lists... +Building dependency tree... +Note, selecting 'foobar2' instead of './foobar.deb' +$SUCCESSDEB" apt install "./foobar.deb/experimental" -s +cd foobar +testsuccessequal "Note, using file '../foobar.dsc' to get the build dependencies +$SUCCESSDSC" apt build-dep ../foobar.dsc/experimental -sqq +testsuccessequal "Reading package lists... +Building dependency tree... +Note, selecting 'foobar2' instead of '../foobar.deb' +$SUCCESSDEB" apt install "../foobar.deb/experimental" -s +cd .. + +msgmsg 'fail with' 'incorrect release' +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt build-dep "$(readlink -f ./foobar.dsc)/stable" -s +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt install "$(readlink -f ./foobar.deb)/stable" -s +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt build-dep ./foobar.dsc/stable -s +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt install ./foobar.deb/stable -s +cd foobar +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt build-dep ../foobar.dsc/stable -s +testfailuremsg 'E: Unable to correct problems, you have held broken packages.' apt install ../foobar.deb/stable -s +cd .. -- cgit v1.2.3 From 117ab302176a65536d9d55de30c53e94f08057ae Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 11 Apr 2018 12:39:40 +0200 Subject: Start pkg records for deb files with dpkg output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is easier to prepend our fields, but that results in confusion for things working on the so generated records as they don't start with the usual "Package" – that shouldn't be a problem in theory, but in practice e.g. "apt-cache show" shows these records directly to the user who will probably be more confused by it than tools. --- apt-pkg/deb/debindexfile.cc | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc index 10ebd1d3e..f7e3c7a5c 100644 --- a/apt-pkg/deb/debindexfile.cc +++ b/apt-pkg/deb/debindexfile.cc @@ -185,28 +185,22 @@ bool debDebPkgFileIndex::GetContent(std::ostream &content, std::string const &de if(Popen((const char**)&Args[0], PipeFd, Child, FileFd::ReadOnly) == false) return _error->Error("Popen failed"); - content << "Filename: " << debfile << "\n"; - content << "Size: " << std::to_string(Buf.st_size) << "\n"; + std::string line; bool first_line_seen = false; - char buffer[1024]; - do { - unsigned long long actual = 0; - if (PipeFd.Read(buffer, sizeof(buffer)-1, &actual) == false) - return _error->Errno("read", "Failed to read dpkg pipe"); - if (actual == 0) - break; - buffer[actual] = '\0'; - char const * b = buffer; + while (PipeFd.ReadLine(line)) + { if (first_line_seen == false) { - for (; *b != '\0' && (*b == '\n' || *b == '\r'); ++b) - /* skip over leading newlines */; - if (*b == '\0') + if (line.empty()) continue; first_line_seen = true; } - content << b; - } while(true); + else if (line.empty()) + break; + content << line << "\n"; + } + content << "Filename: " << debfile << "\n"; + content << "Size: " << std::to_string(Buf.st_size) << "\n"; ExecWait(Child, "Popen"); return true; -- cgit v1.2.3 From c5e2fa2b772524c03b0c7f777ffea6f2485fe6ca Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 11 Apr 2018 12:45:38 +0200 Subject: Deprectate buggy/incorrect Rls/PkgFile::IsOk methods With the advent of compressed files and especially with in-memory post-processed files the simple assumptions made in IsOk are no longer true. Worse, they are at best duplicates of checks performed by the cache generation (and validation) earlier and isn't used in too many places. It is hence best to simply get right of these calls instead of trying to fix them. --- apt-pkg/cacheiterators.h | 2 ++ apt-pkg/pkgcache.cc | 14 -------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h index 52915aae4..20853061e 100644 --- a/apt-pkg/cacheiterators.h +++ b/apt-pkg/cacheiterators.h @@ -422,6 +422,7 @@ class pkgCache::RlsFileIterator : public Iterator inline const char *Site() const {return S->Site == 0?0:Owner->StrP + S->Site;} inline bool Flagged(pkgCache::Flag::ReleaseFileFlags const flag) const {return (S->Flags & flag) == flag; } + APT_DEPRECATED_MSG("Can be remove without replacement; it is a no-op") bool IsOk(); std::string RelStr(); @@ -457,6 +458,7 @@ class pkgCache::PkgFileIterator : public Iterator inline const char *Architecture() const {return S->Architecture == 0?0:Owner->StrP + S->Architecture;} inline const char *IndexType() const {return S->IndexType == 0?0:Owner->StrP + S->IndexType;} + APT_DEPRECATED_MSG("Can be remove without replacement; it is a no-op") bool IsOk(); std::string RelStr(); diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 6b9c645a4..92f0cb777 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -968,13 +968,6 @@ const char * pkgCache::VerIterator::MultiArchType() const included here. */ bool pkgCache::RlsFileIterator::IsOk() { - struct stat Buf; - if (stat(FileName(),&Buf) != 0) - return false; - - if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime) - return false; - return true; } /*}}}*/ @@ -1002,13 +995,6 @@ string pkgCache::RlsFileIterator::RelStr() included here. */ bool pkgCache::PkgFileIterator::IsOk() { - struct stat Buf; - if (stat(FileName(),&Buf) != 0) - return false; - - if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime) - return false; - return true; } /*}}}*/ -- cgit v1.2.3 From bf53f39c9a0221b670ffff74053ed36fc502d5a0 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 11 Apr 2018 12:59:06 +0200 Subject: Support --with-source in show & search commands --- apt-private/private-search.cc | 9 +- apt-private/private-show.cc | 186 +++++++++++++++--------------- apt-private/private-show.h | 7 +- cmdline/apt-cache.cc | 7 +- test/integration/test-apt-get-install-deb | 36 +++++- 5 files changed, 141 insertions(+), 104 deletions(-) diff --git a/apt-private/private-search.cc b/apt-private/private-search.cc index 52a52e522..de1b19758 100644 --- a/apt-private/private-search.cc +++ b/apt-private/private-search.cc @@ -316,7 +316,14 @@ static bool Search(CommandLine &CmdL) if (matchedAll == true) { if (ShowFull == true) - DisplayRecordV1(CacheFile, J->V, std::cout); + { + pkgCache::VerFileIterator Vf; + auto &Parser = LookupParser(Recs, J->V, Vf); + char const *Start, *Stop; + Parser.GetRec(Start, Stop); + size_t const Length = Stop - Start; + DisplayRecordV1(CacheFile, Recs, J->V, Vf, Start, Length, std::cout); + } else printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str()); } diff --git a/apt-private/private-show.cc b/apt-private/private-show.cc index afe448a33..64251bed4 100644 --- a/apt-private/private-show.cc +++ b/apt-private/private-show.cc @@ -30,35 +30,23 @@ #include /*}}}*/ -static bool OpenPackagesFile(pkgCacheFile &CacheFile, pkgCache::VerIterator const &V,/*{{{*/ - FileFd &PkgF, pkgCache::VerFileIterator &Vf) +pkgRecords::Parser &LookupParser(pkgRecords &Recs, pkgCache::VerIterator const &V, pkgCache::VerFileIterator &Vf) /*{{{*/ { - pkgCache const * const Cache = CacheFile.GetPkgCache(); - if (unlikely(Cache == NULL)) - return false; - - // Find an appropriate file Vf = V.FileList(); for (; Vf.end() == false; ++Vf) if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0) break; if (Vf.end() == true) Vf = V.FileList(); - - // Check and load the package list file - pkgCache::PkgFileIterator I = Vf.File(); - if (I.IsOk() == false) - return _error->Error(_("Package file %s is out of sync."),I.FileName()); - - // Read the record - return PkgF.Open(I.FileName(), FileFd::ReadOnly, FileFd::Extension); + return Recs.Lookup(Vf); } /*}}}*/ -static APT_PURE unsigned char const* skipDescriptionFields(unsigned char const * DescP)/*{{{*/ +static APT_PURE char const *skipDescriptionFields(char const *DescP, size_t const Length) /*{{{*/ { + auto const backup = DescP; char const * const TagName = "\nDescription"; size_t const TagLen = strlen(TagName); - while ((DescP = (unsigned char*)strchr((char*)DescP, '\n')) != NULL) + while ((DescP = static_cast(memchr(DescP, '\n', Length - (DescP - backup)))) != nullptr) { if (DescP[1] == ' ') DescP += 2; @@ -72,114 +60,126 @@ static APT_PURE unsigned char const* skipDescriptionFields(unsigned char const * return DescP; } /*}}}*/ -bool DisplayRecordV1(pkgCacheFile &CacheFile, pkgCache::VerIterator const &V,/*{{{*/ - std::ostream &out) +static APT_PURE char const *findDescriptionField(char const *DescP, size_t const Length) /*{{{*/ { - FileFd PkgF; - pkgCache::VerFileIterator Vf; - if (OpenPackagesFile(CacheFile, V, PkgF, Vf) == false) - return false; + auto const backup = DescP; + char const * const TagName = "\nDescription"; + size_t const TagLen = strlen(TagName); + while ((DescP = static_cast(memchr(DescP, '\n', Length - (DescP - backup)))) != nullptr) + { + if (strncmp(DescP, TagName, TagLen) == 0) + break; + else + ++DescP; + } + if (DescP != nullptr) + ++DescP; + return DescP; +} + /*}}}*/ - pkgCache * const Cache = CacheFile.GetPkgCache(); - if (unlikely(Cache == NULL)) +bool DisplayRecordV1(pkgCacheFile &, pkgRecords &Recs, /*{{{*/ + pkgCache::VerIterator const &V, pkgCache::VerFileIterator const &, + char const *Buffer, size_t Length, std::ostream &out) +{ + if (unlikely(Length == 0)) return false; - // Read the record (and ensure that it ends with a newline and NUL) - unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+2]; - Buffer[Vf->Size] = '\n'; - Buffer[Vf->Size+1] = '\0'; - if (PkgF.Seek(Vf->Offset) == false || - PkgF.Read(Buffer,Vf->Size) == false) + auto const Desc = V.TranslatedDescription(); + if (Desc.end()) { - delete [] Buffer; - return false; + // we have no translation output whatever we have got + return FileFd::Write(STDOUT_FILENO, Buffer, Length); } // Get a pointer to start of Description field - const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "\nDescription"); - if (DescP != NULL) - ++DescP; - else - DescP = Buffer + Vf->Size; + char const *DescP = findDescriptionField(Buffer, Length); + if (DescP == nullptr) + DescP = Buffer + Length; // Write all but Description - size_t const length = DescP - Buffer; - if (length != 0 && FileFd::Write(STDOUT_FILENO, Buffer, length) == false) - { - delete [] Buffer; + size_t const untilDesc = DescP - Buffer; + if (untilDesc != 0 && FileFd::Write(STDOUT_FILENO, Buffer, untilDesc) == false) return false; - } // Show the right description - pkgRecords Recs(*Cache); - pkgCache::DescIterator Desc = V.TranslatedDescription(); - if (Desc.end() == false) - { - pkgRecords::Parser &P = Recs.Lookup(Desc.FileList()); - out << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc(); - out << std::endl << "Description-md5: " << Desc.md5() << std::endl; + char desctag[50]; + auto const langcode = Desc.LanguageCode(); + if (strcmp(langcode, "") == 0) + strcpy(desctag, "\nDescription"); + else + snprintf(desctag, sizeof(desctag), "\nDescription-%s", langcode); - // Find the first field after the description (if there is any) - DescP = skipDescriptionFields(DescP); + out << desctag + 1 << ": "; + auto const Df = Desc.FileList(); + if (Df.end() == false) + { + pkgRecords::Parser &P = Recs.Lookup(Df); + out << P.LongDesc(); } - // else we have no translation, so we found a lonely Description-md5 -> don't skip it + + out << std::endl << "Description-md5: " << Desc.md5() << std::endl; + + // Find the first field after the description (if there is any) + DescP = skipDescriptionFields(DescP, Length - (DescP - Buffer)); // write the rest of the buffer, but skip mixed in Descriptions* fields - while (DescP != NULL) + while (DescP != nullptr) { - const unsigned char * const Start = DescP; - const unsigned char *End = (unsigned char*)strstr((char*)DescP, "\nDescription"); - if (End == NULL) + char const *const Start = DescP; + char const *End = findDescriptionField(DescP, Length - (DescP - Buffer)); + if (End == nullptr) { - End = &Buffer[Vf->Size]; - DescP = NULL; + DescP = nullptr; + End = Buffer + Length - 1; + size_t endings = 0; + while (*End == '\n') + { + --End; + if (*End == '\r') + --End; + ++endings; + } + if (endings >= 1) + { + ++End; + if (*End == '\r') + ++End; + } + ++End; } else - { - ++End; // get the newline into the output - DescP = skipDescriptionFields(End + strlen("Description")); - } + DescP = skipDescriptionFields(End + strlen("Description"), Length - (End - Buffer)); + size_t const length = End - Start; if (length != 0 && FileFd::Write(STDOUT_FILENO, Start, length) == false) - { - delete [] Buffer; return false; - } } // write a final newline after the last field out << std::endl; - delete [] Buffer; return true; } /*}}}*/ -static bool DisplayRecordV2(pkgCacheFile &CacheFile, pkgCache::VerIterator const &V,/*{{{*/ - std::ostream &out) +static bool DisplayRecordV2(pkgCacheFile &CacheFile, pkgRecords &Recs, /*{{{*/ + pkgCache::VerIterator const &V, pkgCache::VerFileIterator const &Vf, + char const *Buffer, size_t const Length, std::ostream &out) { - FileFd PkgF; - pkgCache::VerFileIterator Vf; - if (OpenPackagesFile(CacheFile, V, PkgF, Vf) == false) - return false; - // Check and load the package list file pkgCache::PkgFileIterator I = Vf.File(); - if (I.IsOk() == false) - return _error->Error(_("Package file %s is out of sync."),I.FileName()); // find matching sources.list metaindex pkgSourceList *SrcList = CacheFile.GetSourceList(); pkgIndexFile *Index; if (SrcList->FindIndex(I, Index) == false && _system->FindIndex(I, Index) == false) - return _error->Error("Can not find indexfile for Package %s (%s)", - V.ParentPkg().Name(), V.VerStr()); + return _error->Error("Can not find indexfile for Package %s (%s)", + V.ParentPkg().Name(), V.VerStr()); std::string source_index_file = Index->Describe(true); // Read the record pkgTagSection Tags; - pkgTagFile TagF(&PkgF); - - if (TagF.Jump(Tags, V.FileList()->Offset) == false) + if (Tags.Scan(Buffer, Length, true) == false) return _error->Error("Internal Error, Unable to parse a package record"); // make size nice @@ -234,10 +234,6 @@ static bool DisplayRecordV2(pkgCacheFile &CacheFile, pkgCache::VerIterator const return _error->Error("Internal Error, Unable to parse a package record"); // write the description - pkgCache * const Cache = CacheFile.GetPkgCache(); - if (unlikely(Cache == NULL)) - return false; - pkgRecords Recs(*Cache); // FIXME: show (optionally) all available translations(?) pkgCache::DescIterator Desc = V.TranslatedDescription(); if (Desc.end() == false) @@ -245,7 +241,7 @@ static bool DisplayRecordV2(pkgCacheFile &CacheFile, pkgCache::VerIterator const pkgRecords::Parser &P = Recs.Lookup(Desc.FileList()); out << "Description: " << P.LongDesc(); } - + // write a final newline (after the description) out << std::endl << std::endl; @@ -255,6 +251,8 @@ static bool DisplayRecordV2(pkgCacheFile &CacheFile, pkgCache::VerIterator const bool ShowPackage(CommandLine &CmdL) /*{{{*/ { pkgCacheFile CacheFile; + if (unlikely(CacheFile.GetPkgCache() == nullptr)) + return false; CacheSetHelperVirtuals helper(true, GlobalError::NOTICE); APT::CacheSetHelper::VerSelector const select = _config->FindB("APT::Cache::AllVersions", true) ? APT::CacheSetHelper::ALL : APT::CacheSetHelper::CANDIDATE; @@ -262,15 +260,23 @@ bool ShowPackage(CommandLine &CmdL) /*{{{*/ return false; APT::VersionList const verset = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, select, helper); int const ShowVersion = _config->FindI("APT::Cache::Show::Version", 1); + pkgRecords Recs(CacheFile); for (APT::VersionList::const_iterator Ver = verset.begin(); Ver != verset.end(); ++Ver) + { + pkgCache::VerFileIterator Vf; + auto &Parser = LookupParser(Recs, Ver, Vf); + char const *Start, *Stop; + Parser.GetRec(Start, Stop); + size_t const Length = Stop - Start; + if (ShowVersion <= 1) { - if (DisplayRecordV1(CacheFile, Ver, std::cout) == false) + if (DisplayRecordV1(CacheFile, Recs, Ver, Vf, Start, Length, std::cout) == false) return false; } - else - if (DisplayRecordV2(CacheFile, Ver, c1out) == false) - return false; + else if (DisplayRecordV2(CacheFile, Recs, Ver, Vf, Start, Length + 1, c1out) == false) + return false; + } if (select == APT::CacheSetHelper::CANDIDATE) { diff --git a/apt-private/private-show.h b/apt-private/private-show.h index e48979c2c..9e5fa995f 100644 --- a/apt-private/private-show.h +++ b/apt-private/private-show.h @@ -3,6 +3,7 @@ #include #include +#include #include @@ -10,8 +11,12 @@ class CommandLine; class pkgCacheFile; APT_PUBLIC bool ShowPackage(CommandLine &CmdL); -APT_PUBLIC bool DisplayRecordV1(pkgCacheFile &CacheFile, pkgCache::VerIterator const &V, std::ostream &out); APT_PUBLIC bool ShowSrcPackage(CommandLine &CmdL); APT_PUBLIC bool Policy(CommandLine &CmdL); +pkgRecords::Parser &LookupParser(pkgRecords &Recs, pkgCache::VerIterator const &V, pkgCache::VerFileIterator &Vf); +bool DisplayRecordV1(pkgCacheFile &CacheFile, pkgRecords &Recs, + pkgCache::VerIterator const &V, pkgCache::VerFileIterator const &Vf, + char const *Buffer, size_t const Length, std::ostream &out); + #endif diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 085962699..f1b1e144d 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -470,12 +470,7 @@ static bool DumpAvail(CommandLine &) for (pkgCache::VerFile **J = VFList; *J != 0;) { pkgCache::PkgFileIterator File(*Cache,(*J)->File + Cache->PkgFileP); - if (File.IsOk() == false) - { - _error->Error(_("Package file %s is out of sync."),File.FileName()); - break; - } - + // FIXME: Add support for volatile/with-source files FileFd PkgF(File.FileName(),FileFd::ReadOnly, FileFd::Extension); if (_error->PendingError() == true) break; diff --git a/test/integration/test-apt-get-install-deb b/test/integration/test-apt-get-install-deb index 36e94a2dc..ff103a514 100755 --- a/test/integration/test-apt-get-install-deb +++ b/test/integration/test-apt-get-install-deb @@ -8,20 +8,26 @@ setupenvironment configarchitecture 'amd64' 'i386' # regression test for #754904 -testfailureequal 'E: Unsupported file /dev/null given on commandline' aptget install -qq /dev/null - -# only consider .deb files cat > foo.rpm < rootdir/etc/apt/preferences.d/pinit testsuccess aptget install ./incoming/pkg-as-it-should-be_0_all.deb testsuccess aptget install "$(readlink -f ./incoming/pkg-leading-newline_0_all.deb)" testsuccess aptget install ./incoming/pkg-trailing-newline_0_all.deb +testsuccess aptget install ./incoming/pkg-double-trailing-newline_0_all.deb testempty apt clean if [ "$(id -u)" = '0' ]; then -- cgit v1.2.3 From 6085ab7488326cfed8f82e07eefcbc2dc40d4bea Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Thu, 12 Apr 2018 09:59:47 +0200 Subject: Support local files as arguments in show command Now that --with-source is supported in show we can go a little further and add the "syntactic sugar" of supporting deb-files on the commandline directly to give users an alternative to remembering dpkg -I for deb files & as a bonus apt also works on changes files. Most of the code churn is actually to deal with cases probably not too common in reality like mixing packages and deb-files on the commandline and getting the right order for these multiple records. Closes: 883206 --- apt-private/private-install.cc | 63 ++++++++++++++++++------------ apt-private/private-install.h | 1 + apt-private/private-show.cc | 64 +++++++++++++++++++++++++++++-- test/integration/test-apt-get-install-deb | 31 ++++++++++++--- 4 files changed, 127 insertions(+), 32 deletions(-) diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index 4bb756b4f..f90e7097f 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -733,39 +733,54 @@ bool AddVolatileBinaryFile(pkgSourceList *const SL, PseudoPkg &&pkg, std::vector return true; } /*}}}*/ -std::vector GetPseudoPackages(pkgSourceList *const SL, CommandLine &CmdL, bool (*Add)(pkgSourceList *const, PseudoPkg &&, std::vector &), std::string const &pseudoArch)/*{{{*/ +static bool AddIfVolatile(pkgSourceList *const SL, std::vector &VolatileCmdL, bool (*Add)(pkgSourceList *const, PseudoPkg &&, std::vector &), char const * const I, std::string const &pseudoArch)/*{{{*/ { - std::vector VolatileCmdL; - std::remove_if(CmdL.FileList + 1, CmdL.FileList + 1 + CmdL.FileSize(), [&](char const *const I) { - if (I != nullptr && (I[0] == '/' || (I[0] == '.' && (I[1] == '\0' || (I[1] == '.' && (I[2] == '\0' || I[2] == '/')) || I[1] == '/')))) + if (I != nullptr && (I[0] == '/' || (I[0] == '.' && (I[1] == '\0' || (I[1] == '.' && (I[2] == '\0' || I[2] == '/')) || I[1] == '/')))) + { + PseudoPkg pkg(I, pseudoArch, "", SL->GetVolatileFiles().size()); + if (FileExists(I)) // this accepts directories and symlinks, too + { + if (Add(SL, std::move(pkg), VolatileCmdL)) + ; + else + _error->Error(_("Unsupported file %s given on commandline"), I); + return true; + } + else { - PseudoPkg pkg(I, pseudoArch, "", SL->GetVolatileFiles().size()); - if (FileExists(I)) // this accepts directories and symlinks, too + auto const found = pkg.name.rfind("/"); + if (found == pkg.name.find("/")) + _error->Error(_("Unsupported file %s given on commandline"), I); + else { + pkg.release = pkg.name.substr(found + 1); + pkg.name.erase(found); if (Add(SL, std::move(pkg), VolatileCmdL)) ; else _error->Error(_("Unsupported file %s given on commandline"), I); - return true; - } - else - { - auto const found = pkg.name.rfind("/"); - if (found == pkg.name.find("/")) - _error->Error(_("Unsupported file %s given on commandline"), I); - else - { - pkg.release = pkg.name.substr(found + 1); - pkg.name.erase(found); - if (Add(SL, std::move(pkg), VolatileCmdL)) - ; - else - _error->Error(_("Unsupported file %s given on commandline"), I); - } - return true; } + return true; } - return false; + } + return false; +} + /*}}}*/ +std::vector GetAllPackagesAsPseudo(pkgSourceList *const SL, CommandLine &CmdL, bool (*Add)(pkgSourceList *const, PseudoPkg &&, std::vector &), std::string const &pseudoArch)/*{{{*/ +{ + std::vector PkgCmdL; + std::for_each(CmdL.FileList + 1, CmdL.FileList + CmdL.FileSize(), [&](char const *const I) { + if (AddIfVolatile(SL, PkgCmdL, Add, I, pseudoArch) == false) + PkgCmdL.emplace_back(I, pseudoArch, "", -1); + }); + return PkgCmdL; +} + /*}}}*/ +std::vector GetPseudoPackages(pkgSourceList *const SL, CommandLine &CmdL, bool (*Add)(pkgSourceList *const, PseudoPkg &&, std::vector &), std::string const &pseudoArch)/*{{{*/ +{ + std::vector VolatileCmdL; + std::remove_if(CmdL.FileList + 1, CmdL.FileList + 1 + CmdL.FileSize(), [&](char const *const I) { + return AddIfVolatile(SL, VolatileCmdL, Add, I, pseudoArch); }); return VolatileCmdL; } diff --git a/apt-private/private-install.h b/apt-private/private-install.h index 07aa582be..39a040e7d 100644 --- a/apt-private/private-install.h +++ b/apt-private/private-install.h @@ -26,6 +26,7 @@ struct PseudoPkg PseudoPkg(std::string const &n, std::string const &a, std::string const &r) : name(n), arch(a), release(r), index(-1) {} PseudoPkg(std::string const &n, std::string const &a, std::string const &r, ssize_t i) : name(n), arch(a), release(r), index(i) {} }; +std::vector GetAllPackagesAsPseudo(pkgSourceList *const SL, CommandLine &CmdL, bool (*Add)(pkgSourceList *const, PseudoPkg &&, std::vector &), std::string const &pseudoArch); std::vector GetPseudoPackages(pkgSourceList *const SL, CommandLine &CmdL, bool (*Add)(pkgSourceList *const, PseudoPkg &&, std::vector &), std::string const &pseudoArch); bool AddVolatileBinaryFile(pkgSourceList *const SL, PseudoPkg &&pkg, std::vector &VolatileCmdL); bool AddVolatileSourceFile(pkgSourceList *const SL, PseudoPkg &&pkg, std::vector &VolatileCmdL); diff --git a/apt-private/private-show.cc b/apt-private/private-show.cc index 64251bed4..15c05d420 100644 --- a/apt-private/private-show.cc +++ b/apt-private/private-show.cc @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -251,6 +252,8 @@ static bool DisplayRecordV2(pkgCacheFile &CacheFile, pkgRecords &Recs, /*{{{*/ bool ShowPackage(CommandLine &CmdL) /*{{{*/ { pkgCacheFile CacheFile; + auto VolatileCmdL = GetAllPackagesAsPseudo(CacheFile.GetSourceList(), CmdL, AddVolatileBinaryFile, ""); + if (unlikely(CacheFile.GetPkgCache() == nullptr)) return false; CacheSetHelperVirtuals helper(true, GlobalError::NOTICE); @@ -258,7 +261,38 @@ bool ShowPackage(CommandLine &CmdL) /*{{{*/ APT::CacheSetHelper::ALL : APT::CacheSetHelper::CANDIDATE; if (select == APT::CacheSetHelper::CANDIDATE && CacheFile.GetDepCache() == nullptr) return false; - APT::VersionList const verset = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, select, helper); + + APT::VersionList verset; + size_t normalPackages = 0; + for (auto const &I: VolatileCmdL) + { + if (I.index == -1) + { + APT::VersionContainerInterface::FromString(&verset, CacheFile, I.name, select, helper); + ++normalPackages; + } + else + { + if (select != APT::CacheSetHelper::CANDIDATE && unlikely(CacheFile.GetDepCache() == nullptr)) + return false; + pkgCache::PkgIterator const P = CacheFile->FindPkg(I.name); + if (unlikely(P.end())) + continue; + + // Set any version providing the .deb as the candidate. + for (auto Prv = P.ProvidesList(); Prv.end() == false; ++Prv) + { + if (I.release.empty()) + CacheFile->SetCandidateVersion(Prv.OwnerVer()); + else + CacheFile->SetCandidateRelease(Prv.OwnerVer(), I.release); + + // via cacheset to have our usual handling + APT::VersionContainerInterface::FromPackage(&verset, CacheFile, Prv.OwnerPkg(), APT::CacheSetHelper::CANDIDATE, helper); + } + } + } + int const ShowVersion = _config->FindI("APT::Cache::Show::Version", 1); pkgRecords Recs(CacheFile); for (APT::VersionList::const_iterator Ver = verset.begin(); Ver != verset.end(); ++Ver) @@ -278,9 +312,33 @@ bool ShowPackage(CommandLine &CmdL) /*{{{*/ return false; } - if (select == APT::CacheSetHelper::CANDIDATE) + if (select == APT::CacheSetHelper::CANDIDATE && normalPackages != 0) { - APT::VersionList const verset_all = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::CacheSetHelper::ALL, helper); + APT::VersionList verset_all; + for (auto const &I: VolatileCmdL) + { + if (I.index == -1) + APT::VersionContainerInterface::FromString(&verset_all, CacheFile, I.name, APT::CacheSetHelper::ALL, helper); + else + { + pkgCache::PkgIterator const P = CacheFile->FindPkg(I.name); + if (unlikely(P.end())) + continue; + + // Set any version providing the .deb as the candidate. + for (auto Prv = P.ProvidesList(); Prv.end() == false; ++Prv) + { + if (I.release.empty()) + CacheFile->SetCandidateVersion(Prv.OwnerVer()); + else + CacheFile->SetCandidateRelease(Prv.OwnerVer(), I.release); + + // via cacheset to have our usual virtual handling + APT::VersionContainerInterface::FromPackage(&verset_all, CacheFile, Prv.OwnerPkg(), APT::CacheSetHelper::CANDIDATE, helper); + } + } + } + int const records = verset_all.size() - verset.size(); if (records > 0) _error->Notice(P_("There is %i additional record. Please use the '-a' switch to see it", "There are %i additional records. Please use the '-a' switch to see them.", records), records); diff --git a/test/integration/test-apt-get-install-deb b/test/integration/test-apt-get-install-deb index ff103a514..844f1d7c5 100755 --- a/test/integration/test-apt-get-install-deb +++ b/test/integration/test-apt-get-install-deb @@ -48,16 +48,37 @@ E: Unable to correct problems, you have held broken packages." aptget install ./ testsuccess apt show foo --with-source ./incoming/foo_1.0_amd64.deb testequal 'Package: foo -Version: 1.0' head -n 2 rootdir/tmp/testsuccess.output +Version: 1.0' grep -e '^Package:' -e '^Version:' -e '^Architecture:' rootdir/tmp/testsuccess.output +testsuccess apt show ./incoming/foo_1.0_amd64.deb +testequal 'Package: foo +Version: 1.0' grep -e '^Package:' -e '^Version:' -e '^Architecture:' rootdir/tmp/testsuccess.output +testsuccess apt show foo:i386 ./incoming/foo_1.0_amd64.deb --with-source ./incoming/foo_1.0_i386.deb +testequal 'Package: foo:i386 +Version: 1.0 +Package: foo +Version: 1.0' grep -e '^Package:' -e '^Version:' -e '^Architecture:' rootdir/tmp/testsuccess.output + +testsuccess aptcache show foo --with-source ./incoming/foo_1.0_amd64.deb +testequal 'Package: foo +Version: 1.0 +Architecture: amd64' grep -e '^Package:' -e '^Version:' -e '^Architecture:' rootdir/tmp/testsuccess.output +testsuccess aptcache show ./incoming/foo_1.0_amd64.deb +testequal 'Package: foo +Version: 1.0 +Architecture: amd64' grep -e '^Package:' -e '^Version:' -e '^Architecture:' rootdir/tmp/testsuccess.output +testsuccess aptcache show foo:i386 ./incoming/foo_1.0_amd64.deb --with-source ./incoming/foo_1.0_i386.deb +testequal 'Package: foo +Version: 1.0 +Architecture: i386 +Package: foo +Version: 1.0 +Architecture: amd64' grep -e '^Package:' -e '^Version:' -e '^Architecture:' rootdir/tmp/testsuccess.output + testsuccessequal 'Sorting... Full Text Search... foo/local-deb 1.0 amd64 an autogenerated dummy foo=1.0/unstable ' apt search foo --with-source ./incoming/foo_1.0_amd64.deb - -testsuccess aptcache show foo --with-source ./incoming/foo_1.0_amd64.deb -testequal 'Package: foo -Version: 1.0' head -n 2 rootdir/tmp/testsuccess.output testsuccessequal 'foo - an autogenerated dummy foo=1.0/unstable' aptcache search foo --with-source ./incoming/foo_1.0_amd64.deb testdpkgnotinstalled 'foo' 'foo:i386' -- cgit v1.2.3