+ if (Last == 0)
+ return _error->Error(_("Unable to find a source package for %s"),Src.c_str());
+
+ // Back track
+ vector<pkgSrcRecords::File> Lst;
+ if (Last->Files(Lst) == false)
+ return false;
+
+ // Load them into the fetcher
+ for (vector<pkgSrcRecords::File>::const_iterator I = Lst.begin();
+ I != Lst.end(); I++)
+ {
+ // Try to guess what sort of file it is we are getting.
+ if (I->Type == "dsc")
+ {
+ Dsc[J].Package = Last->Package();
+ Dsc[J].Version = Last->Version();
+ Dsc[J].Dsc = flNotDir(I->Path);
+ }
+
+ // Diff only mode only fetches .diff files
+ if (_config->FindB("APT::Get::Diff-Only",false) == true &&
+ I->Type != "diff")
+ continue;
+
+ // Tar only mode only fetches .tar files
+ if (_config->FindB("APT::Get::Tar-Only",false) == true &&
+ I->Type != "tar")
+ continue;
+
+ new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
+ I->MD5Hash,I->Size,
+ Last->Index().SourceInfo(*Last,*I),Src);
+ }
+ }
+
+ // Display statistics
+ double FetchBytes = Fetcher.FetchNeeded();
+ double FetchPBytes = Fetcher.PartialPresent();
+ double DebBytes = Fetcher.TotalNeeded();
+
+ // Check for enough free space
+ struct statvfs Buf;
+ string OutputDir = ".";
+ if (statvfs(OutputDir.c_str(),&Buf) != 0)
+ return _error->Errno("statvfs","Couldn't determine free space in %s",
+ OutputDir.c_str());
+ if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
+ return _error->Error(_("You don't have enough free space in %s"),
+ OutputDir.c_str());
+
+ // Number of bytes
+ if (DebBytes != FetchBytes)
+ ioprintf(c1out,_("Need to get %sB/%sB of source archives.\n"),
+ SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str());
+ else
+ ioprintf(c1out,_("Need to get %sB of source archives.\n"),
+ SizeToStr(DebBytes).c_str());
+
+ if (_config->FindB("APT::Get::Simulate",false) == true)
+ {
+ for (unsigned I = 0; I != J; I++)
+ ioprintf(cout,_("Fetch Source %s\n"),Dsc[I].Package.c_str());
+ return true;
+ }
+
+ // Just print out the uris an exit if the --print-uris flag was used
+ if (_config->FindB("APT::Get::Print-URIs") == true)
+ {
+ pkgAcquire::UriIterator I = Fetcher.UriBegin();
+ for (; I != Fetcher.UriEnd(); I++)
+ cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' <<
+ I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl;
+ return true;
+ }
+
+ // Run it
+ if (Fetcher.Run() == pkgAcquire::Failed)
+ return false;
+
+ // Print error messages
+ bool Failed = false;
+ for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
+ {
+ if ((*I)->Status == pkgAcquire::Item::StatDone &&
+ (*I)->Complete == true)
+ continue;
+
+ fprintf(stderr,_("Failed to fetch %s %s\n"),(*I)->DescURI().c_str(),
+ (*I)->ErrorText.c_str());
+ Failed = true;
+ }
+ if (Failed == true)
+ return _error->Error(_("Failed to fetch some archives."));
+
+ if (_config->FindB("APT::Get::Download-only",false) == true)
+ {
+ c1out << _("Download complete and in download only mode") << endl;
+ return true;
+ }
+
+ // Unpack the sources
+ pid_t Process = ExecFork();
+
+ if (Process == 0)
+ {
+ for (unsigned I = 0; I != J; I++)
+ {
+ string Dir = Dsc[I].Package + '-' + Cache->VS().UpstreamVersion(Dsc[I].Version.c_str());
+
+ // Diff only mode only fetches .diff files
+ if (_config->FindB("APT::Get::Diff-Only",false) == true ||
+ _config->FindB("APT::Get::Tar-Only",false) == true ||
+ Dsc[I].Dsc.empty() == true)
+ continue;
+
+ // See if the package is already unpacked
+ struct stat Stat;
+ if (stat(Dir.c_str(),&Stat) == 0 &&
+ S_ISDIR(Stat.st_mode) != 0)
+ {
+ ioprintf(c0out ,_("Skipping unpack of already unpacked source in %s\n"),
+ Dir.c_str());
+ }
+ else
+ {
+ // Call dpkg-source
+ char S[500];
+ snprintf(S,sizeof(S),"%s -x %s",
+ _config->Find("Dir::Bin::dpkg-source","dpkg-source").c_str(),
+ Dsc[I].Dsc.c_str());
+ if (system(S) != 0)
+ {
+ fprintf(stderr,_("Unpack command '%s' failed.\n"),S);
+ _exit(1);
+ }
+ }
+
+ // Try to compile it with dpkg-buildpackage
+ if (_config->FindB("APT::Get::Compile",false) == true)
+ {
+ // Call dpkg-buildpackage
+ char S[500];
+ snprintf(S,sizeof(S),"cd %s && %s %s",
+ Dir.c_str(),
+ _config->Find("Dir::Bin::dpkg-buildpackage","dpkg-buildpackage").c_str(),
+ _config->Find("DPkg::Build-Options","-b -uc").c_str());
+
+ if (system(S) != 0)
+ {
+ fprintf(stderr,_("Build command '%s' failed.\n"),S);
+ _exit(1);
+ }
+ }
+ }
+
+ _exit(0);
+ }
+
+ // Wait for the subprocess
+ int Status = 0;
+ while (waitpid(Process,&Status,0) != Process)
+ {
+ if (errno == EINTR)
+ continue;
+ return _error->Errno("waitpid","Couldn't wait for subprocess");
+ }
+
+ if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
+ return _error->Error(_("Child process failed"));
+
+ return true;
+}
+ /*}}}*/
+// DoBuildDep - Install/removes packages to satisfy build dependencies /*{{{*/
+// ---------------------------------------------------------------------
+/* This function will look at the build depends list of the given source
+ package and install the necessary packages to make it true, or fail. */
+bool DoBuildDep(CommandLine &CmdL)
+{
+ CacheFile Cache;
+ if (Cache.Open(true) == false)
+ return false;
+
+ if (CmdL.FileSize() <= 1)
+ return _error->Error(_("Must specify at least one package to check builddeps for"));
+
+ // Read the source list
+ pkgSourceList List;
+ if (List.ReadMainList() == false)
+ return _error->Error(_("The list of sources could not be read."));
+
+ // Create the text record parsers
+ pkgRecords Recs(Cache);
+ pkgSrcRecords SrcRecs(List);
+ if (_error->PendingError() == true)
+ return false;
+
+ // Create the download object
+ AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
+ pkgAcquire Fetcher(&Stat);
+
+ unsigned J = 0;
+ for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++)
+ {
+ string Src;
+ pkgSrcRecords::Parser *Last = FindSrc(*I,Recs,SrcRecs,Src,*Cache);
+ if (Last == 0)
+ return _error->Error(_("Unable to find a source package for %s"),Src.c_str());
+
+ // Process the build-dependencies
+ vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
+ if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",false)) == false)
+ return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str());
+
+ // Also ensure that build-essential packages are present
+ Configuration::Item const *Opts = _config->Tree("APT::Build-Essential");
+ if (Opts)
+ Opts = Opts->Child;
+ for (; Opts; Opts = Opts->Next)
+ {
+ if (Opts->Value.empty() == true)
+ continue;
+
+ pkgSrcRecords::Parser::BuildDepRec rec;
+ rec.Package = Opts->Value;
+ rec.Type = pkgSrcRecords::Parser::BuildDependIndep;
+ rec.Op = 0;
+ BuildDeps.push_back(rec);
+ }
+
+ if (BuildDeps.size() == 0)
+ {
+ ioprintf(c1out,_("%s has no build depends.\n"),Src.c_str());
+ continue;
+ }
+
+ // Install the requested packages
+ unsigned int ExpectedInst = 0;
+ vector <pkgSrcRecords::Parser::BuildDepRec>::iterator D;
+ pkgProblemResolver Fix(Cache);
+ bool skipAlternatives = false; // skip remaining alternatives in an or group
+ for (D = BuildDeps.begin(); D != BuildDeps.end(); D++)
+ {
+ bool hasAlternatives = (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or);
+
+ if (skipAlternatives == true)
+ {
+ if (!hasAlternatives)
+ skipAlternatives = false; // end of or group
+ continue;
+ }
+
+ if ((*D).Type == pkgSrcRecords::Parser::BuildConflict ||
+ (*D).Type == pkgSrcRecords::Parser::BuildConflictIndep)
+ {
+ pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package);
+ // Build-conflicts on unknown packages are silently ignored
+ if (Pkg.end() == true)
+ continue;
+
+ pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
+
+ /*
+ * Remove if we have an installed version that satisfies the
+ * version criteria
+ */
+ if (IV.end() == false &&
+ Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
+ TryToInstall(Pkg,Cache,Fix,true,false,ExpectedInst);
+ }
+ else // BuildDep || BuildDepIndep
+ {
+ pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package);
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << "Looking for " << (*D).Package << "...\n";
+
+ if (Pkg.end() == true)
+ {
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " (not found)" << (*D).Package << endl;
+
+ if (hasAlternatives)
+ continue;
+
+ return _error->Error(_("%s dependency for %s cannot be satisfied "
+ "because the package %s cannot be found"),
+ Last->BuildDepType((*D).Type),Src.c_str(),
+ (*D).Package.c_str());
+ }
+
+ /*
+ * if there are alternatives, we've already picked one, so skip
+ * the rest
+ *
+ * TODO: this means that if there's a build-dep on A|B and B is
+ * installed, we'll still try to install A; more importantly,
+ * if A is currently broken, we cannot go back and try B. To fix
+ * this would require we do a Resolve cycle for each package we
+ * add to the install list. Ugh
+ */
+
+ /*
+ * If this is a virtual package, we need to check the list of
+ * packages that provide it and see if any of those are
+ * installed
+ */
+ pkgCache::PrvIterator Prv = Pkg.ProvidesList();
+ for (; Prv.end() != true; Prv++)
+ {
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " Checking provider " << Prv.OwnerPkg().Name() << endl;
+
+ if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
+ break;
+ }
+
+ // Get installed version and version we are going to install
+ pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
+
+ if ((*D).Version[0] != '\0') {
+ // Versioned dependency
+
+ pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
+
+ for (; CV.end() != true; CV++)
+ {
+ if (Cache->VS().CheckDep(CV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
+ break;
+ }
+ if (CV.end() == true)
+ if (hasAlternatives)
+ {
+ continue;
+ }
+ else
+ {
+ return _error->Error(_("%s dependency for %s cannot be satisfied "
+ "because no available versions of package %s "
+ "can satisfy version requirements"),
+ Last->BuildDepType((*D).Type),Src.c_str(),
+ (*D).Package.c_str());
+ }
+ }
+ else
+ {
+ // Only consider virtual packages if there is no versioned dependency
+ if (Prv.end() == false)
+ {
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " Is provided by installed package " << Prv.OwnerPkg().Name() << endl;
+ skipAlternatives = hasAlternatives;
+ continue;
+ }
+ }
+
+ if (IV.end() == false)
+ {
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " Is installed\n";
+
+ if (Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
+ {
+ skipAlternatives = hasAlternatives;
+ continue;
+ }
+
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " ...but the installed version doesn't meet the version requirement\n";
+
+ if (((*D).Op & pkgCache::Dep::LessEq) == pkgCache::Dep::LessEq)
+ {
+ return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"),
+ Last->BuildDepType((*D).Type),
+ Src.c_str(),
+ Pkg.Name());
+ }
+ }
+
+
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " Trying to install " << (*D).Package << endl;
+
+ if (TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst) == true)
+ {
+ // We successfully installed something; skip remaining alternatives
+ skipAlternatives = hasAlternatives;
+ continue;
+ }
+ else if (hasAlternatives)
+ {
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " Unsatisfiable, trying alternatives\n";
+ continue;
+ }
+ else
+ {
+ return _error->Error(_("Failed to satisfy %s dependency for %s: %s"),
+ Last->BuildDepType((*D).Type),
+ Src.c_str(),
+ (*D).Package.c_str());
+ }
+ }
+ }
+
+ Fix.InstallProtect();
+ if (Fix.Resolve(true) == false)
+ _error->Discard();
+
+ // Now we check the state of the packages,
+ if (Cache->BrokenCount() != 0)
+ return _error->Error(_("Build-dependencies for %s could not be satisfied."),*I);
+ }
+
+ if (InstallPackages(Cache, false, true) == false)
+ return _error->Error(_("Failed to process build dependencies"));
+ return true;
+}
+ /*}}}*/
+
+// DoMoo - Never Ask, Never Tell /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool DoMoo(CommandLine &CmdL)
+{
+ cout <<
+ " (__) \n"
+ " (oo) \n"
+ " /------\\/ \n"
+ " / | || \n"
+ " * /\\---/\\ \n"
+ " ~~ ~~ \n"
+ "....\"Have you mooed today?\"...\n";
+
+ return true;
+}
+ /*}}}*/