You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

829 lines
27 KiB

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