private-source.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  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.GetPkgCache()->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.GetPkgCache()->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.empty() == true && ArchTag.empty() == false)
  176. {
  177. if (VerTag.empty() == false)
  178. _error->Error(_("Can not find a package '%s' with version '%s'"),
  179. Pkg.FullName().c_str(), VerTag.c_str());
  180. if (RelTag.empty() == false)
  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. // See if we need to look for a specific release tag
  241. if (RelTag.empty() == false && UserRequestedVerTag.empty() == true)
  242. {
  243. pkgCache::RlsFileIterator const Rls = GetReleaseFileForSourceRecord(Cache, SrcList, Parse);
  244. if (Rls.end() == false)
  245. {
  246. if ((Rls->Archive != 0 && RelTag != Rls.Archive()) &&
  247. (Rls->Codename != 0 && RelTag != Rls.Codename()))
  248. continue;
  249. }
  250. }
  251. // Ignore all versions which doesn't fit
  252. if (VerTag.empty() == false &&
  253. Cache.GetPkgCache()->VS->CmpVersion(VerTag, Ver) != 0) // exact match
  254. continue;
  255. // Newer version or an exact match? Save the hit
  256. if (Last == 0 || Cache.GetPkgCache()->VS->CmpVersion(Version,Ver) < 0) {
  257. Last = Parse;
  258. Offset = Parse->Offset();
  259. Version = Ver;
  260. }
  261. // was the version check above an exact match?
  262. // If so, we don't need to look further
  263. if (VerTag.empty() == false && (VerTag == Ver))
  264. break;
  265. }
  266. if (UserRequestedVerTag == "" && Version != "" && RelTag != "")
  267. ioprintf(c1out, "Selected version '%s' (%s) for %s\n",
  268. Version.c_str(), RelTag.c_str(), Src.c_str());
  269. if (Last != 0 || VerTag.empty() == true)
  270. break;
  271. _error->Error(_("Can not find version '%s' of package '%s'"), VerTag.c_str(), TmpSrc.c_str());
  272. return 0;
  273. }
  274. if (Last == 0 || Last->Jump(Offset) == false)
  275. return 0;
  276. return Last;
  277. }
  278. /*}}}*/
  279. // DoSource - Fetch a source archive /*{{{*/
  280. // ---------------------------------------------------------------------
  281. /* Fetch souce packages */
  282. struct DscFile
  283. {
  284. std::string Package;
  285. std::string Version;
  286. std::string Dsc;
  287. };
  288. bool DoSource(CommandLine &CmdL)
  289. {
  290. if (CmdL.FileSize() <= 1)
  291. return _error->Error(_("Must specify at least one package to fetch source for"));
  292. CacheFile Cache;
  293. // Read the source list
  294. if (Cache.BuildSourceList() == false)
  295. return false;
  296. pkgSourceList *List = Cache.GetSourceList();
  297. // Create the text record parsers
  298. pkgSrcRecords SrcRecs(*List);
  299. if (_error->PendingError() == true)
  300. return false;
  301. std::unique_ptr<DscFile[]> Dsc(new DscFile[CmdL.FileSize()]);
  302. // insert all downloaded uris into this set to avoid downloading them
  303. // twice
  304. std::set<std::string> queued;
  305. // Diff only mode only fetches .diff files
  306. bool const diffOnly = _config->FindB("APT::Get::Diff-Only", false);
  307. // Tar only mode only fetches .tar files
  308. bool const tarOnly = _config->FindB("APT::Get::Tar-Only", false);
  309. // Dsc only mode only fetches .dsc files
  310. bool const dscOnly = _config->FindB("APT::Get::Dsc-Only", false);
  311. // Load the requestd sources into the fetcher
  312. aptAcquireWithTextStatus Fetcher;
  313. unsigned J = 0;
  314. std::vector<std::string> UntrustedList;
  315. for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++)
  316. {
  317. std::string Src;
  318. pkgSrcRecords::Parser *Last = FindSrc(*I,SrcRecs,Src,Cache);
  319. if (Last == 0) {
  320. return _error->Error(_("Unable to find a source package for %s"),Src.c_str());
  321. }
  322. if (Last->Index().IsTrusted() == false)
  323. UntrustedList.push_back(Src);
  324. std::string srec = Last->AsStr();
  325. std::string::size_type pos = srec.find("\nVcs-");
  326. while (pos != std::string::npos)
  327. {
  328. pos += strlen("\nVcs-");
  329. std::string vcs = srec.substr(pos,srec.find(":",pos)-pos);
  330. if(vcs == "Browser")
  331. {
  332. pos = srec.find("\nVcs-", pos);
  333. continue;
  334. }
  335. pos += vcs.length()+2;
  336. std::string::size_type epos = srec.find("\n", pos);
  337. std::string const uri = srec.substr(pos,epos-pos);
  338. ioprintf(c1out, _("NOTICE: '%s' packaging is maintained in "
  339. "the '%s' version control system at:\n"
  340. "%s\n"),
  341. Src.c_str(), vcs.c_str(), uri.c_str());
  342. std::string vcscmd;
  343. if (vcs == "Bzr")
  344. vcscmd = "bzr branch " + uri;
  345. else if (vcs == "Git")
  346. vcscmd = "git clone " + uri;
  347. if (vcscmd.empty() == false)
  348. ioprintf(c1out,_("Please use:\n%s\n"
  349. "to retrieve the latest (possibly unreleased) "
  350. "updates to the package.\n"),
  351. vcscmd.c_str());
  352. break;
  353. }
  354. // Back track
  355. std::vector<pkgSrcRecords::File2> Lst;
  356. if (Last->Files2(Lst) == false) {
  357. return false;
  358. }
  359. // Load them into the fetcher
  360. for (std::vector<pkgSrcRecords::File2>::const_iterator I = Lst.begin();
  361. I != Lst.end(); ++I)
  362. {
  363. // Try to guess what sort of file it is we are getting.
  364. if (I->Type == "dsc")
  365. {
  366. Dsc[J].Package = Last->Package();
  367. Dsc[J].Version = Last->Version();
  368. Dsc[J].Dsc = flNotDir(I->Path);
  369. }
  370. // Handle the only options so that multiple can be used at once
  371. if (diffOnly == true || tarOnly == true || dscOnly == true)
  372. {
  373. if ((diffOnly == true && I->Type == "diff") ||
  374. (tarOnly == true && I->Type == "tar") ||
  375. (dscOnly == true && I->Type == "dsc"))
  376. ; // Fine, we want this file downloaded
  377. else
  378. continue;
  379. }
  380. // don't download the same uri twice (should this be moved to
  381. // the fetcher interface itself?)
  382. if(queued.find(Last->Index().ArchiveURI(I->Path)) != queued.end())
  383. continue;
  384. queued.insert(Last->Index().ArchiveURI(I->Path));
  385. // check if we have a file with that md5 sum already localy
  386. std::string localFile = flNotDir(I->Path);
  387. if (FileExists(localFile) == true)
  388. if(I->Hashes.VerifyFile(localFile) == true)
  389. {
  390. ioprintf(c1out,_("Skipping already downloaded file '%s'\n"),
  391. localFile.c_str());
  392. continue;
  393. }
  394. // see if we have a hash (Acquire::ForceHash is the only way to have none)
  395. if (I->Hashes.usable() == false && _config->FindB("APT::Get::AllowUnauthenticated",false) == false)
  396. {
  397. ioprintf(c1out, "Skipping download of file '%s' as requested hashsum is not available for authentication\n",
  398. localFile.c_str());
  399. continue;
  400. }
  401. new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
  402. I->Hashes, I->FileSize, Last->Index().SourceInfo(*Last,*I), Src);
  403. }
  404. }
  405. // Display statistics
  406. unsigned long long FetchBytes = Fetcher.FetchNeeded();
  407. unsigned long long FetchPBytes = Fetcher.PartialPresent();
  408. unsigned long long DebBytes = Fetcher.TotalNeeded();
  409. if (CheckFreeSpaceBeforeDownload(".", (FetchBytes - FetchPBytes)) == false)
  410. return false;
  411. // Number of bytes
  412. if (DebBytes != FetchBytes)
  413. //TRANSLATOR: The required space between number and unit is already included
  414. // in the replacement strings, so %sB will be correctly translate in e.g. 1,5 MB
  415. ioprintf(c1out,_("Need to get %sB/%sB of source archives.\n"),
  416. SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str());
  417. else
  418. //TRANSLATOR: The required space between number and unit is already included
  419. // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB
  420. ioprintf(c1out,_("Need to get %sB of source archives.\n"),
  421. SizeToStr(DebBytes).c_str());
  422. if (_config->FindB("APT::Get::Simulate",false) == true)
  423. {
  424. for (unsigned I = 0; I != J; I++)
  425. ioprintf(std::cout,_("Fetch source %s\n"),Dsc[I].Package.c_str());
  426. return true;
  427. }
  428. // Just print out the uris an exit if the --print-uris flag was used
  429. if (_config->FindB("APT::Get::Print-URIs") == true)
  430. {
  431. pkgAcquire::UriIterator I = Fetcher.UriBegin();
  432. for (; I != Fetcher.UriEnd(); ++I)
  433. std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' <<
  434. I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl;
  435. return true;
  436. }
  437. // check authentication status of the source as well
  438. if (UntrustedList.empty() == false && AuthPrompt(UntrustedList, false) == false)
  439. return false;
  440. // Run it
  441. bool Failed = false;
  442. if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true)
  443. {
  444. return _error->Error(_("Failed to fetch some archives."));
  445. }
  446. if (_config->FindB("APT::Get::Download-only",false) == true)
  447. {
  448. c1out << _("Download complete and in download only mode") << std::endl;
  449. return true;
  450. }
  451. // Unpack the sources
  452. pid_t Process = ExecFork();
  453. if (Process == 0)
  454. {
  455. bool const fixBroken = _config->FindB("APT::Get::Fix-Broken", false);
  456. for (unsigned I = 0; I != J; ++I)
  457. {
  458. std::string Dir = Dsc[I].Package + '-' + Cache.GetPkgCache()->VS->UpstreamVersion(Dsc[I].Version.c_str());
  459. // Diff only mode only fetches .diff files
  460. if (_config->FindB("APT::Get::Diff-Only",false) == true ||
  461. _config->FindB("APT::Get::Tar-Only",false) == true ||
  462. Dsc[I].Dsc.empty() == true)
  463. continue;
  464. // See if the package is already unpacked
  465. struct stat Stat;
  466. if (fixBroken == false && stat(Dir.c_str(),&Stat) == 0 &&
  467. S_ISDIR(Stat.st_mode) != 0)
  468. {
  469. ioprintf(c0out ,_("Skipping unpack of already unpacked source in %s\n"),
  470. Dir.c_str());
  471. }
  472. else
  473. {
  474. // Call dpkg-source
  475. std::string const sourceopts = _config->Find("DPkg::Source-Options", "-x");
  476. std::string S;
  477. strprintf(S, "%s %s %s",
  478. _config->Find("Dir::Bin::dpkg-source","dpkg-source").c_str(),
  479. sourceopts.c_str(), Dsc[I].Dsc.c_str());
  480. if (system(S.c_str()) != 0)
  481. {
  482. fprintf(stderr, _("Unpack command '%s' failed.\n"), S.c_str());
  483. fprintf(stderr, _("Check if the 'dpkg-dev' package is installed.\n"));
  484. _exit(1);
  485. }
  486. }
  487. // Try to compile it with dpkg-buildpackage
  488. if (_config->FindB("APT::Get::Compile",false) == true)
  489. {
  490. std::string buildopts = _config->Find("APT::Get::Host-Architecture");
  491. if (buildopts.empty() == false)
  492. buildopts = "-a" + buildopts + " ";
  493. // get all active build profiles
  494. std::string const profiles = APT::Configuration::getBuildProfilesString();
  495. if (profiles.empty() == false)
  496. buildopts.append(" -P").append(profiles).append(" ");
  497. buildopts.append(_config->Find("DPkg::Build-Options","-b -uc"));
  498. // Call dpkg-buildpackage
  499. std::string S;
  500. strprintf(S, "cd %s && %s %s",
  501. Dir.c_str(),
  502. _config->Find("Dir::Bin::dpkg-buildpackage","dpkg-buildpackage").c_str(),
  503. buildopts.c_str());
  504. if (system(S.c_str()) != 0)
  505. {
  506. fprintf(stderr, _("Build command '%s' failed.\n"), S.c_str());
  507. _exit(1);
  508. }
  509. }
  510. }
  511. _exit(0);
  512. }
  513. return ExecWait(Process, "dpkg-source");
  514. }
  515. /*}}}*/
  516. // DoBuildDep - Install/removes packages to satisfy build dependencies /*{{{*/
  517. // ---------------------------------------------------------------------
  518. /* This function will look at the build depends list of the given source
  519. package and install the necessary packages to make it true, or fail. */
  520. static std::vector<pkgSrcRecords::Parser::BuildDepRec> GetBuildDeps(pkgSrcRecords::Parser * const Last,
  521. char const * const Src, bool const StripMultiArch, std::string const &hostArch)
  522. {
  523. std::vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
  524. // FIXME: Can't specify architecture to use for [wildcard] matching, so switch default arch temporary
  525. if (hostArch.empty() == false)
  526. {
  527. std::string nativeArch = _config->Find("APT::Architecture");
  528. _config->Set("APT::Architecture", hostArch);
  529. bool Success = Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch);
  530. _config->Set("APT::Architecture", nativeArch);
  531. if (Success == false)
  532. {
  533. _error->Error(_("Unable to get build-dependency information for %s"), Src);
  534. return {};
  535. }
  536. }
  537. else if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch) == false)
  538. {
  539. _error->Error(_("Unable to get build-dependency information for %s"), Src);
  540. return {};
  541. }
  542. if (BuildDeps.empty() == true)
  543. ioprintf(c1out,_("%s has no build depends.\n"), Src);
  544. return BuildDeps;
  545. }
  546. static void WriteBuildDependencyPackage(std::ostringstream &buildDepsPkgFile,
  547. std::string const &PkgName, std::string const &Arch,
  548. std::vector<pkgSrcRecords::Parser::BuildDepRec> const &Dependencies)
  549. {
  550. buildDepsPkgFile << "Package: " << PkgName << "\n"
  551. << "Architecture: " << Arch << "\n"
  552. << "Version: 1\n";
  553. std::string depends, conflicts;
  554. for (auto const &dep: Dependencies)
  555. {
  556. std::string * type;
  557. if (dep.Type == pkgSrcRecords::Parser::BuildConflict || dep.Type == pkgSrcRecords::Parser::BuildConflictIndep)
  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<char const *> 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. char const * const Src = VolatileCmdL[i];
  632. if (DirectoryExists(Src))
  633. ioprintf(c1out, _("Note, using directory '%s' to get the build dependencies\n"), Src);
  634. else
  635. ioprintf(c1out, _("Note, using file '%s' to get the build dependencies\n"), Src);
  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);
  639. std::string const pseudo = std::string("builddeps:") + Src;
  640. WriteBuildDependencyPackage(buildDepsPkgFile, pseudo, pseudoArch,
  641. GetBuildDeps(Last.get(), Src, 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. if (CmdL.FileList[1] != 0)
  651. {
  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. bool WantLock = _config->FindB("APT::Get::Print-URIs", false) == false;
  670. if (Cache.Open(WantLock) == false)
  671. return false;
  672. pkgProblemResolver Fix(Cache.GetDepCache());
  673. APT::PackageVector removeAgain;
  674. {
  675. pkgDepCache::ActionGroup group(Cache);
  676. TryToInstall InstallAction(Cache, &Fix, false);
  677. for (auto const &pkg: pseudoPkgs)
  678. {
  679. pkgCache::PkgIterator const Pkg = Cache->FindPkg(pkg.first, pkg.second);
  680. if (Pkg.end())
  681. continue;
  682. Cache->SetCandidateVersion(Pkg.VersionList());
  683. InstallAction(Cache[Pkg].CandidateVerIter(Cache));
  684. removeAgain.push_back(Pkg);
  685. }
  686. InstallAction.doAutoInstall();
  687. OpTextProgress Progress(*_config);
  688. bool const resolver_fail = Fix.Resolve(true, &Progress);
  689. if (resolver_fail == false && Cache->BrokenCount() == 0)
  690. return false;
  691. if (CheckNothingBroken(Cache) == false)
  692. return false;
  693. }
  694. if (DoAutomaticRemove(Cache) == false)
  695. return false;
  696. {
  697. pkgDepCache::ActionGroup group(Cache);
  698. for (auto const &pkg: removeAgain)
  699. Cache->MarkDelete(pkg, false, 0, true);
  700. }
  701. pseudoPkgs.clear();
  702. if (_error->PendingError() || InstallPackages(Cache, false, true) == false)
  703. return _error->Error(_("Failed to process build dependencies"));
  704. return true;
  705. }
  706. /*}}}*/