X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/5f1b8fadbba7108ba20bd07c7479eb5e5704308e..0b661a5cb3d3f25b47c21b98ddbaeb27985b8279:/apt-private/private-source.cc

diff --git a/apt-private/private-source.cc b/apt-private/private-source.cc
index a2621946a..dd52a8822 100644
--- a/apt-private/private-source.cc
+++ b/apt-private/private-source.cc
@@ -21,6 +21,7 @@
 #include <apt-pkg/srcrecords.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/version.h>
+#include <apt-pkg/policy.h>
 
 #include <apt-private/private-cachefile.h>
 #include <apt-private/private-cacheset.h>
@@ -28,6 +29,8 @@
 #include <apt-private/private-install.h>
 #include <apt-private/private-source.h>
 
+#include <apt-pkg/debindexfile.h>
+
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -36,6 +39,7 @@
 #include <unistd.h>
 
 #include <iostream>
+#include <sstream>
 #include <set>
 #include <string>
 #include <vector>
@@ -43,50 +47,9 @@
 #include <apti18n.h>
 									/*}}}*/
 
-// TryToInstallBuildDep - Try to install a single package		/*{{{*/
-// ---------------------------------------------------------------------
-/* This used to be inlined in DoInstall, but with the advent of regex package
-   name matching it was split out.. */
-static bool TryToInstallBuildDep(pkgCache::PkgIterator Pkg,pkgCacheFile &Cache,
-		  pkgProblemResolver &Fix,bool Remove,bool BrokenFix,
-		  bool AllowFail = true)
-{
-   if (Cache[Pkg].CandidateVer == 0 && Pkg->ProvidesList != 0)
-   {
-      CacheSetHelperAPTGet helper(c1out);
-      helper.showErrors(false);
-      pkgCache::VerIterator Ver = helper.canNotFindNewestVer(Cache, Pkg);
-      if (Ver.end() == false)
-	 Pkg = Ver.ParentPkg();
-      else if (helper.showVirtualPackageErrors(Cache) == false)
-	 return AllowFail;
-   }
-
-   if (_config->FindB("Debug::BuildDeps",false) == true)
-   {
-      if (Remove == true)
-	 std::cout << "  Trying to remove " << Pkg << std::endl;
-      else
-	 std::cout << "  Trying to install " << Pkg << std::endl;
-   }
-
-   if (Remove == true)
-   {
-      TryToRemove RemoveAction(Cache, &Fix);
-      RemoveAction(Pkg.VersionList());
-   } else if (Cache[Pkg].CandidateVer != 0) {
-      TryToInstall InstallAction(Cache, &Fix, BrokenFix);
-      InstallAction(Cache[Pkg].CandidateVerIter(Cache));
-      InstallAction.doAutoInstall();
-   } else
-      return AllowFail;
-
-   return true;
-}
-									/*}}}*/
 // GetReleaseFileForSourceRecord - Return Suite for the given srcrecord	/*{{{*/
 static pkgCache::RlsFileIterator GetReleaseFileForSourceRecord(CacheFile &CacheFile,
-      pkgSourceList *SrcList, pkgSrcRecords::Parser *Parse)
+      pkgSourceList const * const SrcList, pkgSrcRecords::Parser const * const Parse)
 {
    // try to find release
    const pkgIndexFile& CurrentIndexFile = Parse->Index();
@@ -108,13 +71,12 @@ static pkgCache::RlsFileIterator GetReleaseFileForSourceRecord(CacheFile &CacheF
 // FindSrc - Find a source record					/*{{{*/
 static pkgSrcRecords::Parser *FindSrc(const char *Name,
 			       pkgSrcRecords &SrcRecs,std::string &Src,
-			       CacheFile &CacheFile)
+			       CacheFile &Cache)
 {
    std::string VerTag, UserRequestedVerTag;
    std::string ArchTag = "";
    std::string RelTag = _config->Find("APT::Default-Release");
    std::string TmpSrc = Name;
-   pkgDepCache *Cache = CacheFile.GetDepCache();
 
    // extract release
    size_t found = TmpSrc.find_last_of("/");
@@ -144,9 +106,9 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
    bool MatchSrcOnly = _config->FindB("APT::Get::Only-Source");
    pkgCache::PkgIterator Pkg;
    if (ArchTag != "")
-      Pkg = Cache->FindPkg(TmpSrc, ArchTag);
+      Pkg = Cache.GetPkgCache()->FindPkg(TmpSrc, ArchTag);
    else
-      Pkg = Cache->FindPkg(TmpSrc);
+      Pkg = Cache.GetPkgCache()->FindPkg(TmpSrc);
 
    // if we can't find a package but the user qualified with a arch,
    // error out here
@@ -158,7 +120,7 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
       return 0;
    }
 
-   if (MatchSrcOnly == false && Pkg.end() == false) 
+   if (MatchSrcOnly == false && Pkg.end() == false)
    {
       if(VerTag != "" || RelTag != "" || ArchTag != "")
       {
@@ -188,12 +150,12 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
 	    // pick highest version for the arch unless the user wants
 	    // something else
 	    if (ArchTag != "" && VerTag == "" && RelTag == "")
-	       if(Cache->VS().CmpVersion(VerTag, Ver.VerStr()) < 0)
+	       if(Cache.GetPkgCache()->VS->CmpVersion(VerTag, Ver.VerStr()) < 0)
 		  VerTag = Ver.VerStr();
 
 	    // We match against a concrete version (or a part of this version)
 	    if (VerTag.empty() == false &&
-		  (fuzzy == true || Cache->VS().CmpVersion(VerTag, Ver.VerStr()) != 0) && // exact match
+		  (fuzzy == true || Cache.GetPkgCache()->VS->CmpVersion(VerTag, Ver.VerStr()) != 0) && // exact match
 		  (fuzzy == false || strncmp(VerTag.c_str(), Ver.VerStr(), VerTag.size()) != 0)) // fuzzy match
 	       continue;
 
@@ -212,7 +174,7 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
 	       // or we match against a release
 	       if(VerTag.empty() == false ||
 		     (VF.File().Archive() != 0 && VF.File().Archive() == RelTag) ||
-		     (VF.File().Codename() != 0 && VF.File().Codename() == RelTag)) 
+		     (VF.File().Codename() != 0 && VF.File().Codename() == RelTag))
 	       {
 		  // the Version we have is possibly fuzzy or includes binUploads,
 		  // so we use the Version of the SourcePkg (empty if same as package)
@@ -226,12 +188,12 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
 	 }
       }
 
-      if (Src == "" && ArchTag != "")
+      if (Src.empty() == true && ArchTag.empty() == false)
       {
-	 if (VerTag != "")
+	 if (VerTag.empty() == false)
 	    _error->Error(_("Can not find a package '%s' with version '%s'"),
 		  Pkg.FullName().c_str(), VerTag.c_str());
-	 if (RelTag != "")
+	 if (RelTag.empty() == false)
 	    _error->Error(_("Can not find a package '%s' with release '%s'"),
 		  Pkg.FullName().c_str(), RelTag.c_str());
 	 Src = Name;
@@ -245,7 +207,15 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
 	 // choose a good candidate and proceed with that.
 	 // Maybe we will find a source later on with the right VerTag
 	 // or RelTag
-	 pkgCache::VerIterator const Ver = Cache->GetCandidateVersion(Pkg);
+	 if (Cache.BuildPolicy() == false)
+	    return nullptr;
+	 pkgPolicy * Policy = dynamic_cast<pkgPolicy*>(Cache.GetPolicy());
+	 if (Policy == nullptr)
+	 {
+	    _error->Fatal("Implementation error: dynamic up-casting policy engine failed in FindSrc!");
+	    return nullptr;
+	 }
+	 pkgCache::VerIterator const Ver = Policy->GetCandidateVer(Pkg);
 	 if (Ver.end() == false)
 	 {
 	    if (strcmp(Ver.SourcePkgName(),Ver.ParentPkg().Name()) != 0)
@@ -277,39 +247,37 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
    pkgSrcRecords::Parser *Last = 0;
    unsigned long Offset = 0;
    std::string Version;
-   pkgSourceList *SrcList = CacheFile.GetSourceList();
+   pkgSourceList const * const SrcList = Cache.GetSourceList();
 
    /* Iterate over all of the hits, which includes the resulting
       binary packages in the search */
 	       pkgSrcRecords::Parser *Parse;
-	       while (true) 
+	       while (true)
 	       {
 		  SrcRecs.Restart();
-		  while ((Parse = SrcRecs.Find(Src.c_str(), MatchSrcOnly)) != 0) 
+		  while ((Parse = SrcRecs.Find(Src.c_str(), MatchSrcOnly)) != 0)
 		  {
 		     const std::string Ver = Parse->Version();
-		     bool CorrectRelTag = false;
 
 		     // See if we need to look for a specific release tag
-		     if (RelTag != "" && UserRequestedVerTag == "")
+		     if (RelTag.empty() == false && UserRequestedVerTag.empty() == true)
 		     {
-			pkgCache::RlsFileIterator const Rls = GetReleaseFileForSourceRecord(CacheFile, SrcList, Parse);
+			pkgCache::RlsFileIterator const Rls = GetReleaseFileForSourceRecord(Cache, SrcList, Parse);
 			if (Rls.end() == false)
 			{
-			   if ((Rls->Archive != 0 && RelTag == Rls.Archive()) ||
-				 (Rls->Codename != 0 && RelTag == Rls.Codename()))
-			      CorrectRelTag = true;
+			   if ((Rls->Archive != 0 && RelTag != Rls.Archive()) &&
+				 (Rls->Codename != 0 && RelTag != Rls.Codename()))
+			      continue;
 			}
-		     } else
-			CorrectRelTag = true;
+		     }
 
 		     // Ignore all versions which doesn't fit
 		     if (VerTag.empty() == false &&
-			   Cache->VS().CmpVersion(VerTag, Ver) != 0) // exact match
+			   Cache.GetPkgCache()->VS->CmpVersion(VerTag, Ver) != 0) // exact match
 			continue;
 
 		     // Newer version or an exact match? Save the hit
-		     if (CorrectRelTag && (Last == 0 || Cache->VS().CmpVersion(Version,Ver) < 0)) {
+		     if (Last == 0 || Cache.GetPkgCache()->VS->CmpVersion(Version,Ver) < 0) {
 			Last = Parse;
 			Offset = Parse->Offset();
 			Version = Ver;
@@ -321,7 +289,7 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
 			break;
 		  }
 		  if (UserRequestedVerTag == "" && Version != "" && RelTag != "")
-		     ioprintf(c1out, "Selected version '%s' (%s) for %s\n", 
+		     ioprintf(c1out, "Selected version '%s' (%s) for %s\n",
 			   Version.c_str(), RelTag.c_str(), Src.c_str());
 
 		  if (Last != 0 || VerTag.empty() == true)
@@ -347,19 +315,15 @@ struct DscFile
 };
 bool DoSource(CommandLine &CmdL)
 {
-   CacheFile Cache;
-   if (Cache.Open(false) == false)
-      return false;
-
    if (CmdL.FileSize() <= 1)
       return _error->Error(_("Must specify at least one package to fetch source for"));
 
-   // Read the source list
-   if (Cache.BuildSourceList() == false)
+   CacheFile Cache;
+   if (Cache.BuildCaches(false) == false)
       return false;
-   pkgSourceList *List = Cache.GetSourceList();
 
    // Create the text record parsers
+   pkgSourceList * const List = Cache.GetSourceList();
    pkgSrcRecords SrcRecs(*List);
    if (_error->PendingError() == true)
       return false;
@@ -514,8 +478,8 @@ bool DoSource(CommandLine &CmdL)
    {
       pkgAcquire::UriIterator I = Fetcher.UriBegin();
       for (; I != Fetcher.UriEnd(); ++I)
-	 std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << 
-	    I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl;
+	 std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' <<
+	    std::to_string(I->Owner->FileSize) << ' ' << I->Owner->HashSum() << std::endl;
       return true;
    }
 
@@ -544,7 +508,7 @@ bool DoSource(CommandLine &CmdL)
       bool const fixBroken = _config->FindB("APT::Get::Fix-Broken", false);
       for (unsigned I = 0; I != J; ++I)
       {
-	 std::string Dir = Dsc[I].Package + '-' + Cache->VS().UpstreamVersion(Dsc[I].Version.c_str());
+	 std::string Dir = Dsc[I].Package + '-' + Cache.GetPkgCache()->VS->UpstreamVersion(Dsc[I].Version.c_str());
 
 	 // Diff only mode only fetches .diff files
 	 if (_config->FindB("APT::Get::Diff-Only",false) == true ||
@@ -611,306 +575,6 @@ bool DoSource(CommandLine &CmdL)
    return ExecWait(Process, "dpkg-source");
 }
 									/*}}}*/
-// InstallBuildDepsLoop							/*{{{*/
-static bool InstallBuildDepsLoop(CacheFile &Cache, std::string const &Src,
-      std::vector<pkgSrcRecords::Parser::BuildDepRec> const &BuildDeps,
-      bool const StripMultiArch, std::string const &hostArch)
-{
-   // Install the requested packages
-   std::vector <pkgSrcRecords::Parser::BuildDepRec>::const_iterator D;
-   pkgProblemResolver Fix(Cache);
-   bool skipAlternatives = false; // skip remaining alternatives in an or group
-   for (D = BuildDeps.begin(); D != BuildDeps.end(); ++D)
-   {
-      bool hasAlternatives = (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or);
-
-      if (skipAlternatives == true)
-      {
-	 /*
-	  * if there are alternatives, we've already picked one, so skip
-	  * the rest
-	  *
-	  * TODO: this means that if there's a build-dep on A|B and B is
-	  * installed, we'll still try to install A; more importantly,
-	  * if A is currently broken, we cannot go back and try B. To fix
-	  * this would require we do a Resolve cycle for each package we
-	  * add to the install list. Ugh
-	  */
-	 if (!hasAlternatives)
-	    skipAlternatives = false; // end of or group
-	 continue;
-      }
-
-      if ((*D).Type == pkgSrcRecords::Parser::BuildConflict ||
-	    (*D).Type == pkgSrcRecords::Parser::BuildConflictIndep)
-      {
-	 pkgCache::GrpIterator Grp = Cache->FindGrp((*D).Package);
-	 // Build-conflicts on unknown packages are silently ignored
-	 if (Grp.end() == true)
-	    continue;
-
-	 for (pkgCache::PkgIterator Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
-	 {
-	    pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
-	    /*
-	     * Remove if we have an installed version that satisfies the
-	     * version criteria
-	     */
-	    if (IV.end() == false &&
-		  Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
-	       TryToInstallBuildDep(Pkg,Cache,Fix,true,false);
-	 }
-      }
-      else // BuildDep || BuildDepIndep
-      {
-	 if (_config->FindB("Debug::BuildDeps",false) == true)
-	    std::cout << "Looking for " << (*D).Package << "...\n";
-
-	 pkgCache::PkgIterator Pkg;
-
-	 // Cross-Building?
-	 if (StripMultiArch == false && D->Type != pkgSrcRecords::Parser::BuildDependIndep)
-	 {
-	    size_t const colon = D->Package.find(":");
-	    if (colon != std::string::npos)
-	    {
-	       if (strcmp(D->Package.c_str() + colon, ":any") == 0 || strcmp(D->Package.c_str() + colon, ":native") == 0)
-		  Pkg = Cache->FindPkg(D->Package.substr(0,colon));
-	       else
-		  Pkg = Cache->FindPkg(D->Package);
-	    }
-	    else
-	       Pkg = Cache->FindPkg(D->Package, hostArch);
-
-	    // a bad version either is invalid or doesn't satify dependency
-#define BADVER(Ver) (Ver.end() == true || \
-      (D->Version.empty() == false && \
-       Cache->VS().CheckDep(Ver.VerStr(),D->Op,D->Version.c_str()) == false))
-
-	    APT::VersionList verlist;
-	    if (Pkg.end() == false)
-	    {
-	       pkgCache::VerIterator Ver = (*Cache)[Pkg].InstVerIter(*Cache);
-	       if (BADVER(Ver) == false)
-		  verlist.insert(Ver);
-	       Ver = (*Cache)[Pkg].CandidateVerIter(*Cache);
-	       if (BADVER(Ver) == false)
-		  verlist.insert(Ver);
-	    }
-	    if (verlist.empty() == true)
-	    {
-	       pkgCache::PkgIterator BuildPkg = Cache->FindPkg(D->Package, "native");
-	       if (BuildPkg.end() == false && Pkg != BuildPkg)
-	       {
-		  pkgCache::VerIterator Ver = (*Cache)[BuildPkg].InstVerIter(*Cache);
-		  if (BADVER(Ver) == false)
-		     verlist.insert(Ver);
-		  Ver = (*Cache)[BuildPkg].CandidateVerIter(*Cache);
-		  if (BADVER(Ver) == false)
-		     verlist.insert(Ver);
-	       }
-	    }
-#undef BADVER
-
-	    std::string forbidden;
-	    // We need to decide if host or build arch, so find a version we can look at
-	    APT::VersionList::const_iterator Ver = verlist.begin();
-	    for (; Ver != verlist.end(); ++Ver)
-	    {
-	       forbidden.clear();
-	       if (Ver->MultiArch == pkgCache::Version::No || Ver->MultiArch == pkgCache::Version::All)
-	       {
-		  if (colon == std::string::npos)
-		     Pkg = Ver.ParentPkg().Group().FindPkg(hostArch);
-		  else if (strcmp(D->Package.c_str() + colon, ":any") == 0)
-		     forbidden = "Multi-Arch: no";
-		  else if (strcmp(D->Package.c_str() + colon, ":native") == 0)
-		     Pkg = Ver.ParentPkg().Group().FindPkg("native");
-	       }
-	       else if (Ver->MultiArch == pkgCache::Version::Same)
-	       {
-		  if (colon == std::string::npos)
-		     Pkg = Ver.ParentPkg().Group().FindPkg(hostArch);
-		  else if (strcmp(D->Package.c_str() + colon, ":any") == 0)
-		     forbidden = "Multi-Arch: same";
-		  else if (strcmp(D->Package.c_str() + colon, ":native") == 0)
-		     Pkg = Ver.ParentPkg().Group().FindPkg("native");
-	       }
-	       else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
-	       {
-		  if (colon == std::string::npos)
-		     Pkg = Ver.ParentPkg().Group().FindPkg("native");
-		  else if (strcmp(D->Package.c_str() + colon, ":any") == 0 ||
-			strcmp(D->Package.c_str() + colon, ":native") == 0)
-		     forbidden = "Multi-Arch: foreign";
-	       }
-	       else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
-	       {
-		  if (colon == std::string::npos)
-		     Pkg = Ver.ParentPkg().Group().FindPkg(hostArch);
-		  else if (strcmp(D->Package.c_str() + colon, ":any") == 0)
-		  {
-		     // prefer any installed over preferred non-installed architectures
-		     pkgCache::GrpIterator Grp = Ver.ParentPkg().Group();
-		     // we don't check for version here as we are better of with upgrading than remove and install
-		     for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
-			if (Pkg.CurrentVer().end() == false)
-			   break;
-		     if (Pkg.end() == true)
-			Pkg = Grp.FindPreferredPkg(true);
-		  }
-		  else if (strcmp(D->Package.c_str() + colon, ":native") == 0)
-		     Pkg = Ver.ParentPkg().Group().FindPkg("native");
-	       }
-
-	       if (forbidden.empty() == false)
-	       {
-		  if (_config->FindB("Debug::BuildDeps",false) == true)
-		     std::cout << D->Package.substr(colon, std::string::npos) << " is not allowed from " << forbidden << " package " << (*D).Package << " (" << Ver.VerStr() << ")" << std::endl;
-		  continue;
-	       }
-
-	       //we found a good version
-	       break;
-	    }
-	    if (Ver == verlist.end())
-	    {
-	       if (_config->FindB("Debug::BuildDeps",false) == true)
-		  std::cout << " No multiarch info as we have no satisfying installed nor candidate for " << D->Package << " on build or host arch" << std::endl;
-
-	       if (forbidden.empty() == false)
-	       {
-		  if (hasAlternatives)
-		     continue;
-		  return _error->Error(_("%s dependency for %s can't be satisfied "
-			   "because %s is not allowed on '%s' packages"),
-			pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(),
-			D->Package.c_str(), forbidden.c_str());
-	       }
-	    }
-	 }
-	 else
-	    Pkg = Cache->FindPkg(D->Package);
-
-	 if (Pkg.end() == true || (Pkg->VersionList == 0 && Pkg->ProvidesList == 0))
-	 {
-	    if (_config->FindB("Debug::BuildDeps",false) == true)
-	       std::cout << " (not found)" << (*D).Package << std::endl;
-
-	    if (hasAlternatives)
-	       continue;
-
-	    return _error->Error(_("%s dependency for %s cannot be satisfied "
-		     "because the package %s cannot be found"),
-		  pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(),
-		  (*D).Package.c_str());
-	 }
-
-	 pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
-	 if (IV.end() == false)
-	 {
-	    if (_config->FindB("Debug::BuildDeps",false) == true)
-	       std::cout << "  Is installed\n";
-
-	    if (D->Version.empty() == true ||
-		  Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
-	    {
-	       skipAlternatives = hasAlternatives;
-	       continue;
-	    }
-
-	    if (_config->FindB("Debug::BuildDeps",false) == true)
-	       std::cout << "    ...but the installed version doesn't meet the version requirement\n";
-
-	    if (((*D).Op & pkgCache::Dep::LessEq) == pkgCache::Dep::LessEq)
-	       return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"),
-		     pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(), Pkg.FullName(true).c_str());
-	 }
-
-	 // Only consider virtual packages if there is no versioned dependency
-	 if ((*D).Version.empty() == true)
-	 {
-	    /*
-	     * If this is a virtual package, we need to check the list of
-	     * packages that provide it and see if any of those are
-	     * installed
-	     */
-	    pkgCache::PrvIterator Prv = Pkg.ProvidesList();
-	    for (; Prv.end() != true; ++Prv)
-	    {
-	       if (_config->FindB("Debug::BuildDeps",false) == true)
-		  std::cout << "  Checking provider " << Prv.OwnerPkg().FullName() << std::endl;
-
-	       if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
-		  break;
-	    }
-
-	    if (Prv.end() == false)
-	    {
-	       if (_config->FindB("Debug::BuildDeps",false) == true)
-		  std::cout << "  Is provided by installed package " << Prv.OwnerPkg().FullName() << std::endl;
-	       skipAlternatives = hasAlternatives;
-	       continue;
-	    }
-	 }
-	 else // versioned dependency
-	 {
-	    pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
-	    if (CV.end() == true ||
-		  Cache->VS().CheckDep(CV.VerStr(),(*D).Op,(*D).Version.c_str()) == false)
-	    {
-	       if (hasAlternatives)
-		  continue;
-	       else if (CV.end() == false)
-		  return _error->Error(_("%s dependency for %s cannot be satisfied "
-			   "because candidate version of package %s "
-			   "can't satisfy version requirements"),
-			pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(),
-			D->Package.c_str());
-	       else
-		  return _error->Error(_("%s dependency for %s cannot be satisfied "
-			   "because package %s has no candidate version"),
-			pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(),
-			D->Package.c_str());
-	    }
-	 }
-
-	 if (TryToInstallBuildDep(Pkg,Cache,Fix,false,false,false) == true)
-	 {
-	    // We successfully installed something; skip remaining alternatives
-	    skipAlternatives = hasAlternatives;
-	    if(_config->FindB("APT::Get::Build-Dep-Automatic", false) == true)
-	       Cache->MarkAuto(Pkg, true);
-	    continue;
-	 }
-	 else if (hasAlternatives)
-	 {
-	    if (_config->FindB("Debug::BuildDeps",false) == true)
-	       std::cout << "  Unsatisfiable, trying alternatives\n";
-	    continue;
-	 }
-	 else
-	 {
-	    return _error->Error(_("Failed to satisfy %s dependency for %s: %s"),
-		  pkgSrcRecords::Parser::BuildDepType(D->Type),
-		  Src.c_str(),
-		  (*D).Package.c_str());
-	 }
-      }
-   }
-
-   if (Fix.Resolve(true) == false)
-      _error->Discard();
-
-   // Now we check the state of the packages,
-   if (Cache->BrokenCount() != 0)
-   {
-      ShowBroken(std::cout, Cache, false);
-      return _error->Error(_("Build-dependencies for %s could not be satisfied."), Src.c_str());
-   }
-   return true;
-}
-									/*}}}*/
 // DoBuildDep - Install/removes packages to satisfy build dependencies  /*{{{*/
 // ---------------------------------------------------------------------
 /* This function will look at the build depends list of the given source 
@@ -943,6 +607,39 @@ static std::vector<pkgSrcRecords::Parser::BuildDepRec> GetBuildDeps(pkgSrcRecord
 
    return BuildDeps;
 }
+static void WriteBuildDependencyPackage(std::ostringstream &buildDepsPkgFile,
+      std::string const &PkgName, std::string const &Arch,
+      std::vector<pkgSrcRecords::Parser::BuildDepRec> const &Dependencies)
+{
+   buildDepsPkgFile << "Package: " << PkgName << "\n"
+      << "Architecture: " << Arch << "\n"
+      << "Version: 1\n";
+
+   std::string depends, conflicts;
+   for (auto const &dep: Dependencies)
+   {
+      std::string * type;
+      if (dep.Type == pkgSrcRecords::Parser::BuildConflict || dep.Type == pkgSrcRecords::Parser::BuildConflictIndep)
+	 type = &conflicts;
+      else
+	 type = &depends;
+
+      type->append(" ").append(dep.Package);
+      if (dep.Version.empty() ==  false)
+	 type->append(" (").append(pkgCache::CompTypeDeb(dep.Op)).append(" ").append(dep.Version).append(")");
+      if ((dep.Op & pkgCache::Dep::Or) == pkgCache::Dep::Or)
+      {
+	 type->append("\n  |");
+      }
+      else
+	 type->append(",\n");
+   }
+   if (depends.empty() == false)
+      buildDepsPkgFile << "Depends:\n" << depends;
+   if (conflicts.empty() == false)
+      buildDepsPkgFile << "Conflicts:\n" << conflicts;
+   buildDepsPkgFile << "\n";
+}
 bool DoBuildDep(CommandLine &CmdL)
 {
    CacheFile Cache;
@@ -951,24 +648,9 @@ bool DoBuildDep(CommandLine &CmdL)
 
    _config->Set("APT::Install-Recommends", false);
 
-   bool WantLock = _config->FindB("APT::Get::Print-URIs", false) == false;
-
-   if (Cache.Open(WantLock) == false)
-      return false;
-
    if (CmdL.FileSize() <= 1 && VolatileCmdL.empty())
       return _error->Error(_("Must specify at least one package to check builddeps for"));
 
-   // Read the source list
-   if (Cache.BuildSourceList() == false)
-      return false;
-   pkgSourceList *List = Cache.GetSourceList();
-
-   // Create the text record parsers
-   pkgSrcRecords SrcRecs(*List);
-   if (_error->PendingError() == true)
-      return false;
-
    bool StripMultiArch;
    std::string hostArch = _config->Find("APT::Get::Host-Architecture");
    if (hostArch.empty() == false)
@@ -981,10 +663,11 @@ bool DoBuildDep(CommandLine &CmdL)
    else
       StripMultiArch = true;
 
+   std::ostringstream buildDepsPkgFile;
+   std::vector<std::pair<std::string,std::string>> pseudoPkgs;
    // deal with the build essentials first
    {
       std::vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
-
       Configuration::Item const *Opts = _config->Tree("APT::Build-Essential");
       if (Opts)
 	 Opts = Opts->Child;
@@ -999,11 +682,18 @@ bool DoBuildDep(CommandLine &CmdL)
 	 rec.Op = 0;
 	 BuildDeps.push_back(rec);
       }
-
-      if (InstallBuildDepsLoop(Cache, "APT::Build-Essential", BuildDeps, StripMultiArch, hostArch) == false)
-	 return false;
+      std::string const pseudo = "builddeps:essentials";
+      std::string const nativeArch = _config->Find("APT::Architecture");
+      WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, nativeArch, BuildDeps);
+      pseudoPkgs.emplace_back(pseudo, nativeArch);
    }
 
+   // Read the source list
+   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();
@@ -1020,27 +710,101 @@ bool DoBuildDep(CommandLine &CmdL)
 	    if (Last == nullptr)
 	       return _error->Error(_("Unable to find a source package for %s"), Src);
 
-	    auto const BuildDeps = GetBuildDeps(Last.get(), Src, StripMultiArch, hostArch);
-	    if (InstallBuildDepsLoop(Cache, Src, BuildDeps, StripMultiArch, hostArch) == false)
-	       return false;
+	    std::string const pseudo = std::string("builddeps:") + Src;
+	    WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch,
+		  GetBuildDeps(Last.get(), Src, StripMultiArch, hostArch));
+	    pseudoPkgs.emplace_back(pseudo, pseudoArch);
 	 }
       }
       else
-	 _error->Error("Implementation error: Volatile sources (%lu) and commandline elements (%lu) do not match!", VolatileSources.size(), VolatileCmdL.size());
+	 return _error->Error("Implementation error: Volatile sources (%lu) and"
+	       "commandline elements (%lu) do not match!", VolatileSources.size(),
+	       VolatileCmdL.size());
    }
 
-   for (const char **I = CmdL.FileList + 1; *I != 0; ++I)
+   bool const WantLock = _config->FindB("APT::Get::Print-URIs", false) == false;
+   if (CmdL.FileList[1] != 0)
    {
-      std::string Src;
-      pkgSrcRecords::Parser * const Last = FindSrc(*I,SrcRecs,Src,Cache);
-      if (Last == nullptr)
-	 return _error->Error(_("Unable to find a source package for %s"), *I);
+      if (Cache.BuildCaches(WantLock) == false)
+	 return false;
+      // Create the text record parsers
+      pkgSrcRecords SrcRecs(*List);
+      if (_error->PendingError() == true)
+	 return false;
+      for (const char **I = CmdL.FileList + 1; *I != 0; ++I)
+      {
+	 std::string Src;
+	 pkgSrcRecords::Parser * const Last = FindSrc(*I,SrcRecs,Src,Cache);
+	 if (Last == nullptr)
+	    return _error->Error(_("Unable to find a source package for %s"), *I);
+
+	 std::string const pseudo = std::string("builddeps:") + Src;
+	 WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch,
+	       GetBuildDeps(Last, Src.c_str(), StripMultiArch, hostArch));
+	 pseudoPkgs.emplace_back(pseudo, pseudoArch);
+      }
+   }
+
+   Cache.AddIndexFile(new debStringPackageIndex(buildDepsPkgFile.str()));
+
+   if (Cache.Open(WantLock) == false)
+      return false;
+   pkgProblemResolver Fix(Cache.GetDepCache());
+
+   APT::PackageVector removeAgain;
+   {
+      pkgDepCache::ActionGroup group(Cache);
+      TryToInstall InstallAction(Cache, &Fix, false);
+      for (auto const &pkg: pseudoPkgs)
+      {
+	 pkgCache::PkgIterator const Pkg = Cache->FindPkg(pkg.first, pkg.second);
+	 if (Pkg.end())
+	    continue;
+	 Cache->SetCandidateVersion(Pkg.VersionList());
+	 InstallAction(Cache[Pkg].CandidateVerIter(Cache));
+	 removeAgain.push_back(Pkg);
+      }
+      InstallAction.doAutoInstall();
 
-      auto const BuildDeps = GetBuildDeps(Last, Src.c_str(), StripMultiArch, hostArch);
-      if (InstallBuildDepsLoop(Cache, Src, BuildDeps, StripMultiArch, hostArch) == false)
+      OpTextProgress Progress(*_config);
+      bool const resolver_fail = Fix.Resolve(true, &Progress);
+      if (resolver_fail == false && Cache->BrokenCount() == 0)
+	 return false;
+      if (CheckNothingBroken(Cache) == false)
 	 return false;
    }
+   if (DoAutomaticRemove(Cache) == false)
+      return false;
+
+   {
+      pkgDepCache::ActionGroup group(Cache);
+      if (_config->FindB("APT::Get::Build-Dep-Automatic", false) == false)
+      {
+	 for (auto const &pkg: removeAgain)
+	 {
+	    auto const instVer = Cache[pkg].InstVerIter(Cache);
+	    if (unlikely(instVer.end() == true))
+	       continue;
+	    for (auto D = instVer.DependsList(); D.end() != true; ++D)
+	    {
+	       if (D->Type != pkgCache::Dep::Depends || D.IsMultiArchImplicit())
+		  continue;
+	       APT::VersionList verlist = APT::VersionList::FromDependency(Cache, D, APT::CacheSetHelper::CANDIDATE);
+	       for (auto const &V : verlist)
+	       {
+		  auto const P = V.ParentPkg();
+		  if (Cache[P].InstallVer != V)
+		     continue;
+		  Cache->MarkAuto(P, false);
+	       }
+	    }
+	 }
+      }
+      for (auto const &pkg: removeAgain)
+	 Cache->MarkDelete(pkg, false, 0, true);
+   }
 
+   pseudoPkgs.clear();
    if (_error->PendingError() || InstallPackages(Cache, false, true) == false)
       return _error->Error(_("Failed to process build dependencies"));
    return true;