private-source.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  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. Dsc[J].Dsc.clear();
  397. continue;
  398. }
  399. new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
  400. I->Hashes, I->FileSize, Last->Index().SourceInfo(*Last,*I), Src);
  401. }
  402. }
  403. // Display statistics
  404. unsigned long long FetchBytes = Fetcher.FetchNeeded();
  405. unsigned long long FetchPBytes = Fetcher.PartialPresent();
  406. unsigned long long DebBytes = Fetcher.TotalNeeded();
  407. if (CheckFreeSpaceBeforeDownload(".", (FetchBytes - FetchPBytes)) == false)
  408. return false;
  409. // Number of bytes
  410. if (DebBytes != FetchBytes)
  411. //TRANSLATOR: The required space between number and unit is already included
  412. // in the replacement strings, so %sB will be correctly translate in e.g. 1,5 MB
  413. ioprintf(c1out,_("Need to get %sB/%sB of source archives.\n"),
  414. SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str());
  415. else
  416. //TRANSLATOR: The required space between number and unit is already included
  417. // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB
  418. ioprintf(c1out,_("Need to get %sB of source archives.\n"),
  419. SizeToStr(DebBytes).c_str());
  420. if (_config->FindB("APT::Get::Simulate",false) == true)
  421. {
  422. for (unsigned I = 0; I != J; I++)
  423. ioprintf(std::cout,_("Fetch source %s\n"),Dsc[I].Package.c_str());
  424. return true;
  425. }
  426. // Just print out the uris an exit if the --print-uris flag was used
  427. if (_config->FindB("APT::Get::Print-URIs") == true)
  428. {
  429. pkgAcquire::UriIterator I = Fetcher.UriBegin();
  430. for (; I != Fetcher.UriEnd(); ++I)
  431. std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' <<
  432. std::to_string(I->Owner->FileSize) << ' ' << I->Owner->HashSum() << std::endl;
  433. return true;
  434. }
  435. // check authentication status of the source as well
  436. if (UntrustedList.empty() == false && AuthPrompt(UntrustedList, false) == false)
  437. return false;
  438. // Run it
  439. bool Failed = false;
  440. if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true)
  441. {
  442. return _error->Error(_("Failed to fetch some archives."));
  443. }
  444. if (_config->FindB("APT::Get::Download-only",false) == true)
  445. {
  446. c1out << _("Download complete and in download only mode") << std::endl;
  447. return true;
  448. }
  449. // Unpack the sources
  450. pid_t Process = ExecFork();
  451. if (Process == 0)
  452. {
  453. bool const fixBroken = _config->FindB("APT::Get::Fix-Broken", false);
  454. for (unsigned I = 0; I != J; ++I)
  455. {
  456. std::string Dir = Dsc[I].Package + '-' + Cache.GetPkgCache()->VS->UpstreamVersion(Dsc[I].Version.c_str());
  457. // Diff only mode only fetches .diff files
  458. if (_config->FindB("APT::Get::Diff-Only",false) == true ||
  459. _config->FindB("APT::Get::Tar-Only",false) == true ||
  460. Dsc[I].Dsc.empty() == true)
  461. continue;
  462. // See if the package is already unpacked
  463. struct stat Stat;
  464. if (fixBroken == false && stat(Dir.c_str(),&Stat) == 0 &&
  465. S_ISDIR(Stat.st_mode) != 0)
  466. {
  467. ioprintf(c0out ,_("Skipping unpack of already unpacked source in %s\n"),
  468. Dir.c_str());
  469. }
  470. else
  471. {
  472. // Call dpkg-source
  473. std::string const sourceopts = _config->Find("DPkg::Source-Options", "-x");
  474. std::string S;
  475. strprintf(S, "%s %s %s",
  476. _config->Find("Dir::Bin::dpkg-source","dpkg-source").c_str(),
  477. sourceopts.c_str(), Dsc[I].Dsc.c_str());
  478. if (RunCmd(S.c_str()) != 0)
  479. {
  480. fprintf(stderr, _("Unpack command '%s' failed.\n"), S.c_str());
  481. fprintf(stderr, _("Check if the 'dpkg-dev' package is installed.\n"));
  482. _exit(1);
  483. }
  484. }
  485. // Try to compile it with dpkg-buildpackage
  486. if (_config->FindB("APT::Get::Compile",false) == true)
  487. {
  488. std::string buildopts = _config->Find("APT::Get::Host-Architecture");
  489. if (buildopts.empty() == false)
  490. buildopts = "-a" + buildopts + " ";
  491. // get all active build profiles
  492. std::string const profiles = APT::Configuration::getBuildProfilesString();
  493. if (profiles.empty() == false)
  494. buildopts.append(" -P").append(profiles).append(" ");
  495. buildopts.append(_config->Find("DPkg::Build-Options","-b -uc"));
  496. // Call dpkg-buildpackage
  497. std::string S;
  498. strprintf(S, "cd %s && %s %s",
  499. Dir.c_str(),
  500. _config->Find("Dir::Bin::dpkg-buildpackage","dpkg-buildpackage").c_str(),
  501. buildopts.c_str());
  502. if (RunCmd(S.c_str()) != 0)
  503. {
  504. fprintf(stderr, _("Build command '%s' failed.\n"), S.c_str());
  505. _exit(1);
  506. }
  507. }
  508. }
  509. _exit(0);
  510. }
  511. return ExecWait(Process, "dpkg-source");
  512. }
  513. /*}}}*/
  514. // DoBuildDep - Install/removes packages to satisfy build dependencies /*{{{*/
  515. // ---------------------------------------------------------------------
  516. /* This function will look at the build depends list of the given source
  517. package and install the necessary packages to make it true, or fail. */
  518. static std::vector<pkgSrcRecords::Parser::BuildDepRec> GetBuildDeps(pkgSrcRecords::Parser * const Last,
  519. char const * const Src, bool const StripMultiArch, std::string const &hostArch)
  520. {
  521. std::vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
  522. // FIXME: Can't specify architecture to use for [wildcard] matching, so switch default arch temporary
  523. if (hostArch.empty() == false)
  524. {
  525. std::string nativeArch = _config->Find("APT::Architecture");
  526. _config->Set("APT::Architecture", hostArch);
  527. bool Success = Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch);
  528. _config->Set("APT::Architecture", nativeArch);
  529. if (Success == false)
  530. {
  531. _error->Error(_("Unable to get build-dependency information for %s"), Src);
  532. return {};
  533. }
  534. }
  535. else if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch) == false)
  536. {
  537. _error->Error(_("Unable to get build-dependency information for %s"), Src);
  538. return {};
  539. }
  540. if (BuildDeps.empty() == true)
  541. ioprintf(c1out,_("%s has no build depends.\n"), Src);
  542. return BuildDeps;
  543. }
  544. static void WriteBuildDependencyPackage(std::ostringstream &buildDepsPkgFile,
  545. std::string const &PkgName, std::string const &Arch,
  546. std::vector<pkgSrcRecords::Parser::BuildDepRec> const &Dependencies)
  547. {
  548. buildDepsPkgFile << "Package: " << PkgName << "\n"
  549. << "Architecture: " << Arch << "\n"
  550. << "Version: 1\n";
  551. std::string depends, conflicts;
  552. for (auto const &dep: Dependencies)
  553. {
  554. std::string * type;
  555. if (dep.Type == pkgSrcRecords::Parser::BuildConflict ||
  556. dep.Type == pkgSrcRecords::Parser::BuildConflictIndep ||
  557. dep.Type == pkgSrcRecords::Parser::BuildConflictArch)
  558. type = &conflicts;
  559. else
  560. type = &depends;
  561. type->append(" ").append(dep.Package);
  562. if (dep.Version.empty() == false)
  563. type->append(" (").append(pkgCache::CompTypeDeb(dep.Op)).append(" ").append(dep.Version).append(")");
  564. if ((dep.Op & pkgCache::Dep::Or) == pkgCache::Dep::Or)
  565. {
  566. type->append("\n |");
  567. }
  568. else
  569. type->append(",\n");
  570. }
  571. if (depends.empty() == false)
  572. buildDepsPkgFile << "Depends:\n" << depends;
  573. if (conflicts.empty() == false)
  574. buildDepsPkgFile << "Conflicts:\n" << conflicts;
  575. buildDepsPkgFile << "\n";
  576. }
  577. bool DoBuildDep(CommandLine &CmdL)
  578. {
  579. CacheFile Cache;
  580. std::vector<std::string> VolatileCmdL;
  581. Cache.GetSourceList()->AddVolatileFiles(CmdL, &VolatileCmdL);
  582. _config->Set("APT::Install-Recommends", false);
  583. if (CmdL.FileSize() <= 1 && VolatileCmdL.empty())
  584. return _error->Error(_("Must specify at least one package to check builddeps for"));
  585. bool StripMultiArch;
  586. std::string hostArch = _config->Find("APT::Get::Host-Architecture");
  587. if (hostArch.empty() == false)
  588. {
  589. std::vector<std::string> archs = APT::Configuration::getArchitectures();
  590. if (std::find(archs.begin(), archs.end(), hostArch) == archs.end())
  591. return _error->Error(_("No architecture information available for %s. See apt.conf(5) APT::Architectures for setup"), hostArch.c_str());
  592. StripMultiArch = false;
  593. }
  594. else
  595. StripMultiArch = true;
  596. std::ostringstream buildDepsPkgFile;
  597. std::vector<std::pair<std::string,std::string>> pseudoPkgs;
  598. // deal with the build essentials first
  599. {
  600. std::vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
  601. Configuration::Item const *Opts = _config->Tree("APT::Build-Essential");
  602. if (Opts)
  603. Opts = Opts->Child;
  604. for (; Opts; Opts = Opts->Next)
  605. {
  606. if (Opts->Value.empty() == true)
  607. continue;
  608. pkgSrcRecords::Parser::BuildDepRec rec;
  609. rec.Package = Opts->Value;
  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. pseudoPkgs.emplace_back(pseudo, pseudoArch);
  669. }
  670. }
  671. Cache.AddIndexFile(new debStringPackageIndex(buildDepsPkgFile.str()));
  672. if (Cache.Open(WantLock) == false)
  673. return false;
  674. pkgProblemResolver Fix(Cache.GetDepCache());
  675. APT::PackageVector removeAgain;
  676. {
  677. pkgDepCache::ActionGroup group(Cache);
  678. TryToInstall InstallAction(Cache, &Fix, false);
  679. for (auto const &pkg: pseudoPkgs)
  680. {
  681. pkgCache::PkgIterator const Pkg = Cache->FindPkg(pkg.first, pkg.second);
  682. if (Pkg.end())
  683. continue;
  684. Cache->SetCandidateVersion(Pkg.VersionList());
  685. InstallAction(Cache[Pkg].CandidateVerIter(Cache));
  686. removeAgain.push_back(Pkg);
  687. }
  688. InstallAction.doAutoInstall();
  689. OpTextProgress Progress(*_config);
  690. bool const resolver_fail = Fix.Resolve(true, &Progress);
  691. if (resolver_fail == false && Cache->BrokenCount() == 0)
  692. return false;
  693. if (CheckNothingBroken(Cache) == false)
  694. return false;
  695. }
  696. if (DoAutomaticRemove(Cache) == false)
  697. return false;
  698. {
  699. pkgDepCache::ActionGroup group(Cache);
  700. if (_config->FindB("APT::Get::Build-Dep-Automatic", false) == false)
  701. {
  702. for (auto const &pkg: removeAgain)
  703. {
  704. auto const instVer = Cache[pkg].InstVerIter(Cache);
  705. if (unlikely(instVer.end() == true))
  706. continue;
  707. for (auto D = instVer.DependsList(); D.end() != true; ++D)
  708. {
  709. if (D->Type != pkgCache::Dep::Depends || D.IsMultiArchImplicit())
  710. continue;
  711. APT::VersionList verlist = APT::VersionList::FromDependency(Cache, D, APT::CacheSetHelper::CANDIDATE);
  712. for (auto const &V : verlist)
  713. {
  714. auto const P = V.ParentPkg();
  715. if (Cache[P].InstallVer != V)
  716. continue;
  717. Cache->MarkAuto(P, false);
  718. }
  719. }
  720. }
  721. }
  722. for (auto const &pkg: removeAgain)
  723. Cache->MarkDelete(pkg, false, 0, true);
  724. }
  725. pseudoPkgs.clear();
  726. if (_error->PendingError() || InstallPackages(Cache, false, true) == false)
  727. return _error->Error(_("Failed to process build dependencies"));
  728. return true;
  729. }
  730. /*}}}*/