Commit 9244f712 authored by Julian Andres Klode's avatar Julian Andres Klode
Browse files

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 !63
parent 35cb34d7
Loading
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -216,14 +216,17 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &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);
      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<CommandLine::Args> &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);
+74 −3
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <apt-private/private-source.h>

#include <apt-pkg/debindexfile.h>
#include <apt-pkg/deblistparser.h>

#include <stddef.h>
#include <stdio.h>
@@ -652,7 +653,9 @@ bool DoBuildDep(CommandLine &CmdL)

   CacheFile Cache;
   auto VolatileCmdL = GetPseudoPackages(Cache.GetSourceList(), CmdL, AddVolatileSourceFile, pseudoArch);
   auto AreDoingSatisfy = strcasecmp(CmdL.FileList[0], "satisfy") == 0;

   if (not AreDoingSatisfy)
      _config->Set("APT::Install-Recommends", false);

   if (CmdL.FileSize() <= 1 && VolatileCmdL.empty())
@@ -661,6 +664,7 @@ bool DoBuildDep(CommandLine &CmdL)
   std::ostringstream buildDepsPkgFile;
   std::vector<PseudoPkg> pseudoPkgs;
   // deal with the build essentials first
   if (not AreDoingSatisfy)
   {
      std::vector<pkgSrcRecords::Parser::BuildDepRec> 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<pkgSrcRecords::Parser::BuildDepRec> 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)
	 {
+1 −0
Original line number Diff line number Diff line
@@ -416,6 +416,7 @@ static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
      {"full-upgrade", &DoDistUpgrade, nullptr},
      {"dselect-upgrade", &DoDSelectUpgrade, _("Follow dselect selections")},
      {"build-dep", &DoBuildDep, _("Configure build-dependencies for source packages")},
      {"satisfy", &DoBuildDep, _("Satisfy dependency strings")},
      {"clean", &DoClean, _("Erase downloaded archive files")},
      {"autoclean", &DoAutoClean, _("Erase old downloaded archive files")},
      {"auto-clean", &DoAutoClean, nullptr},
+1 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
      // misc
      {"edit-sources", &EditSources, _("edit the source information file")},
      {"moo", &DoMoo, nullptr},
      {"satisfy", &DoBuildDep, _("satisfy dependency strings")},

      // for compat with muscle memory
      {"dist-upgrade", &DoDistUpgrade, nullptr},
+13 −0
Original line number Diff line number Diff line
@@ -205,6 +205,19 @@
     option if you want to change that.</para></listitem>
     </varlistentry>

     <varlistentry><term><option>satisfy</option></term>
     <listitem><para><literal>satisfy</literal> causes apt-get to satisfy the given dependency string.s The
     dependency strings may have build profiles and architecture restriction list as in build dependencies. They
     may optionally be prefixed with <literal>"Conflicts: "</literal> to unsatisfy the dependency string. Multiple strings of the same type can be specified.</para>

     <para>Example: <literal>apt-get satisfy "foo" "Conflicts: bar" "baz (&gt;&gt; 1.0) | bar (= 2.0), moo"</literal></para>

     <para>The legacy operator '&lt;/&gt;' is not supported, use '&lt;=/&gt;=' instead.</para>


     </listitem>
     </varlistentry>

     <varlistentry><term><option>check</option></term>
     <listitem><para><literal>check</literal> is a diagnostic tool; it updates the package cache and checks 
     for broken dependencies.</para></listitem>
Loading