From 9244f712396c10b674740cc79fdab61c47173d04 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 9 May 2019 22:23:17 +0200 Subject: Introduce apt satisfy and apt-get satisfy Allow to satisfy dependency strings supplied on the command line, optionally prefixed with "Conflicts:" to satisfy them like Conflicts. Build profiles and architecture restriction lists, as used in build dependencies, are supported as well. Compared to build-dep, build-essential is not installed automatically, and installing of recommended packages follows the global default, which defaults to yes. Closes: #275379 See merge request apt-team/apt!63 --- apt-private/private-cmndline.cc | 11 +++--- apt-private/private-source.cc | 77 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 7 deletions(-) (limited to 'apt-private') diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc index 3a25c7131..3f43d6eb1 100644 --- a/apt-private/private-cmndline.cc +++ b/apt-private/private-cmndline.cc @@ -216,14 +216,17 @@ static bool addArgumentsAPTGet(std::vector &Args, char const addArg(0, "tar-only", "APT::Get::Tar-Only", 0); addArg(0, "dsc-only", "APT::Get::Dsc-Only", 0); } - else if (CmdMatches("build-dep")) + else if (CmdMatches("build-dep") || CmdMatches("satisfy")) { addArg('a', "host-architecture", "APT::Get::Host-Architecture", CommandLine::HasArg); addArg('P', "build-profiles", "APT::Build-Profiles", CommandLine::HasArg); addArg(0, "purge", "APT::Get::Purge", 0); addArg(0, "solver", "APT::Solver", CommandLine::HasArg); - addArg(0,"arch-only","APT::Get::Arch-Only",0); - addArg(0,"indep-only","APT::Get::Indep-Only",0); + if (CmdMatches("build-dep")) + { + addArg(0,"arch-only","APT::Get::Arch-Only",0); + addArg(0,"indep-only","APT::Get::Indep-Only",0); + } // this has no effect *but* sbuild is using it (see LP: #1255806) // once sbuild is fixed, this option can be removed addArg('f', "fix-broken", "APT::Get::Fix-Broken", 0); @@ -241,7 +244,7 @@ static bool addArgumentsAPTGet(std::vector &Args, char const if (CmdMatches("install", "reinstall", "remove", "purge", "upgrade", "dist-upgrade", "dselect-upgrade", "autoremove", "auto-remove", "autopurge", "clean", "autoclean", "auto-clean", "check", - "build-dep", "full-upgrade", "source")) + "build-dep", "satisfy", "full-upgrade", "source")) { addArg('s', "simulate", "APT::Get::Simulate", 0); addArg('s', "just-print", "APT::Get::Simulate", 0); diff --git a/apt-private/private-source.cc b/apt-private/private-source.cc index 48c9d8094..bbb14b1d8 100644 --- a/apt-private/private-source.cc +++ b/apt-private/private-source.cc @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -652,8 +653,10 @@ bool DoBuildDep(CommandLine &CmdL) CacheFile Cache; auto VolatileCmdL = GetPseudoPackages(Cache.GetSourceList(), CmdL, AddVolatileSourceFile, pseudoArch); + auto AreDoingSatisfy = strcasecmp(CmdL.FileList[0], "satisfy") == 0; - _config->Set("APT::Install-Recommends", false); + if (not AreDoingSatisfy) + _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")); @@ -661,6 +664,7 @@ bool DoBuildDep(CommandLine &CmdL) std::ostringstream buildDepsPkgFile; std::vector pseudoPkgs; // deal with the build essentials first + if (not AreDoingSatisfy) { std::vector BuildDeps; for (auto && opt: _config->FindVector("APT::Build-Essential")) @@ -678,11 +682,78 @@ bool DoBuildDep(CommandLine &CmdL) pseudoPkgs.emplace_back(pseudo, nativeArch, ""); } + if (AreDoingSatisfy) + { + std::vector BuildDeps; + for (unsigned i = 1; i < CmdL.FileSize(); i++) + { + const char *Start = CmdL.FileList[i]; + const char *Stop = Start + strlen(Start); + auto Type = pkgSrcRecords::Parser::BuildDependIndep; + + // Reject '>' and '<' as operators, as they have strange meanings. + bool insideVersionRestriction = false; + for (auto C = Start; C + 1 != Stop; C++) + { + if (*C == '(') + insideVersionRestriction = true; + else if (*C == ')') + insideVersionRestriction = false; + else if (insideVersionRestriction && (*C == '<' || *C == '>')) + { + if (C[1] != *C && C[1] != '=') + return _error->Error(_("Invalid operator '%c' at offset %d, did you mean '%c%c' or '%c='? - in: %s"), *C, (int)(C - Start), *C, *C, *C, Start); + C++; + } + } + + if (APT::String::Startswith(Start, "Conflicts:")) + { + Type = pkgSrcRecords::Parser::BuildConflictIndep; + Start += strlen("Conflicts:"); + } + while (1) + { + pkgSrcRecords::Parser::BuildDepRec rec; + Start = debListParser::ParseDepends(Start, Stop, + rec.Package, rec.Version, rec.Op, true, false, true, pseudoArch); + + if (Start == 0) + return _error->Error("Problem parsing dependency: %s", CmdL.FileList[i]); + rec.Type = Type; + + // We parsed a package that was ignored (wrong architecture restriction + // or something). + if (rec.Package.empty()) + { + // If we are in an OR group, we need to set the "Or" flag of the + // previous entry to our value. + if (BuildDeps.empty() == false && (BuildDeps[BuildDeps.size() - 1].Op & pkgCache::Dep::Or) == pkgCache::Dep::Or) + { + BuildDeps[BuildDeps.size() - 1].Op &= ~pkgCache::Dep::Or; + BuildDeps[BuildDeps.size() - 1].Op |= (rec.Op & pkgCache::Dep::Or); + } + } + else + { + BuildDeps.emplace_back(std::move(rec)); + } + + if (Start == Stop) + break; + } + } + std::string const pseudo = "command line argument"; + WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch, BuildDeps); + pseudoPkgs.emplace_back(pseudo, pseudoArch, ""); + } + // Read the source list if (Cache.BuildSourceList() == false) return false; pkgSourceList *List = Cache.GetSourceList(); + if (not AreDoingSatisfy) { auto const VolatileSources = List->GetVolatileFiles(); for (auto &&pkg : VolatileCmdL) @@ -713,7 +784,7 @@ bool DoBuildDep(CommandLine &CmdL) } bool const WantLock = _config->FindB("APT::Get::Print-URIs", false) == false; - if (CmdL.FileList[1] != 0) + if (CmdL.FileList[1] != 0 && not AreDoingSatisfy) { if (Cache.BuildCaches(WantLock) == false) return false; @@ -786,7 +857,7 @@ bool DoBuildDep(CommandLine &CmdL) { pkgDepCache::ActionGroup group(Cache); - if (_config->FindB("APT::Get::Build-Dep-Automatic", false) == false) + if (_config->FindB(AreDoingSatisfy ? "APT::Get::Satisfy-Automatic" : "APT::Get::Build-Dep-Automatic", false) == false) { for (auto const &pkg: removeAgain) { -- cgit v1.2.3-18-g5258