]> git.saurik.com Git - apt.git/blame - apt-private/private-source.cc
rred: Use buffered writes
[apt.git] / apt-private / private-source.cc
CommitLineData
9055d5e6
DK
1// Include Files /*{{{*/
2#include <config.h>
3
4#include <apt-pkg/acquire-item.h>
5#include <apt-pkg/acquire.h>
6#include <apt-pkg/algorithms.h>
7#include <apt-pkg/aptconfiguration.h>
8#include <apt-pkg/cachefile.h>
9#include <apt-pkg/cacheiterators.h>
10#include <apt-pkg/cacheset.h>
11#include <apt-pkg/cmndline.h>
12#include <apt-pkg/configuration.h>
13#include <apt-pkg/depcache.h>
14#include <apt-pkg/error.h>
15#include <apt-pkg/fileutl.h>
16#include <apt-pkg/hashes.h>
17#include <apt-pkg/indexfile.h>
18#include <apt-pkg/metaindex.h>
19#include <apt-pkg/pkgcache.h>
20#include <apt-pkg/sourcelist.h>
21#include <apt-pkg/srcrecords.h>
22#include <apt-pkg/strutl.h>
23#include <apt-pkg/version.h>
24
25#include <apt-private/private-cachefile.h>
26#include <apt-private/private-cacheset.h>
27#include <apt-private/private-download.h>
28#include <apt-private/private-install.h>
29#include <apt-private/private-source.h>
30
31#include <stddef.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/stat.h>
36#include <unistd.h>
37
38#include <iostream>
39#include <set>
40#include <string>
41#include <vector>
42
43#include <apti18n.h>
44 /*}}}*/
45
46// TryToInstallBuildDep - Try to install a single package /*{{{*/
47// ---------------------------------------------------------------------
48/* This used to be inlined in DoInstall, but with the advent of regex package
49 name matching it was split out.. */
50static bool TryToInstallBuildDep(pkgCache::PkgIterator Pkg,pkgCacheFile &Cache,
51 pkgProblemResolver &Fix,bool Remove,bool BrokenFix,
52 bool AllowFail = true)
53{
54 if (Cache[Pkg].CandidateVer == 0 && Pkg->ProvidesList != 0)
55 {
56 CacheSetHelperAPTGet helper(c1out);
57 helper.showErrors(false);
58 pkgCache::VerIterator Ver = helper.canNotFindNewestVer(Cache, Pkg);
59 if (Ver.end() == false)
60 Pkg = Ver.ParentPkg();
61 else if (helper.showVirtualPackageErrors(Cache) == false)
62 return AllowFail;
63 }
64
65 if (_config->FindB("Debug::BuildDeps",false) == true)
66 {
67 if (Remove == true)
68 std::cout << " Trying to remove " << Pkg << std::endl;
69 else
70 std::cout << " Trying to install " << Pkg << std::endl;
71 }
72
73 if (Remove == true)
74 {
75 TryToRemove RemoveAction(Cache, &Fix);
76 RemoveAction(Pkg.VersionList());
77 } else if (Cache[Pkg].CandidateVer != 0) {
78 TryToInstall InstallAction(Cache, &Fix, BrokenFix);
79 InstallAction(Cache[Pkg].CandidateVerIter(Cache));
80 InstallAction.doAutoInstall();
81 } else
82 return AllowFail;
83
84 return true;
85}
86 /*}}}*/
87// GetReleaseFileForSourceRecord - Return Suite for the given srcrecord /*{{{*/
88static pkgCache::RlsFileIterator GetReleaseFileForSourceRecord(CacheFile &CacheFile,
89 pkgSourceList *SrcList, pkgSrcRecords::Parser *Parse)
90{
91 // try to find release
92 const pkgIndexFile& CurrentIndexFile = Parse->Index();
93
94 for (pkgSourceList::const_iterator S = SrcList->begin();
95 S != SrcList->end(); ++S)
96 {
97 std::vector<pkgIndexFile *> *Indexes = (*S)->GetIndexFiles();
98 for (std::vector<pkgIndexFile *>::const_iterator IF = Indexes->begin();
99 IF != Indexes->end(); ++IF)
100 {
101 if (&CurrentIndexFile == (*IF))
102 return (*S)->FindInCache(CacheFile, false);
103 }
104 }
105 return pkgCache::RlsFileIterator(CacheFile);
106}
107 /*}}}*/
108// FindSrc - Find a source record /*{{{*/
109static pkgSrcRecords::Parser *FindSrc(const char *Name,
110 pkgSrcRecords &SrcRecs,std::string &Src,
111 CacheFile &CacheFile)
112{
113 std::string VerTag, UserRequestedVerTag;
114 std::string ArchTag = "";
115 std::string RelTag = _config->Find("APT::Default-Release");
116 std::string TmpSrc = Name;
117 pkgDepCache *Cache = CacheFile.GetDepCache();
118
119 // extract release
120 size_t found = TmpSrc.find_last_of("/");
121 if (found != std::string::npos)
122 {
123 RelTag = TmpSrc.substr(found+1);
124 TmpSrc = TmpSrc.substr(0,found);
125 }
126 // extract the version
127 found = TmpSrc.find_last_of("=");
128 if (found != std::string::npos)
129 {
130 VerTag = UserRequestedVerTag = TmpSrc.substr(found+1);
131 TmpSrc = TmpSrc.substr(0,found);
132 }
133 // extract arch
134 found = TmpSrc.find_last_of(":");
135 if (found != std::string::npos)
136 {
137 ArchTag = TmpSrc.substr(found+1);
138 TmpSrc = TmpSrc.substr(0,found);
139 }
140
141 /* Lookup the version of the package we would install if we were to
142 install a version and determine the source package name, then look
143 in the archive for a source package of the same name. */
144 bool MatchSrcOnly = _config->FindB("APT::Get::Only-Source");
145 pkgCache::PkgIterator Pkg;
146 if (ArchTag != "")
147 Pkg = Cache->FindPkg(TmpSrc, ArchTag);
148 else
149 Pkg = Cache->FindPkg(TmpSrc);
150
151 // if we can't find a package but the user qualified with a arch,
152 // error out here
153 if (Pkg.end() && ArchTag != "")
154 {
155 Src = Name;
156 _error->Error(_("Can not find a package for architecture '%s'"),
157 ArchTag.c_str());
158 return 0;
159 }
160
161 if (MatchSrcOnly == false && Pkg.end() == false)
162 {
163 if(VerTag != "" || RelTag != "" || ArchTag != "")
164 {
165 bool fuzzy = false;
166 // we have a default release, try to locate the pkg. we do it like
167 // this because GetCandidateVer() will not "downgrade", that means
168 // "apt-get source -t stable apt" won't work on a unstable system
169 for (pkgCache::VerIterator Ver = Pkg.VersionList();; ++Ver)
170 {
171 // try first only exact matches, later fuzzy matches
172 if (Ver.end() == true)
173 {
174 if (fuzzy == true)
175 break;
176 fuzzy = true;
177 Ver = Pkg.VersionList();
178 // exit right away from the Pkg.VersionList() loop if we
179 // don't have any versions
180 if (Ver.end() == true)
181 break;
182 }
183
184 // ignore arches that are not for us
185 if (ArchTag != "" && Ver.Arch() != ArchTag)
186 continue;
187
188 // pick highest version for the arch unless the user wants
189 // something else
190 if (ArchTag != "" && VerTag == "" && RelTag == "")
191 if(Cache->VS().CmpVersion(VerTag, Ver.VerStr()) < 0)
192 VerTag = Ver.VerStr();
193
194 // We match against a concrete version (or a part of this version)
195 if (VerTag.empty() == false &&
196 (fuzzy == true || Cache->VS().CmpVersion(VerTag, Ver.VerStr()) != 0) && // exact match
197 (fuzzy == false || strncmp(VerTag.c_str(), Ver.VerStr(), VerTag.size()) != 0)) // fuzzy match
198 continue;
199
200 for (pkgCache::VerFileIterator VF = Ver.FileList();
201 VF.end() == false; ++VF)
202 {
203 /* If this is the status file, and the current version is not the
204 version in the status file (ie it is not installed, or somesuch)
205 then it is not a candidate for installation, ever. This weeds
206 out bogus entries that may be due to config-file states, or
207 other. */
208 if ((VF.File()->Flags & pkgCache::Flag::NotSource) ==
209 pkgCache::Flag::NotSource && Pkg.CurrentVer() != Ver)
210 continue;
211
212 // or we match against a release
213 if(VerTag.empty() == false ||
214 (VF.File().Archive() != 0 && VF.File().Archive() == RelTag) ||
215 (VF.File().Codename() != 0 && VF.File().Codename() == RelTag))
216 {
217 // the Version we have is possibly fuzzy or includes binUploads,
218 // so we use the Version of the SourcePkg (empty if same as package)
219 Src = Ver.SourcePkgName();
220 VerTag = Ver.SourceVerStr();
221 break;
222 }
223 }
224 if (Src.empty() == false)
225 break;
226 }
227 }
228
229 if (Src == "" && ArchTag != "")
230 {
231 if (VerTag != "")
232 _error->Error(_("Can not find a package '%s' with version '%s'"),
233 Pkg.FullName().c_str(), VerTag.c_str());
234 if (RelTag != "")
235 _error->Error(_("Can not find a package '%s' with release '%s'"),
236 Pkg.FullName().c_str(), RelTag.c_str());
237 Src = Name;
238 return 0;
239 }
240
241
242 if (Src.empty() == true)
243 {
244 // if we don't have found a fitting package yet so we will
245 // choose a good candidate and proceed with that.
246 // Maybe we will find a source later on with the right VerTag
247 // or RelTag
294a8020
DK
248 pkgCache::VerIterator const Ver = Cache->GetCandidateVersion(Pkg);
249 if (Ver.end() == false)
9055d5e6
DK
250 {
251 if (strcmp(Ver.SourcePkgName(),Ver.ParentPkg().Name()) != 0)
252 Src = Ver.SourcePkgName();
253 if (VerTag.empty() == true && strcmp(Ver.SourceVerStr(),Ver.VerStr()) != 0)
254 VerTag = Ver.SourceVerStr();
255 }
256 }
257 }
258
259 if (Src.empty() == true)
260 {
261 Src = TmpSrc;
262 }
263 else
264 {
265 /* if we have a source pkg name, make sure to only search
266 for srcpkg names, otherwise apt gets confused if there
267 is a binary package "pkg1" and a source package "pkg1"
268 with the same name but that comes from different packages */
269 MatchSrcOnly = true;
270 if (Src != TmpSrc)
271 {
272 ioprintf(c1out, _("Picking '%s' as source package instead of '%s'\n"), Src.c_str(), TmpSrc.c_str());
273 }
274 }
275
276 // The best hit
277 pkgSrcRecords::Parser *Last = 0;
278 unsigned long Offset = 0;
279 std::string Version;
280 pkgSourceList *SrcList = CacheFile.GetSourceList();
281
282 /* Iterate over all of the hits, which includes the resulting
283 binary packages in the search */
284 pkgSrcRecords::Parser *Parse;
285 while (true)
286 {
287 SrcRecs.Restart();
288 while ((Parse = SrcRecs.Find(Src.c_str(), MatchSrcOnly)) != 0)
289 {
290 const std::string Ver = Parse->Version();
321213f0 291 bool CorrectRelTag = false;
9055d5e6
DK
292
293 // See if we need to look for a specific release tag
294 if (RelTag != "" && UserRequestedVerTag == "")
295 {
296 pkgCache::RlsFileIterator const Rls = GetReleaseFileForSourceRecord(CacheFile, SrcList, Parse);
297 if (Rls.end() == false)
298 {
299 if ((Rls->Archive != 0 && RelTag == Rls.Archive()) ||
300 (Rls->Codename != 0 && RelTag == Rls.Codename()))
321213f0 301 CorrectRelTag = true;
9055d5e6 302 }
321213f0
AC
303 } else
304 CorrectRelTag = true;
9055d5e6
DK
305
306 // Ignore all versions which doesn't fit
307 if (VerTag.empty() == false &&
308 Cache->VS().CmpVersion(VerTag, Ver) != 0) // exact match
309 continue;
310
311 // Newer version or an exact match? Save the hit
321213f0 312 if (CorrectRelTag && (Last == 0 || Cache->VS().CmpVersion(Version,Ver) < 0)) {
9055d5e6
DK
313 Last = Parse;
314 Offset = Parse->Offset();
315 Version = Ver;
316 }
317
318 // was the version check above an exact match?
319 // If so, we don't need to look further
320 if (VerTag.empty() == false && (VerTag == Ver))
321 break;
322 }
323 if (UserRequestedVerTag == "" && Version != "" && RelTag != "")
324 ioprintf(c1out, "Selected version '%s' (%s) for %s\n",
325 Version.c_str(), RelTag.c_str(), Src.c_str());
326
327 if (Last != 0 || VerTag.empty() == true)
328 break;
329 _error->Error(_("Can not find version '%s' of package '%s'"), VerTag.c_str(), TmpSrc.c_str());
330 return 0;
331 }
332
333 if (Last == 0 || Last->Jump(Offset) == false)
334 return 0;
335
336 return Last;
337}
338 /*}}}*/
339// DoSource - Fetch a source archive /*{{{*/
340// ---------------------------------------------------------------------
341/* Fetch souce packages */
342struct DscFile
343{
344 std::string Package;
345 std::string Version;
346 std::string Dsc;
347};
348bool DoSource(CommandLine &CmdL)
349{
350 CacheFile Cache;
351 if (Cache.Open(false) == false)
352 return false;
353
354 if (CmdL.FileSize() <= 1)
355 return _error->Error(_("Must specify at least one package to fetch source for"));
356
357 // Read the source list
358 if (Cache.BuildSourceList() == false)
359 return false;
360 pkgSourceList *List = Cache.GetSourceList();
361
362 // Create the text record parsers
363 pkgSrcRecords SrcRecs(*List);
364 if (_error->PendingError() == true)
365 return false;
366
367 std::unique_ptr<DscFile[]> Dsc(new DscFile[CmdL.FileSize()]);
368
369 // insert all downloaded uris into this set to avoid downloading them
370 // twice
371 std::set<std::string> queued;
372
373 // Diff only mode only fetches .diff files
374 bool const diffOnly = _config->FindB("APT::Get::Diff-Only", false);
375 // Tar only mode only fetches .tar files
376 bool const tarOnly = _config->FindB("APT::Get::Tar-Only", false);
377 // Dsc only mode only fetches .dsc files
378 bool const dscOnly = _config->FindB("APT::Get::Dsc-Only", false);
379
380 // Load the requestd sources into the fetcher
381 aptAcquireWithTextStatus Fetcher;
382 unsigned J = 0;
383 std::vector<std::string> UntrustedList;
384 for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++)
385 {
386 std::string Src;
387 pkgSrcRecords::Parser *Last = FindSrc(*I,SrcRecs,Src,Cache);
388 if (Last == 0) {
389 return _error->Error(_("Unable to find a source package for %s"),Src.c_str());
390 }
391
392 if (Last->Index().IsTrusted() == false)
393 UntrustedList.push_back(Src);
394
395 std::string srec = Last->AsStr();
396 std::string::size_type pos = srec.find("\nVcs-");
397 while (pos != std::string::npos)
398 {
399 pos += strlen("\nVcs-");
400 std::string vcs = srec.substr(pos,srec.find(":",pos)-pos);
401 if(vcs == "Browser")
402 {
403 pos = srec.find("\nVcs-", pos);
404 continue;
405 }
406 pos += vcs.length()+2;
407 std::string::size_type epos = srec.find("\n", pos);
408 std::string const uri = srec.substr(pos,epos-pos);
409 ioprintf(c1out, _("NOTICE: '%s' packaging is maintained in "
410 "the '%s' version control system at:\n"
411 "%s\n"),
412 Src.c_str(), vcs.c_str(), uri.c_str());
413 std::string vcscmd;
414 if (vcs == "Bzr")
415 vcscmd = "bzr branch " + uri;
416 else if (vcs == "Git")
417 vcscmd = "git clone " + uri;
418
419 if (vcscmd.empty() == false)
420 ioprintf(c1out,_("Please use:\n%s\n"
421 "to retrieve the latest (possibly unreleased) "
422 "updates to the package.\n"),
423 vcscmd.c_str());
424 break;
425 }
426
427 // Back track
428 std::vector<pkgSrcRecords::File2> Lst;
429 if (Last->Files2(Lst) == false) {
430 return false;
431 }
432
433 // Load them into the fetcher
434 for (std::vector<pkgSrcRecords::File2>::const_iterator I = Lst.begin();
435 I != Lst.end(); ++I)
436 {
437 // Try to guess what sort of file it is we are getting.
438 if (I->Type == "dsc")
439 {
440 Dsc[J].Package = Last->Package();
441 Dsc[J].Version = Last->Version();
442 Dsc[J].Dsc = flNotDir(I->Path);
443 }
444
445 // Handle the only options so that multiple can be used at once
446 if (diffOnly == true || tarOnly == true || dscOnly == true)
447 {
448 if ((diffOnly == true && I->Type == "diff") ||
449 (tarOnly == true && I->Type == "tar") ||
450 (dscOnly == true && I->Type == "dsc"))
451 ; // Fine, we want this file downloaded
452 else
453 continue;
454 }
455
456 // don't download the same uri twice (should this be moved to
457 // the fetcher interface itself?)
458 if(queued.find(Last->Index().ArchiveURI(I->Path)) != queued.end())
459 continue;
460 queued.insert(Last->Index().ArchiveURI(I->Path));
461
462 // check if we have a file with that md5 sum already localy
463 std::string localFile = flNotDir(I->Path);
464 if (FileExists(localFile) == true)
465 if(I->Hashes.VerifyFile(localFile) == true)
466 {
467 ioprintf(c1out,_("Skipping already downloaded file '%s'\n"),
468 localFile.c_str());
469 continue;
470 }
471
472 // see if we have a hash (Acquire::ForceHash is the only way to have none)
473 if (I->Hashes.usable() == false && _config->FindB("APT::Get::AllowUnauthenticated",false) == false)
474 {
475 ioprintf(c1out, "Skipping download of file '%s' as requested hashsum is not available for authentication\n",
476 localFile.c_str());
477 continue;
478 }
479
480 new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
481 I->Hashes, I->FileSize, Last->Index().SourceInfo(*Last,*I), Src);
482 }
483 }
484
485 // Display statistics
486 unsigned long long FetchBytes = Fetcher.FetchNeeded();
487 unsigned long long FetchPBytes = Fetcher.PartialPresent();
488 unsigned long long DebBytes = Fetcher.TotalNeeded();
489
490 if (CheckFreeSpaceBeforeDownload(".", (FetchBytes - FetchPBytes)) == false)
491 return false;
492
493 // Number of bytes
494 if (DebBytes != FetchBytes)
495 //TRANSLATOR: The required space between number and unit is already included
496 // in the replacement strings, so %sB will be correctly translate in e.g. 1,5 MB
497 ioprintf(c1out,_("Need to get %sB/%sB of source archives.\n"),
498 SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str());
499 else
500 //TRANSLATOR: The required space between number and unit is already included
501 // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB
502 ioprintf(c1out,_("Need to get %sB of source archives.\n"),
503 SizeToStr(DebBytes).c_str());
504
505 if (_config->FindB("APT::Get::Simulate",false) == true)
506 {
507 for (unsigned I = 0; I != J; I++)
508 ioprintf(std::cout,_("Fetch source %s\n"),Dsc[I].Package.c_str());
509 return true;
510 }
511
512 // Just print out the uris an exit if the --print-uris flag was used
513 if (_config->FindB("APT::Get::Print-URIs") == true)
514 {
515 pkgAcquire::UriIterator I = Fetcher.UriBegin();
516 for (; I != Fetcher.UriEnd(); ++I)
517 std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' <<
518 I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl;
519 return true;
520 }
521
522 // check authentication status of the source as well
523 if (UntrustedList.empty() == false && AuthPrompt(UntrustedList, false) == false)
524 return false;
525
526 // Run it
527 bool Failed = false;
528 if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true)
529 {
530 return _error->Error(_("Failed to fetch some archives."));
531 }
532
533 if (_config->FindB("APT::Get::Download-only",false) == true)
534 {
535 c1out << _("Download complete and in download only mode") << std::endl;
536 return true;
537 }
538
539 // Unpack the sources
540 pid_t Process = ExecFork();
541
542 if (Process == 0)
543 {
544 bool const fixBroken = _config->FindB("APT::Get::Fix-Broken", false);
545 for (unsigned I = 0; I != J; ++I)
546 {
547 std::string Dir = Dsc[I].Package + '-' + Cache->VS().UpstreamVersion(Dsc[I].Version.c_str());
548
549 // Diff only mode only fetches .diff files
550 if (_config->FindB("APT::Get::Diff-Only",false) == true ||
551 _config->FindB("APT::Get::Tar-Only",false) == true ||
552 Dsc[I].Dsc.empty() == true)
553 continue;
554
555 // See if the package is already unpacked
556 struct stat Stat;
557 if (fixBroken == false && stat(Dir.c_str(),&Stat) == 0 &&
558 S_ISDIR(Stat.st_mode) != 0)
559 {
560 ioprintf(c0out ,_("Skipping unpack of already unpacked source in %s\n"),
561 Dir.c_str());
562 }
563 else
564 {
565 // Call dpkg-source
566 std::string const sourceopts = _config->Find("DPkg::Source-Options", "-x");
567 std::string S;
568 strprintf(S, "%s %s %s",
569 _config->Find("Dir::Bin::dpkg-source","dpkg-source").c_str(),
570 sourceopts.c_str(), Dsc[I].Dsc.c_str());
571 if (system(S.c_str()) != 0)
572 {
573 fprintf(stderr, _("Unpack command '%s' failed.\n"), S.c_str());
574 fprintf(stderr, _("Check if the 'dpkg-dev' package is installed.\n"));
575 _exit(1);
576 }
577 }
578
579 // Try to compile it with dpkg-buildpackage
580 if (_config->FindB("APT::Get::Compile",false) == true)
581 {
582 std::string buildopts = _config->Find("APT::Get::Host-Architecture");
583 if (buildopts.empty() == false)
584 buildopts = "-a" + buildopts + " ";
585
586 // get all active build profiles
587 std::string const profiles = APT::Configuration::getBuildProfilesString();
588 if (profiles.empty() == false)
589 buildopts.append(" -P").append(profiles).append(" ");
590
591 buildopts.append(_config->Find("DPkg::Build-Options","-b -uc"));
592
593 // Call dpkg-buildpackage
594 std::string S;
595 strprintf(S, "cd %s && %s %s",
596 Dir.c_str(),
597 _config->Find("Dir::Bin::dpkg-buildpackage","dpkg-buildpackage").c_str(),
598 buildopts.c_str());
599
600 if (system(S.c_str()) != 0)
601 {
602 fprintf(stderr, _("Build command '%s' failed.\n"), S.c_str());
603 _exit(1);
604 }
605 }
606 }
607
608 _exit(0);
609 }
610
611 return ExecWait(Process, "dpkg-source");
612}
613 /*}}}*/
aa368243
DK
614// InstallBuildDepsLoop /*{{{*/
615static bool InstallBuildDepsLoop(CacheFile &Cache, std::string const &Src,
616 std::vector<pkgSrcRecords::Parser::BuildDepRec> const &BuildDeps,
617 bool const StripMultiArch, std::string const &hostArch)
618{
619 // Install the requested packages
620 std::vector <pkgSrcRecords::Parser::BuildDepRec>::const_iterator D;
621 pkgProblemResolver Fix(Cache);
622 bool skipAlternatives = false; // skip remaining alternatives in an or group
623 for (D = BuildDeps.begin(); D != BuildDeps.end(); ++D)
624 {
625 bool hasAlternatives = (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or);
626
627 if (skipAlternatives == true)
628 {
629 /*
630 * if there are alternatives, we've already picked one, so skip
631 * the rest
632 *
633 * TODO: this means that if there's a build-dep on A|B and B is
634 * installed, we'll still try to install A; more importantly,
635 * if A is currently broken, we cannot go back and try B. To fix
636 * this would require we do a Resolve cycle for each package we
637 * add to the install list. Ugh
638 */
639 if (!hasAlternatives)
640 skipAlternatives = false; // end of or group
641 continue;
642 }
643
644 if ((*D).Type == pkgSrcRecords::Parser::BuildConflict ||
645 (*D).Type == pkgSrcRecords::Parser::BuildConflictIndep)
646 {
647 pkgCache::GrpIterator Grp = Cache->FindGrp((*D).Package);
648 // Build-conflicts on unknown packages are silently ignored
649 if (Grp.end() == true)
650 continue;
651
652 for (pkgCache::PkgIterator Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
653 {
654 pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
655 /*
656 * Remove if we have an installed version that satisfies the
657 * version criteria
658 */
659 if (IV.end() == false &&
660 Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
661 TryToInstallBuildDep(Pkg,Cache,Fix,true,false);
662 }
663 }
664 else // BuildDep || BuildDepIndep
665 {
666 if (_config->FindB("Debug::BuildDeps",false) == true)
667 std::cout << "Looking for " << (*D).Package << "...\n";
668
669 pkgCache::PkgIterator Pkg;
670
671 // Cross-Building?
672 if (StripMultiArch == false && D->Type != pkgSrcRecords::Parser::BuildDependIndep)
673 {
674 size_t const colon = D->Package.find(":");
675 if (colon != std::string::npos)
676 {
677 if (strcmp(D->Package.c_str() + colon, ":any") == 0 || strcmp(D->Package.c_str() + colon, ":native") == 0)
678 Pkg = Cache->FindPkg(D->Package.substr(0,colon));
679 else
680 Pkg = Cache->FindPkg(D->Package);
681 }
682 else
683 Pkg = Cache->FindPkg(D->Package, hostArch);
684
685 // a bad version either is invalid or doesn't satify dependency
686#define BADVER(Ver) (Ver.end() == true || \
687 (D->Version.empty() == false && \
688 Cache->VS().CheckDep(Ver.VerStr(),D->Op,D->Version.c_str()) == false))
689
690 APT::VersionList verlist;
691 if (Pkg.end() == false)
692 {
693 pkgCache::VerIterator Ver = (*Cache)[Pkg].InstVerIter(*Cache);
694 if (BADVER(Ver) == false)
695 verlist.insert(Ver);
696 Ver = (*Cache)[Pkg].CandidateVerIter(*Cache);
697 if (BADVER(Ver) == false)
698 verlist.insert(Ver);
699 }
700 if (verlist.empty() == true)
701 {
702 pkgCache::PkgIterator BuildPkg = Cache->FindPkg(D->Package, "native");
703 if (BuildPkg.end() == false && Pkg != BuildPkg)
704 {
705 pkgCache::VerIterator Ver = (*Cache)[BuildPkg].InstVerIter(*Cache);
706 if (BADVER(Ver) == false)
707 verlist.insert(Ver);
708 Ver = (*Cache)[BuildPkg].CandidateVerIter(*Cache);
709 if (BADVER(Ver) == false)
710 verlist.insert(Ver);
711 }
712 }
713#undef BADVER
714
715 std::string forbidden;
716 // We need to decide if host or build arch, so find a version we can look at
717 APT::VersionList::const_iterator Ver = verlist.begin();
718 for (; Ver != verlist.end(); ++Ver)
719 {
720 forbidden.clear();
721 if (Ver->MultiArch == pkgCache::Version::No || Ver->MultiArch == pkgCache::Version::All)
722 {
723 if (colon == std::string::npos)
724 Pkg = Ver.ParentPkg().Group().FindPkg(hostArch);
725 else if (strcmp(D->Package.c_str() + colon, ":any") == 0)
726 forbidden = "Multi-Arch: no";
727 else if (strcmp(D->Package.c_str() + colon, ":native") == 0)
728 Pkg = Ver.ParentPkg().Group().FindPkg("native");
729 }
730 else if (Ver->MultiArch == pkgCache::Version::Same)
731 {
732 if (colon == std::string::npos)
733 Pkg = Ver.ParentPkg().Group().FindPkg(hostArch);
734 else if (strcmp(D->Package.c_str() + colon, ":any") == 0)
735 forbidden = "Multi-Arch: same";
736 else if (strcmp(D->Package.c_str() + colon, ":native") == 0)
737 Pkg = Ver.ParentPkg().Group().FindPkg("native");
738 }
739 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
740 {
741 if (colon == std::string::npos)
742 Pkg = Ver.ParentPkg().Group().FindPkg("native");
743 else if (strcmp(D->Package.c_str() + colon, ":any") == 0 ||
744 strcmp(D->Package.c_str() + colon, ":native") == 0)
745 forbidden = "Multi-Arch: foreign";
746 }
747 else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
748 {
749 if (colon == std::string::npos)
750 Pkg = Ver.ParentPkg().Group().FindPkg(hostArch);
751 else if (strcmp(D->Package.c_str() + colon, ":any") == 0)
752 {
753 // prefer any installed over preferred non-installed architectures
754 pkgCache::GrpIterator Grp = Ver.ParentPkg().Group();
755 // we don't check for version here as we are better of with upgrading than remove and install
756 for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
757 if (Pkg.CurrentVer().end() == false)
758 break;
759 if (Pkg.end() == true)
760 Pkg = Grp.FindPreferredPkg(true);
761 }
762 else if (strcmp(D->Package.c_str() + colon, ":native") == 0)
763 Pkg = Ver.ParentPkg().Group().FindPkg("native");
764 }
765
766 if (forbidden.empty() == false)
767 {
768 if (_config->FindB("Debug::BuildDeps",false) == true)
769 std::cout << D->Package.substr(colon, std::string::npos) << " is not allowed from " << forbidden << " package " << (*D).Package << " (" << Ver.VerStr() << ")" << std::endl;
770 continue;
771 }
772
773 //we found a good version
774 break;
775 }
776 if (Ver == verlist.end())
777 {
778 if (_config->FindB("Debug::BuildDeps",false) == true)
779 std::cout << " No multiarch info as we have no satisfying installed nor candidate for " << D->Package << " on build or host arch" << std::endl;
780
781 if (forbidden.empty() == false)
782 {
783 if (hasAlternatives)
784 continue;
785 return _error->Error(_("%s dependency for %s can't be satisfied "
786 "because %s is not allowed on '%s' packages"),
787 pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(),
788 D->Package.c_str(), forbidden.c_str());
789 }
790 }
791 }
792 else
793 Pkg = Cache->FindPkg(D->Package);
794
795 if (Pkg.end() == true || (Pkg->VersionList == 0 && Pkg->ProvidesList == 0))
796 {
797 if (_config->FindB("Debug::BuildDeps",false) == true)
798 std::cout << " (not found)" << (*D).Package << std::endl;
799
800 if (hasAlternatives)
801 continue;
802
803 return _error->Error(_("%s dependency for %s cannot be satisfied "
804 "because the package %s cannot be found"),
805 pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(),
806 (*D).Package.c_str());
807 }
808
809 pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
810 if (IV.end() == false)
811 {
812 if (_config->FindB("Debug::BuildDeps",false) == true)
813 std::cout << " Is installed\n";
814
815 if (D->Version.empty() == true ||
816 Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
817 {
818 skipAlternatives = hasAlternatives;
819 continue;
820 }
821
822 if (_config->FindB("Debug::BuildDeps",false) == true)
823 std::cout << " ...but the installed version doesn't meet the version requirement\n";
824
825 if (((*D).Op & pkgCache::Dep::LessEq) == pkgCache::Dep::LessEq)
826 return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"),
827 pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(), Pkg.FullName(true).c_str());
828 }
829
830 // Only consider virtual packages if there is no versioned dependency
831 if ((*D).Version.empty() == true)
832 {
833 /*
834 * If this is a virtual package, we need to check the list of
835 * packages that provide it and see if any of those are
836 * installed
837 */
838 pkgCache::PrvIterator Prv = Pkg.ProvidesList();
839 for (; Prv.end() != true; ++Prv)
840 {
841 if (_config->FindB("Debug::BuildDeps",false) == true)
842 std::cout << " Checking provider " << Prv.OwnerPkg().FullName() << std::endl;
843
844 if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
845 break;
846 }
847
848 if (Prv.end() == false)
849 {
850 if (_config->FindB("Debug::BuildDeps",false) == true)
851 std::cout << " Is provided by installed package " << Prv.OwnerPkg().FullName() << std::endl;
852 skipAlternatives = hasAlternatives;
853 continue;
854 }
855 }
856 else // versioned dependency
857 {
858 pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
859 if (CV.end() == true ||
860 Cache->VS().CheckDep(CV.VerStr(),(*D).Op,(*D).Version.c_str()) == false)
861 {
862 if (hasAlternatives)
863 continue;
864 else if (CV.end() == false)
865 return _error->Error(_("%s dependency for %s cannot be satisfied "
866 "because candidate version of package %s "
867 "can't satisfy version requirements"),
868 pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(),
869 D->Package.c_str());
870 else
871 return _error->Error(_("%s dependency for %s cannot be satisfied "
872 "because package %s has no candidate version"),
873 pkgSrcRecords::Parser::BuildDepType(D->Type), Src.c_str(),
874 D->Package.c_str());
875 }
876 }
877
878 if (TryToInstallBuildDep(Pkg,Cache,Fix,false,false,false) == true)
879 {
880 // We successfully installed something; skip remaining alternatives
881 skipAlternatives = hasAlternatives;
882 if(_config->FindB("APT::Get::Build-Dep-Automatic", false) == true)
883 Cache->MarkAuto(Pkg, true);
884 continue;
885 }
886 else if (hasAlternatives)
887 {
888 if (_config->FindB("Debug::BuildDeps",false) == true)
889 std::cout << " Unsatisfiable, trying alternatives\n";
890 continue;
891 }
892 else
893 {
894 return _error->Error(_("Failed to satisfy %s dependency for %s: %s"),
895 pkgSrcRecords::Parser::BuildDepType(D->Type),
896 Src.c_str(),
897 (*D).Package.c_str());
898 }
899 }
900 }
901
902 if (Fix.Resolve(true) == false)
903 _error->Discard();
904
905 // Now we check the state of the packages,
906 if (Cache->BrokenCount() != 0)
907 {
908 ShowBroken(std::cout, Cache, false);
909 return _error->Error(_("Build-dependencies for %s could not be satisfied."), Src.c_str());
910 }
911 return true;
912}
913 /*}}}*/
9055d5e6
DK
914// DoBuildDep - Install/removes packages to satisfy build dependencies /*{{{*/
915// ---------------------------------------------------------------------
916/* This function will look at the build depends list of the given source
917 package and install the necessary packages to make it true, or fail. */
f359b7e8
DK
918static std::vector<pkgSrcRecords::Parser::BuildDepRec> GetBuildDeps(pkgSrcRecords::Parser * const Last,
919 char const * const Src, bool const StripMultiArch, std::string const &hostArch)
920{
921 std::vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
922 // FIXME: Can't specify architecture to use for [wildcard] matching, so switch default arch temporary
923 if (hostArch.empty() == false)
924 {
925 std::string nativeArch = _config->Find("APT::Architecture");
926 _config->Set("APT::Architecture", hostArch);
927 bool Success = Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch);
928 _config->Set("APT::Architecture", nativeArch);
929 if (Success == false)
930 {
931 _error->Error(_("Unable to get build-dependency information for %s"), Src);
932 return {};
933 }
934 }
935 else if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch) == false)
936 {
937 _error->Error(_("Unable to get build-dependency information for %s"), Src);
938 return {};
939 }
940
941 if (BuildDeps.empty() == true)
942 ioprintf(c1out,_("%s has no build depends.\n"), Src);
943
944 return BuildDeps;
945}
9055d5e6
DK
946bool DoBuildDep(CommandLine &CmdL)
947{
948 CacheFile Cache;
f359b7e8
DK
949 std::vector<char const *> VolatileCmdL;
950 Cache.GetSourceList()->AddVolatileFiles(CmdL, &VolatileCmdL);
9055d5e6
DK
951
952 _config->Set("APT::Install-Recommends", false);
953
954 bool WantLock = _config->FindB("APT::Get::Print-URIs", false) == false;
955
956 if (Cache.Open(WantLock) == false)
957 return false;
958
f359b7e8 959 if (CmdL.FileSize() <= 1 && VolatileCmdL.empty())
9055d5e6
DK
960 return _error->Error(_("Must specify at least one package to check builddeps for"));
961
962 // Read the source list
963 if (Cache.BuildSourceList() == false)
964 return false;
965 pkgSourceList *List = Cache.GetSourceList();
966
967 // Create the text record parsers
968 pkgSrcRecords SrcRecs(*List);
969 if (_error->PendingError() == true)
970 return false;
971
972 bool StripMultiArch;
973 std::string hostArch = _config->Find("APT::Get::Host-Architecture");
974 if (hostArch.empty() == false)
975 {
976 std::vector<std::string> archs = APT::Configuration::getArchitectures();
977 if (std::find(archs.begin(), archs.end(), hostArch) == archs.end())
978 return _error->Error(_("No architecture information available for %s. See apt.conf(5) APT::Architectures for setup"), hostArch.c_str());
979 StripMultiArch = false;
980 }
981 else
982 StripMultiArch = true;
983
7d19ee92
DK
984 // deal with the build essentials first
985 {
986 std::vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
987
988 Configuration::Item const *Opts = _config->Tree("APT::Build-Essential");
989 if (Opts)
990 Opts = Opts->Child;
991 for (; Opts; Opts = Opts->Next)
992 {
993 if (Opts->Value.empty() == true)
994 continue;
995
996 pkgSrcRecords::Parser::BuildDepRec rec;
997 rec.Package = Opts->Value;
998 rec.Type = pkgSrcRecords::Parser::BuildDependIndep;
999 rec.Op = 0;
1000 BuildDeps.push_back(rec);
1001 }
1002
1003 if (InstallBuildDepsLoop(Cache, "APT::Build-Essential", BuildDeps, StripMultiArch, hostArch) == false)
1004 return false;
1005 }
1006
f359b7e8 1007 // FIXME: Avoid volatile sources == cmdline assumption
9055d5e6 1008 {
f359b7e8
DK
1009 auto const VolatileSources = List->GetVolatileFiles();
1010 if (VolatileSources.size() == VolatileCmdL.size())
9055d5e6 1011 {
f359b7e8
DK
1012 for (size_t i = 0; i < VolatileSources.size(); ++i)
1013 {
1014 char const * const Src = VolatileCmdL[i];
1015 if (DirectoryExists(Src))
1016 ioprintf(c1out, _("Note, using directory '%s' to get the build dependencies\n"), Src);
1017 else
1018 ioprintf(c1out, _("Note, using file '%s' to get the build dependencies\n"), Src);
1019 std::unique_ptr<pkgSrcRecords::Parser> Last(VolatileSources[i]->CreateSrcParser());
1020 if (Last == nullptr)
1021 return _error->Error(_("Unable to find a source package for %s"), Src);
1022
1023 auto const BuildDeps = GetBuildDeps(Last.get(), Src, StripMultiArch, hostArch);
1024 if (InstallBuildDepsLoop(Cache, Src, BuildDeps, StripMultiArch, hostArch) == false)
1025 return false;
1026 }
9055d5e6 1027 }
f359b7e8
DK
1028 else
1029 _error->Error("Implementation error: Volatile sources (%lu) and commandline elements (%lu) do not match!", VolatileSources.size(), VolatileCmdL.size());
1030 }
9055d5e6 1031
f359b7e8
DK
1032 for (const char **I = CmdL.FileList + 1; *I != 0; ++I)
1033 {
1034 std::string Src;
1035 pkgSrcRecords::Parser * const Last = FindSrc(*I,SrcRecs,Src,Cache);
1036 if (Last == nullptr)
1037 return _error->Error(_("Unable to find a source package for %s"), *I);
9055d5e6 1038
f359b7e8 1039 auto const BuildDeps = GetBuildDeps(Last, Src.c_str(), StripMultiArch, hostArch);
aa368243
DK
1040 if (InstallBuildDepsLoop(Cache, Src, BuildDeps, StripMultiArch, hostArch) == false)
1041 return false;
9055d5e6
DK
1042 }
1043
1044 if (InstallPackages(Cache, false, true) == false)
1045 return _error->Error(_("Failed to process build dependencies"));
1046 return true;
1047}
1048 /*}}}*/