apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

private-source.cc
Go to the documentation of this file.
1 // Include Files /*{{{*/
2 #include <config.h>
3 
4 #include <apt-pkg/acquire-item.h>
5 #include <apt-pkg/acquire.h>
6 #include <apt-pkg/algorithms.h>
8 #include <apt-pkg/cachefile.h>
9 #include <apt-pkg/cacheset.h>
10 #include <apt-pkg/cmndline.h>
11 #include <apt-pkg/configuration.h>
12 #include <apt-pkg/depcache.h>
13 #include <apt-pkg/error.h>
14 #include <apt-pkg/fileutl.h>
15 #include <apt-pkg/hashes.h>
16 #include <apt-pkg/indexfile.h>
17 #include <apt-pkg/metaindex.h>
18 #include <apt-pkg/pkgcache.h>
19 #include <apt-pkg/policy.h>
20 #include <apt-pkg/sourcelist.h>
21 #include <apt-pkg/srcrecords.h>
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/version.h>
24 
30 
31 #include <apt-pkg/debindexfile.h>
32 #include <apt-pkg/deblistparser.h>
33 
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 
41 #include <iostream>
42 #include <set>
43 #include <sstream>
44 #include <string>
45 #include <vector>
46 
47 #include <apti18n.h>
48  /*}}}*/
49 
50 // GetReleaseFileForSourceRecord - Return Suite for the given srcrecord /*{{{*/
52  pkgSourceList const * const SrcList, pkgSrcRecords::Parser const * const Parse)
53 {
54  // try to find release
55  const pkgIndexFile& CurrentIndexFile = Parse->Index();
56 
57  for (pkgSourceList::const_iterator S = SrcList->begin();
58  S != SrcList->end(); ++S)
59  {
60  std::vector<pkgIndexFile *> *Indexes = (*S)->GetIndexFiles();
61  for (std::vector<pkgIndexFile *>::const_iterator IF = Indexes->begin();
62  IF != Indexes->end(); ++IF)
63  {
64  if (&CurrentIndexFile == (*IF))
65  return (*S)->FindInCache(CacheFile, false);
66  }
67  }
69 }
70  /*}}}*/
71 // FindSrc - Find a source record /*{{{*/
72 static pkgSrcRecords::Parser *FindSrc(const char *Name,
73  pkgSrcRecords &SrcRecs,std::string &Src,
74  CacheFile &Cache)
75 {
76  std::string VerTag, UserRequestedVerTag;
77  std::string ArchTag = "";
78  std::string RelTag = _config->Find("APT::Default-Release");
79  std::string TmpSrc = Name;
80 
81  // extract release
82  size_t found = TmpSrc.find_last_of("/");
83  if (found != std::string::npos)
84  {
85  RelTag = TmpSrc.substr(found+1);
86  TmpSrc = TmpSrc.substr(0,found);
87  }
88  // extract the version
89  found = TmpSrc.find_last_of("=");
90  if (found != std::string::npos)
91  {
92  VerTag = UserRequestedVerTag = TmpSrc.substr(found+1);
93  TmpSrc = TmpSrc.substr(0,found);
94  }
95  // extract arch
96  found = TmpSrc.find_last_of(":");
97  if (found != std::string::npos)
98  {
99  ArchTag = TmpSrc.substr(found+1);
100  TmpSrc = TmpSrc.substr(0,found);
101  }
102 
103  /* Lookup the version of the package we would install if we were to
104  install a version and determine the source package name, then look
105  in the archive for a source package of the same name. */
106  bool MatchSrcOnly = _config->FindB("APT::Get::Only-Source");
108  if (ArchTag != "")
109  Pkg = Cache.GetPkgCache()->FindPkg(TmpSrc, ArchTag);
110  else
111  Pkg = Cache.GetPkgCache()->FindPkg(TmpSrc);
112 
113  // if we can't find a package but the user qualified with a arch,
114  // error out here
115  if (Pkg.end() && ArchTag != "")
116  {
117  Src = Name;
118  _error->Error(_("Can not find a package for architecture '%s'"),
119  ArchTag.c_str());
120  return 0;
121  }
122 
123  if (MatchSrcOnly == false && Pkg.end() == false)
124  {
125  if(VerTag != "" || RelTag != "" || ArchTag != "")
126  {
127  bool fuzzy = false;
128  // we have a default release, try to locate the pkg. we do it like
129  // this because GetCandidateVer() will not "downgrade", that means
130  // "apt-get source -t stable apt" won't work on a unstable system
131  for (pkgCache::VerIterator Ver = Pkg.VersionList();; ++Ver)
132  {
133  // try first only exact matches, later fuzzy matches
134  if (Ver.end() == true)
135  {
136  if (fuzzy == true)
137  break;
138  fuzzy = true;
139  Ver = Pkg.VersionList();
140  // exit right away from the Pkg.VersionList() loop if we
141  // don't have any versions
142  if (Ver.end() == true)
143  break;
144  }
145 
146  // ignore arches that are not for us
147  if (ArchTag != "" && Ver.Arch() != ArchTag)
148  continue;
149 
150  // pick highest version for the arch unless the user wants
151  // something else
152  if (ArchTag != "" && VerTag == "" && RelTag == "")
153  if(Cache.GetPkgCache()->VS->CmpVersion(VerTag, Ver.VerStr()) < 0)
154  VerTag = Ver.VerStr();
155 
156  // We match against a concrete version (or a part of this version)
157  if (VerTag.empty() == false &&
158  (fuzzy == true || Cache.GetPkgCache()->VS->CmpVersion(VerTag, Ver.VerStr()) != 0) && // exact match
159  (fuzzy == false || strncmp(VerTag.c_str(), Ver.VerStr(), VerTag.size()) != 0)) // fuzzy match
160  continue;
161 
162  for (pkgCache::VerFileIterator VF = Ver.FileList();
163  VF.end() == false; ++VF)
164  {
165  /* If this is the status file, and the current version is not the
166  version in the status file (ie it is not installed, or somesuch)
167  then it is not a candidate for installation, ever. This weeds
168  out bogus entries that may be due to config-file states, or
169  other. */
170  if ((VF.File()->Flags & pkgCache::Flag::NotSource) ==
171  pkgCache::Flag::NotSource && Pkg.CurrentVer() != Ver)
172  continue;
173 
174  // or we match against a release
175  if(VerTag.empty() == false ||
176  (VF.File().Archive() != 0 && VF.File().Archive() == RelTag) ||
177  (VF.File().Codename() != 0 && VF.File().Codename() == RelTag))
178  {
179  // the Version we have is possibly fuzzy or includes binUploads,
180  // so we use the Version of the SourcePkg (empty if same as package)
181  Src = Ver.SourcePkgName();
182  VerTag = Ver.SourceVerStr();
183  break;
184  }
185  }
186  if (Src.empty() == false)
187  break;
188  }
189  }
190 
191  if (Src.empty() == true && ArchTag.empty() == false)
192  {
193  if (VerTag.empty() == false)
194  _error->Error(_("Can not find a package '%s' with version '%s'"),
195  Pkg.FullName().c_str(), VerTag.c_str());
196  if (RelTag.empty() == false)
197  _error->Error(_("Can not find a package '%s' with release '%s'"),
198  Pkg.FullName().c_str(), RelTag.c_str());
199  Src = Name;
200  return 0;
201  }
202 
203 
204  if (Src.empty() == true)
205  {
206  // if we don't have found a fitting package yet so we will
207  // choose a good candidate and proceed with that.
208  // Maybe we will find a source later on with the right VerTag
209  // or RelTag
210  if (Cache.BuildPolicy() == false)
211  return nullptr;
212  pkgPolicy * const Policy = Cache.GetPolicy();
213  pkgCache::VerIterator const Ver = Policy->GetCandidateVer(Pkg);
214  if (Ver.end() == false)
215  {
216  if (strcmp(Ver.SourcePkgName(),Ver.ParentPkg().Name()) != 0)
217  Src = Ver.SourcePkgName();
218  if (VerTag.empty() == true && strcmp(Ver.SourceVerStr(),Ver.VerStr()) != 0)
219  VerTag = Ver.SourceVerStr();
220  }
221  }
222  }
223 
224  if (Src.empty() == true)
225  {
226  Src = TmpSrc;
227  }
228  else
229  {
230  /* if we have a source pkg name, make sure to only search
231  for srcpkg names, otherwise apt gets confused if there
232  is a binary package "pkg1" and a source package "pkg1"
233  with the same name but that comes from different packages */
234  MatchSrcOnly = true;
235  if (Src != TmpSrc)
236  {
237  ioprintf(c1out, _("Picking '%s' as source package instead of '%s'\n"), Src.c_str(), TmpSrc.c_str());
238  }
239  }
240 
241  // The best hit
242  pkgSrcRecords::Parser *Last = 0;
243  unsigned long Offset = 0;
244  std::string Version;
245  pkgSourceList const * const SrcList = Cache.GetSourceList();
246 
247  /* Iterate over all of the hits, which includes the resulting
248  binary packages in the search */
249  pkgSrcRecords::Parser *Parse;
250  while (true)
251  {
252  SrcRecs.Restart();
253  while ((Parse = SrcRecs.Find(Src.c_str(), MatchSrcOnly)) != 0)
254  {
255  const std::string Ver = Parse->Version();
256 
257  // See if we need to look for a specific release tag
258  if (RelTag.empty() == false && UserRequestedVerTag.empty() == true)
259  {
260  pkgCache::RlsFileIterator const Rls = GetReleaseFileForSourceRecord(Cache, SrcList, Parse);
261  if (Rls.end() == false)
262  {
263  if ((Rls->Archive != 0 && RelTag != Rls.Archive()) &&
264  (Rls->Codename != 0 && RelTag != Rls.Codename()))
265  continue;
266  }
267  }
268 
269  // Ignore all versions which doesn't fit
270  if (VerTag.empty() == false &&
271  Cache.GetPkgCache()->VS->CmpVersion(VerTag, Ver) != 0) // exact match
272  continue;
273 
274  // Newer version or an exact match? Save the hit
275  if (Last == 0 || Cache.GetPkgCache()->VS->CmpVersion(Version,Ver) < 0) {
276  Last = Parse;
277  Offset = Parse->Offset();
278  Version = Ver;
279  }
280 
281  // was the version check above an exact match?
282  // If so, we don't need to look further
283  if (VerTag.empty() == false && (VerTag == Ver))
284  break;
285  }
286  if (UserRequestedVerTag == "" && Version != "" && RelTag != "")
287  ioprintf(c1out, "Selected version '%s' (%s) for %s\n",
288  Version.c_str(), RelTag.c_str(), Src.c_str());
289 
290  if (Last != 0 || VerTag.empty() == true)
291  break;
292  _error->Error(_("Can not find version '%s' of package '%s'"), VerTag.c_str(), TmpSrc.c_str());
293  return 0;
294  }
295 
296  if (Last == 0 || Last->Jump(Offset) == false)
297  return 0;
298 
299  return Last;
300 }
301  /*}}}*/
302 // DoSource - Fetch a source archive /*{{{*/
303 // ---------------------------------------------------------------------
304 /* Fetch source packages */
305 struct DscFile
306 {
307  std::string Package;
308  std::string Version;
309  std::string Dsc;
310 };
312 {
313  if (CmdL.FileSize() <= 1)
314  return _error->Error(_("Must specify at least one package to fetch source for"));
315 
316  CacheFile Cache;
317  if (Cache.BuildCaches(false) == false)
318  return false;
319 
320  // Create the text record parsers
321  pkgSourceList * const List = Cache.GetSourceList();
322  pkgSrcRecords SrcRecs(*List);
323  if (_error->PendingError() == true)
324  return false;
325 
326  std::vector<DscFile> Dsc;
327  Dsc.reserve(CmdL.FileSize());
328 
329  // insert all downloaded uris into this set to avoid downloading them
330  // twice
331  std::set<std::string> queued;
332 
333  // Diff only mode only fetches .diff files
334  bool const diffOnly = _config->FindB("APT::Get::Diff-Only", false);
335  // Tar only mode only fetches .tar files
336  bool const tarOnly = _config->FindB("APT::Get::Tar-Only", false);
337  // Dsc only mode only fetches .dsc files
338  bool const dscOnly = _config->FindB("APT::Get::Dsc-Only", false);
339 
340  // Load the requestd sources into the fetcher
341  aptAcquireWithTextStatus Fetcher;
342  std::vector<std::string> UntrustedList;
343  for (const char **cmdl = CmdL.FileList + 1; *cmdl != 0; ++cmdl)
344  {
345  std::string Src;
346  pkgSrcRecords::Parser *Last = FindSrc(*cmdl, SrcRecs, Src, Cache);
347  if (Last == 0) {
348  return _error->Error(_("Unable to find a source package for %s"),Src.c_str());
349  }
350 
351  if (Last->Index().IsTrusted() == false)
352  UntrustedList.push_back(Src);
353 
354  std::string srec = Last->AsStr();
355  std::string::size_type pos = srec.find("\nVcs-");
356  while (pos != std::string::npos)
357  {
358  pos += strlen("\nVcs-");
359  std::string vcs = srec.substr(pos,srec.find(":",pos)-pos);
360  if(vcs == "Browser")
361  {
362  pos = srec.find("\nVcs-", pos);
363  continue;
364  }
365  pos += vcs.length()+2;
366  std::string::size_type epos = srec.find("\n", pos);
367  std::string const uri = srec.substr(pos,epos-pos);
368  ioprintf(c1out, _("NOTICE: '%s' packaging is maintained in "
369  "the '%s' version control system at:\n"
370  "%s\n"),
371  Src.c_str(), vcs.c_str(), uri.c_str());
372  std::string vcscmd;
373  if (vcs == "Bzr")
374  vcscmd = "bzr branch " + uri;
375  else if (vcs == "Git")
376  vcscmd = "git clone " + uri;
377 
378  if (vcscmd.empty() == false)
379  ioprintf(c1out,_("Please use:\n%s\n"
380  "to retrieve the latest (possibly unreleased) "
381  "updates to the package.\n"),
382  vcscmd.c_str());
383  break;
384  }
385 
386  // Back track
387  std::vector<pkgSrcRecords::File> Lst;
388  if (Last->Files(Lst) == false) {
389  return false;
390  }
391 
392  DscFile curDsc;
393  // Load them into the fetcher
394  for (std::vector<pkgSrcRecords::File>::const_iterator I = Lst.begin();
395  I != Lst.end(); ++I)
396  {
397  // Try to guess what sort of file it is we are getting.
398  if (I->Type == "dsc")
399  {
400  curDsc.Package = Last->Package();
401  curDsc.Version = Last->Version();
402  curDsc.Dsc = flNotDir(I->Path);
403  }
404 
405  // Handle the only options so that multiple can be used at once
406  if (diffOnly == true || tarOnly == true || dscOnly == true)
407  {
408  if ((diffOnly == true && I->Type == "diff") ||
409  (tarOnly == true && I->Type == "tar") ||
410  (dscOnly == true && I->Type == "dsc"))
411  ; // Fine, we want this file downloaded
412  else
413  continue;
414  }
415 
416  // don't download the same uri twice (should this be moved to
417  // the fetcher interface itself?)
418  if(queued.find(Last->Index().ArchiveURI(I->Path)) != queued.end())
419  continue;
420  queued.insert(Last->Index().ArchiveURI(I->Path));
421 
422  // check if we have a file with that md5 sum already localy
423  std::string localFile = flNotDir(I->Path);
424  if (FileExists(localFile) == true)
425  if(I->Hashes.VerifyFile(localFile) == true)
426  {
427  ioprintf(c1out,_("Skipping already downloaded file '%s'\n"),
428  localFile.c_str());
429  continue;
430  }
431 
432  // see if we have a hash (Acquire::ForceHash is the only way to have none)
433  if (I->Hashes.usable() == false && _config->FindB("APT::Get::AllowUnauthenticated",false) == false)
434  {
435  ioprintf(c1out, "Skipping download of file '%s' as requested hashsum is not available for authentication\n",
436  localFile.c_str());
437  curDsc.Dsc.clear();
438  continue;
439  }
440 
441  new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
442  I->Hashes, I->FileSize, Last->Index().SourceInfo(*Last,*I), Src);
443  }
444  Dsc.push_back(std::move(curDsc));
445  }
446 
447  // Display statistics
448  unsigned long long FetchBytes = Fetcher.FetchNeeded();
449  unsigned long long FetchPBytes = Fetcher.PartialPresent();
450  unsigned long long DebBytes = Fetcher.TotalNeeded();
451 
452  if (CheckFreeSpaceBeforeDownload(".", (FetchBytes - FetchPBytes)) == false)
453  return false;
454 
455  // Number of bytes
456  if (DebBytes != FetchBytes)
457  //TRANSLATOR: The required space between number and unit is already included
458  // in the replacement strings, so %sB will be correctly translate in e.g. 1,5 MB
459  ioprintf(c1out,_("Need to get %sB/%sB of source archives.\n"),
460  SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str());
461  else
462  //TRANSLATOR: The required space between number and unit is already included
463  // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB
464  ioprintf(c1out,_("Need to get %sB of source archives.\n"),
465  SizeToStr(DebBytes).c_str());
466 
467  if (_config->FindB("APT::Get::Simulate",false) == true)
468  {
469  for (auto const &D: Dsc)
470  ioprintf(std::cout, _("Fetch source %s\n"), D.Package.c_str());
471  return true;
472  }
473 
474  // Just print out the uris an exit if the --print-uris flag was used
475  if (_config->FindB("APT::Get::Print-URIs") == true)
476  {
477  pkgAcquire::UriIterator I = Fetcher.UriBegin();
478  for (; I != Fetcher.UriEnd(); ++I)
479  std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' <<
480  std::to_string(I->Owner->FileSize) << ' ' << I->Owner->HashSum() << std::endl;
481  return true;
482  }
483 
484  // check authentication status of the source as well
485  if (UntrustedList.empty() == false && AuthPrompt(UntrustedList, false) == false)
486  return false;
487 
488  // Run it
489  bool Failed = false;
490  if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true)
491  return _error->Error(_("Failed to fetch some archives."));
492 
493  if (diffOnly || tarOnly || dscOnly || _config->FindB("APT::Get::Download-only",false) == true)
494  {
495  c1out << _("Download complete and in download only mode") << std::endl;
496  return true;
497  }
498 
499  bool const fixBroken = _config->FindB("APT::Get::Fix-Broken", false);
500  bool SaidCheckIfDpkgDev = false;
501  for (auto const &D: Dsc)
502  {
503  if (unlikely(D.Dsc.empty() == true))
504  continue;
505  std::string const Dir = D.Package + '-' + Cache.GetPkgCache()->VS->UpstreamVersion(D.Version.c_str());
506 
507  // See if the package is already unpacked
508  struct stat Stat;
509  if (fixBroken == false && stat(Dir.c_str(),&Stat) == 0 &&
510  S_ISDIR(Stat.st_mode) != 0)
511  {
512  ioprintf(c0out ,_("Skipping unpack of already unpacked source in %s\n"),
513  Dir.c_str());
514  }
515  else
516  {
517  // Call dpkg-source
518  std::string const sourceopts = _config->Find("DPkg::Source-Options", "--no-check -x");
519  std::string S;
520  strprintf(S, "%s %s %s",
521  _config->Find("Dir::Bin::dpkg-source","dpkg-source").c_str(),
522  sourceopts.c_str(), D.Dsc.c_str());
523  if (system(S.c_str()) != 0)
524  {
525  _error->Error(_("Unpack command '%s' failed.\n"), S.c_str());
526  if (SaidCheckIfDpkgDev == false)
527  {
528  _error->Notice(_("Check if the 'dpkg-dev' package is installed.\n"));
529  SaidCheckIfDpkgDev = true;
530  }
531  continue;
532  }
533  }
534 
535  // Try to compile it with dpkg-buildpackage
536  if (_config->FindB("APT::Get::Compile",false) == true)
537  {
538  std::string buildopts = _config->Find("APT::Get::Host-Architecture");
539  if (buildopts.empty() == false)
540  buildopts = "-a" + buildopts + " ";
541 
542  // get all active build profiles
543  std::string const profiles = APT::Configuration::getBuildProfilesString();
544  if (profiles.empty() == false)
545  buildopts.append(" -P").append(profiles).append(" ");
546 
547  buildopts.append(_config->Find("DPkg::Build-Options","-b -uc"));
548 
549  // Call dpkg-buildpackage
550  std::string S;
551  strprintf(S, "cd %s && %s %s",
552  Dir.c_str(),
553  _config->Find("Dir::Bin::dpkg-buildpackage","dpkg-buildpackage").c_str(),
554  buildopts.c_str());
555 
556  if (system(S.c_str()) != 0)
557  {
558  _error->Error(_("Build command '%s' failed.\n"), S.c_str());
559  continue;
560  }
561  }
562  }
563  return true;
564 }
565  /*}}}*/
566 // DoBuildDep - Install/removes packages to satisfy build dependencies /*{{{*/
567 // ---------------------------------------------------------------------
568 /* This function will look at the build depends list of the given source
569  package and install the necessary packages to make it true, or fail. */
570 static std::vector<pkgSrcRecords::Parser::BuildDepRec> GetBuildDeps(pkgSrcRecords::Parser * const Last,
571  char const * const Src, bool const StripMultiArch, std::string const &hostArch)
572 {
573  std::vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
574  // FIXME: Can't specify architecture to use for [wildcard] matching, so switch default arch temporary
575  if (hostArch.empty() == false)
576  {
577  std::string nativeArch = _config->Find("APT::Architecture");
578  _config->Set("APT::Architecture", hostArch);
579  bool Success = Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch);
580  _config->Set("APT::Architecture", nativeArch);
581  if (Success == false)
582  {
583  _error->Error(_("Unable to get build-dependency information for %s"), Src);
584  return {};
585  }
586  }
587  else if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch) == false)
588  {
589  _error->Error(_("Unable to get build-dependency information for %s"), Src);
590  return {};
591  }
592 
593  if (BuildDeps.empty() == true)
594  ioprintf(c1out,_("%s has no build depends.\n"), Src);
595 
596  return BuildDeps;
597 }
598 static void WriteBuildDependencyPackage(std::ostringstream &buildDepsPkgFile,
599  std::string const &PkgName, std::string const &Arch,
600  std::vector<pkgSrcRecords::Parser::BuildDepRec> const &Dependencies)
601 {
602  buildDepsPkgFile << "Package: " << PkgName << "\n"
603  << "Architecture: " << Arch << "\n"
604  << "Version: 1\n";
605 
606  bool const IndepOnly = _config->FindB("APT::Get::Indep-Only", false);
607  std::string depends, conflicts;
608  for (auto const &dep: Dependencies)
609  {
610  // ArchOnly is handled while parsing the dependencies on input
611  if (IndepOnly && (dep.Type == pkgSrcRecords::Parser::BuildDependArch ||
613  continue;
614  std::string * type;
615  if (dep.Type == pkgSrcRecords::Parser::BuildConflict ||
618  type = &conflicts;
619  else
620  type = &depends;
621 
622  type->append(" ").append(dep.Package);
623  if (dep.Version.empty() == false)
624  type->append(" (").append(pkgCache::CompTypeDeb(dep.Op)).append(" ").append(dep.Version).append(")");
625  if ((dep.Op & pkgCache::Dep::Or) == pkgCache::Dep::Or)
626  {
627  type->append("\n |");
628  }
629  else
630  type->append(",\n");
631  }
632  if (depends.empty() == false)
633  buildDepsPkgFile << "Depends:\n" << depends;
634  if (conflicts.empty() == false)
635  buildDepsPkgFile << "Conflicts:\n" << conflicts;
636  buildDepsPkgFile << "\n";
637 }
639 {
640  bool StripMultiArch;
641  std::string hostArch = _config->Find("APT::Get::Host-Architecture");
642  if (hostArch.empty() == false)
643  {
644  std::vector<std::string> archs = APT::Configuration::getArchitectures();
645  if (std::find(archs.begin(), archs.end(), hostArch) == archs.end())
646  return _error->Error(_("No architecture information available for %s. See apt.conf(5) APT::Architectures for setup"), hostArch.c_str());
647  StripMultiArch = false;
648  }
649  else
650  StripMultiArch = true;
651  auto const nativeArch = _config->Find("APT::Architecture");
652  std::string const pseudoArch = hostArch.empty() ? nativeArch : hostArch;
653 
654  CacheFile Cache;
655  auto VolatileCmdL = GetPseudoPackages(Cache.GetSourceList(), CmdL, AddVolatileSourceFile, pseudoArch);
656  auto AreDoingSatisfy = strcasecmp(CmdL.FileList[0], "satisfy") == 0;
657 
658  if (not AreDoingSatisfy)
659  _config->Set("APT::Install-Recommends", false);
660 
661  if (CmdL.FileSize() <= 1 && VolatileCmdL.empty())
662  return _error->Error(_("Must specify at least one package to check builddeps for"));
663 
664  std::ostringstream buildDepsPkgFile;
665  std::vector<PseudoPkg> pseudoPkgs;
666  // deal with the build essentials first
667  if (not AreDoingSatisfy)
668  {
669  std::vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
670  for (auto && opt: _config->FindVector("APT::Build-Essential"))
671  {
672  if (opt.empty())
673  continue;
675  rec.Package = std::move(opt);
677  rec.Op = 0;
678  BuildDeps.push_back(rec);
679  }
680  std::string const pseudo = "builddeps:essentials";
681  WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, nativeArch, BuildDeps);
682  pseudoPkgs.emplace_back(pseudo, nativeArch, "");
683  }
684 
685  if (AreDoingSatisfy)
686  {
687  std::vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
688  for (unsigned i = 1; i < CmdL.FileSize(); i++)
689  {
690  const char *Start = CmdL.FileList[i];
691  const char *Stop = Start + strlen(Start);
693 
694  // Reject '>' and '<' as operators, as they have strange meanings.
695  bool insideVersionRestriction = false;
696  for (auto C = Start; C + 1 < Stop; C++)
697  {
698  if (*C == '(')
699  insideVersionRestriction = true;
700  else if (*C == ')')
701  insideVersionRestriction = false;
702  else if (insideVersionRestriction && (*C == '<' || *C == '>'))
703  {
704  if (C[1] != *C && C[1] != '=')
705  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);
706  C++;
707  }
708  }
709 
710  if (APT::String::Startswith(Start, "Conflicts:"))
711  {
713  Start += strlen("Conflicts:");
714  }
715  while (1)
716  {
718  Start = debListParser::ParseDepends(Start, Stop,
719  rec.Package, rec.Version, rec.Op, true, false, true, pseudoArch);
720 
721  if (Start == 0)
722  return _error->Error("Problem parsing dependency: %s", CmdL.FileList[i]);
723  rec.Type = Type;
724 
725  // We parsed a package that was ignored (wrong architecture restriction
726  // or something).
727  if (rec.Package.empty())
728  {
729  // If we are in an OR group, we need to set the "Or" flag of the
730  // previous entry to our value.
731  if (BuildDeps.empty() == false && (BuildDeps[BuildDeps.size() - 1].Op & pkgCache::Dep::Or) == pkgCache::Dep::Or)
732  {
733  BuildDeps[BuildDeps.size() - 1].Op &= ~~pkgCache::Dep::Or;
734  BuildDeps[BuildDeps.size() - 1].Op |= (rec.Op & pkgCache::Dep::Or);
735  }
736  }
737  else
738  {
739  BuildDeps.emplace_back(std::move(rec));
740  }
741 
742  if (Start == Stop)
743  break;
744  }
745  }
746  std::string const pseudo = "command line argument";
747  WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch, BuildDeps);
748  pseudoPkgs.emplace_back(pseudo, pseudoArch, "");
749  }
750 
751  // Read the source list
752  if (Cache.BuildSourceList() == false)
753  return false;
754  pkgSourceList *List = Cache.GetSourceList();
755 
756  if (not AreDoingSatisfy)
757  {
758  auto const VolatileSources = List->GetVolatileFiles();
759  for (auto &&pkg : VolatileCmdL)
760  {
761  if (unlikely(pkg.index == -1))
762  {
763  _error->Error(_("Unable to find a source package for %s"), pkg.name.c_str());
764  continue;
765  }
766  if (DirectoryExists(pkg.name))
767  ioprintf(c1out, _("Note, using directory '%s' to get the build dependencies\n"), pkg.name.c_str());
768  else
769  ioprintf(c1out, _("Note, using file '%s' to get the build dependencies\n"), pkg.name.c_str());
770  std::unique_ptr<pkgSrcRecords::Parser> Last(VolatileSources[pkg.index]->CreateSrcParser());
771  if (Last == nullptr)
772  {
773  _error->Error(_("Unable to find a source package for %s"), pkg.name.c_str());
774  continue;
775  }
776 
777  auto pseudo = std::string("builddeps:") + pkg.name;
778  WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch,
779  GetBuildDeps(Last.get(), pkg.name.c_str(), StripMultiArch, hostArch));
780  pkg.name = std::move(pseudo);
781  pseudoPkgs.push_back(std::move(pkg));
782  }
783  VolatileCmdL.clear();
784  }
785 
786  bool const WantLock = _config->FindB("APT::Get::Print-URIs", false) == false;
787  if (CmdL.FileList[1] != 0 && not AreDoingSatisfy)
788  {
789  if (Cache.BuildCaches(WantLock) == false)
790  return false;
791  // Create the text record parsers
792  pkgSrcRecords SrcRecs(*List);
793  if (_error->PendingError() == true)
794  return false;
795  for (const char **I = CmdL.FileList + 1; *I != 0; ++I)
796  {
797  std::string Src;
798  pkgSrcRecords::Parser * const Last = FindSrc(*I,SrcRecs,Src,Cache);
799  if (Last == nullptr)
800  return _error->Error(_("Unable to find a source package for %s"), *I);
801 
802  std::string const pseudo = std::string("builddeps:") + Src;
803  WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch,
804  GetBuildDeps(Last, Src.c_str(), StripMultiArch, hostArch));
805  std::string reltag = *I;
806  size_t found = reltag.find_last_of("/");
807  if (found == std::string::npos)
808  reltag.clear();
809  else
810  reltag.erase(0, found + 1);
811  pseudoPkgs.emplace_back(pseudo, pseudoArch, std::move(reltag));
812  }
813  }
814 
815  Cache.AddIndexFile(new debStringPackageIndex(buildDepsPkgFile.str()));
816 
817  if (Cache.Open(WantLock) == false)
818  return false;
819  pkgProblemResolver Fix(Cache.GetDepCache());
820 
821  APT::PackageVector removeAgain;
822  {
823  pkgDepCache::ActionGroup group(Cache);
824  TryToInstall InstallAction(Cache, &Fix, false);
825  std::list<std::pair<pkgCache::VerIterator, std::string>> candSwitch;
826  for (auto const &pkg: pseudoPkgs)
827  {
828  pkgCache::PkgIterator const Pkg = Cache->FindPkg(pkg.name, pkg.arch);
829  if (Pkg.end())
830  continue;
831  if (pkg.release.empty())
832  Cache->SetCandidateVersion(Pkg.VersionList());
833  else
834  candSwitch.emplace_back(Pkg.VersionList(), pkg.release);
835  }
836  if (candSwitch.empty() == false)
837  InstallAction.propergateReleaseCandiateSwitching(candSwitch, c0out);
838  for (auto const &pkg: pseudoPkgs)
839  {
840  pkgCache::PkgIterator const Pkg = Cache->FindPkg(pkg.name, pkg.arch);
841  if (Pkg.end())
842  continue;
843  InstallAction(Cache[Pkg].CandidateVerIter(Cache));
844  removeAgain.push_back(Pkg);
845  }
846  InstallAction.doAutoInstall();
847 
848  OpTextProgress Progress(*_config);
849  bool const resolver_fail = Fix.Resolve(true, &Progress);
850  if (resolver_fail == false && Cache->BrokenCount() == 0)
851  return false;
852  if (CheckNothingBroken(Cache) == false)
853  return false;
854  }
855  if (DoAutomaticRemove(Cache) == false)
856  return false;
857 
858  {
859  pkgDepCache::ActionGroup group(Cache);
860  if (_config->FindB(AreDoingSatisfy ? "APT::Get::Satisfy-Automatic" : "APT::Get::Build-Dep-Automatic", false) == false)
861  {
862  for (auto const &pkg: removeAgain)
863  {
864  auto const instVer = Cache[pkg].InstVerIter(Cache);
865  if (unlikely(instVer.end() == true))
866  continue;
867  for (auto D = instVer.DependsList(); D.end() != true; ++D)
868  {
869  if (D->Type != pkgCache::Dep::Depends || D.IsMultiArchImplicit())
870  continue;
872  for (auto const &V : verlist)
873  {
874  auto const P = V.ParentPkg();
875  if (Cache[P].InstallVer != V)
876  continue;
877  Cache->MarkAuto(P, false);
878  }
879  }
880  }
881  }
882  for (auto const &pkg: removeAgain)
883  Cache->MarkDelete(pkg, false, 0, true);
884  }
885 
886  pseudoPkgs.clear();
887  if (_error->PendingError() || InstallPackages(Cache, false, true) == false)
888  return _error->Error(_("Failed to process build dependencies"));
889  return true;
890 }
891  /*}}}*/
strprintf(m, msg, repo.c_str())
static bool std::string const metaIndex const *const pkgAcqMetaClearSig *const pkgAcquire::Item *const I
void push_back(const value_type &P)
Definition: cacheset.h:395
static VersionContainer FromDependency(pkgCacheFile &Cache, pkgCache::DepIterator const &D, CacheSetHelper::VerSelector const selector, CacheSetHelper &helper)
Definition: cacheset.h:947
bool BuildCaches(bool WithLock=true)
bool Open(bool WithLock=true)
const char ** FileList
Definition: cmndline.h:78
unsigned int FileSize() const APT_PURE
Definition: cmndline.cc:353
void Set(const std::string &Name, const std::string &Value)
Definition: configuration.h:92
std::vector< std::string > FindVector(const char *Name, std::string const &Default="", bool const Keys=false) const
std::string Find(const char *Name, const char *Default=0) const
bool FindB(const char *Name, bool const &Default=false) const
bool ParseDepends(pkgCache::VerIterator &Ver, pkgTagSection::Key Key, unsigned int Type)
std::string URI
Definition: metaindex.h:39
const char * Type
Definition: metaindex.h:38
Retrieve an arbitrary file to the current directory. {{{.
UriIterator UriBegin()
Get the head of the list of enqueued item URIs.
Definition: acquire.cc:872
unsigned long long FetchNeeded()
Definition: acquire.cc:844
unsigned long long TotalNeeded()
Definition: acquire.cc:833
UriIterator UriEnd()
Get the end iterator of the list of enqueued item URIs.
Definition: acquire.cc:880
UriIterator(pkgAcquire::Queue *Q)
Create a new UriIterator.
unsigned long long PartialPresent()
Definition: acquire.cc:858
pkgPolicy * GetPolicy()
Definition: cachefile.h:75
pkgDepCache * GetDepCache()
Definition: cachefile.h:74
bool BuildSourceList(OpProgress *Progress=NULL)
Definition: cachefile.cc:151
pkgSourceList * GetSourceList()
Definition: cachefile.h:76
bool BuildPolicy(OpProgress *Progress=NULL)
Definition: cachefile.cc:167
bool AddIndexFile(pkgIndexFile *const File)
Definition: cachefile.cc:231
pkgCache * GetPkgCache()
Definition: cachefile.h:73
static const char * CompTypeDeb(unsigned char Comp) APT_PURE
Definition: pkgcache.cc:317
Represents an active action group.
Definition: depcache.h:166
virtual std::string ArchiveURI(std::string const &) const
Definition: indexfile.h:135
bool IsTrusted() const
Definition: indexfile.h:147
virtual std::string SourceInfo(pkgSrcRecords::Parser const &Record, pkgSrcRecords::File const &File) const
Definition: indexfile.cc:81
virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const
Definition: indexfile.cc:75
bool Resolve(bool BrokenFix=false, OpProgress *const Progress=NULL)
Definition: algorithms.cc:741
std::vector< pkgIndexFile * > GetVolatileFiles() const
Definition: sourcelist.cc:530
const_iterator begin() const
Definition: sourcelist.h:97
const_iterator end() const
Definition: sourcelist.h:98
std::vector< metaIndex * >::const_iterator const_iterator
Definition: sourcelist.h:76
virtual bool Files(std::vector< pkgSrcRecords::File > &F)=0
const pkgIndexFile & Index() const
Definition: srcrecords.h:59
virtual bool BuildDepends(std::vector< BuildDepRec > &BuildDeps, bool const &ArchOnly, bool const &StripMultiArch=true)=0
virtual std::string Version() const =0
virtual std::string AsStr()=0
virtual bool Jump(unsigned long const &Off)=0
virtual std::string Package() const =0
virtual unsigned long Offset()=0
bool Restart()
Definition: srcrecords.cc:76
Parser * Find(const char *Package, bool const &SrcOnly=false)
Definition: srcrecords.cc:111
Configuration * _config
bool DirectoryExists(string const &Path)
Definition: fileutl.cc:348
string flNotDir(string File)
Definition: fileutl.cc:664
bool FileExists(string File)
Definition: fileutl.cc:326
APT_PUBLIC std::vector< std::string > const getArchitectures(bool const &Cached=true)
Returns a vector of Architectures we support.
APT_PUBLIC std::string const getBuildProfilesString()
bool Startswith(const std::string &s, const std::string &start)
Definition: strutl.cc:84
pkgCache - Structure definitions for the cache file
bool AuthPrompt(std::vector< std::string > const &UntrustedList, bool const PromptUser)
bool AcquireRun(pkgAcquire &Fetcher, int const PulseInterval, bool *const Failure, bool *const TransientNetworkFailure)
bool CheckFreeSpaceBeforeDownload(std::string const &Dir, unsigned long long FetchBytes)
bool AddVolatileSourceFile(pkgSourceList *const SL, PseudoPkg &&pkg, std::vector< PseudoPkg > &VolatileCmdL)
bool CheckNothingBroken(CacheFile &Cache)
bool DoAutomaticRemove(CacheFile &Cache)
bool InstallPackages(CacheFile &Cache, bool ShwKept, bool Ask, bool Safety)
std::vector< PseudoPkg > GetPseudoPackages(pkgSourceList *const SL, CommandLine &CmdL, bool(*Add)(pkgSourceList *const, PseudoPkg &&, std::vector< PseudoPkg > &), std::string const &pseudoArch)
APT_PUBLIC std::ostream c1out
APT_PUBLIC std::ostream c0out
bool Policy(CommandLine &CmdL)
static std::vector< pkgSrcRecords::Parser::BuildDepRec > GetBuildDeps(pkgSrcRecords::Parser *const Last, char const *const Src, bool const StripMultiArch, std::string const &hostArch)
static void WriteBuildDependencyPackage(std::ostringstream &buildDepsPkgFile, std::string const &PkgName, std::string const &Arch, std::vector< pkgSrcRecords::Parser::BuildDepRec > const &Dependencies)
bool DoSource(CommandLine &CmdL)
bool DoBuildDep(CommandLine &CmdL)
static pkgCache::RlsFileIterator GetReleaseFileForSourceRecord(CacheFile &CacheFile, pkgSourceList const *const SrcList, pkgSrcRecords::Parser const *const Parse)
static pkgSrcRecords::Parser * FindSrc(const char *Name, pkgSrcRecords &SrcRecs, std::string &Src, CacheFile &Cache)
std::string Package
std::string Dsc
std::string Version
bool propergateReleaseCandiateSwitching(std::list< std::pair< pkgCache::VerIterator, std::string > > const &start, std::ostream &out)
string SizeToStr(double Size)
Definition: strutl.cc:437
void ioprintf(ostream &out, const char *format,...)
Definition: strutl.cc:1433