private-source.cc 26 KB

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