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.
 
 
 
 
 
 

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