X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/1fc07a44e8191e00fc1566bfc15e8b370da77330..178dd062eeaa1d7e56770455e005dc27aa71f026:/cmdline/apt-get.cc diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 1211a3411..1849f1335 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -363,7 +363,7 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now) if (Start == End) break; - Start++; + ++Start; } } } @@ -382,8 +382,6 @@ void ShowNew(ostream &out,CacheFile &Cache) { pkgCache::PkgIterator I(Cache,Cache.List[J]); if (Cache[I].NewInstall() == true) { - if (Cache[I].CandidateVerIter(Cache).Pseudo() == true) - continue; List += I.FullName(true) + " "; VersionsList += string(Cache[I].CandVersion) + "\n"; } @@ -406,8 +404,6 @@ void ShowDel(ostream &out,CacheFile &Cache) pkgCache::PkgIterator I(Cache,Cache.List[J]); if (Cache[I].Delete() == true) { - if (Cache[I].CandidateVerIter(Cache).Pseudo() == true) - continue; if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge) List += I.FullName(true) + "* "; else @@ -456,8 +452,6 @@ void ShowUpgraded(ostream &out,CacheFile &Cache) // Not interesting if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true) continue; - if (Cache[I].CandidateVerIter(Cache).Pseudo() == true) - continue; List += I.FullName(true) + " "; VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; @@ -479,8 +473,6 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache) // Not interesting if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true) continue; - if (Cache[I].CandidateVerIter(Cache).Pseudo() == true) - continue; List += I.FullName(true) + " "; VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; @@ -545,7 +537,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache) continue; // Print out any essential package depenendents that are to be removed - for (pkgCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; D++) + for (pkgCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; ++D) { // Skip everything but depends if (D->Type != pkgCache::Dep::PreDepends && @@ -582,11 +574,8 @@ void Stats(ostream &out,pkgDepCache &Dep) unsigned long Downgrade = 0; unsigned long Install = 0; unsigned long ReInstall = 0; - for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++) + for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; ++I) { - if (pkgCache::VerIterator(Dep, Dep[I].CandidateVer).Pseudo() == true) - continue; - if (Dep[I].NewInstall() == true) Install++; else @@ -677,7 +666,7 @@ public: } // if we found no candidate which provide this package, show non-candidates if (provider == 0) - for (I = Pkg.ProvidesList(); I.end() == false; I++) + for (I = Pkg.ProvidesList(); I.end() == false; ++I) out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr() << _(" [Not candidate version]") << endl; else @@ -693,7 +682,7 @@ public: SPtrArray Seen = new bool[Cache.GetPkgCache()->Head().PackageCount]; memset(Seen,0,Cache.GetPkgCache()->Head().PackageCount*sizeof(*Seen)); for (pkgCache::DepIterator Dep = Pkg.RevDependsList(); - Dep.end() == false; Dep++) { + Dep.end() == false; ++Dep) { if (Dep->Type != pkgCache::Dep::Replaces) continue; if (Seen[Dep.ParentPkg()->ID] == true) @@ -775,7 +764,7 @@ struct TryToInstall { unsigned long AutoMarkChanged; APT::PackageSet doAutoInstallLater; - TryToInstall(pkgCacheFile &Cache, pkgProblemResolver &PM, bool const &FixBroken) : Cache(&Cache), Fix(&PM), + TryToInstall(pkgCacheFile &Cache, pkgProblemResolver *PM, bool const &FixBroken) : Cache(&Cache), Fix(PM), FixBroken(FixBroken), AutoMarkChanged(0) {}; void operator() (pkgCache::VerIterator const &Ver) { @@ -793,8 +782,10 @@ struct TryToInstall { ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"), Pkg.FullName(true).c_str()); else { - Fix->Clear(Pkg); - Fix->Protect(Pkg); + if (Fix != NULL) { + Fix->Clear(Pkg); + Fix->Protect(Pkg); + } Cache->GetDepCache()->MarkInstall(Pkg,false); if (State.Install() == false) { @@ -878,20 +869,21 @@ struct TryToInstall { struct TryToRemove { pkgCacheFile* Cache; pkgProblemResolver* Fix; - bool FixBroken; bool PurgePkgs; - unsigned long AutoMarkChanged; - TryToRemove(pkgCacheFile &Cache, pkgProblemResolver &PM) : Cache(&Cache), Fix(&PM), + TryToRemove(pkgCacheFile &Cache, pkgProblemResolver *PM) : Cache(&Cache), Fix(PM), PurgePkgs(_config->FindB("APT::Get::Purge", false)) {}; void operator() (pkgCache::VerIterator const &Ver) { pkgCache::PkgIterator Pkg = Ver.ParentPkg(); - Fix->Clear(Pkg); - Fix->Protect(Pkg); - Fix->Remove(Pkg); + if (Fix != NULL) + { + Fix->Clear(Pkg); + Fix->Protect(Pkg); + Fix->Remove(Pkg); + } if ((Pkg->CurrentVer == 0 && PurgePkgs == false) || (PurgePkgs == true && Pkg->CurrentState == pkgCache::State::NotInstalled)) @@ -929,7 +921,7 @@ void CacheFile::Sort() List = new pkgCache::Package *[Cache->Head().PackageCount]; memset(List,0,sizeof(*List)*Cache->Head().PackageCount); pkgCache::PkgIterator I = Cache->PkgBegin(); - for (;I.end() != true; I++) + for (;I.end() != true; ++I) List[I->ID] = I; SortCache = *this; @@ -961,7 +953,7 @@ bool CacheFile::CheckDeps(bool AllowBroken) if ((DCache->PolicyBrokenCount() > 0)) { // upgrade all policy-broken packages with ForceImportantDeps=True - for (pkgCache::PkgIterator I = Cache->PkgBegin(); !I.end(); I++) + for (pkgCache::PkgIterator I = Cache->PkgBegin(); !I.end(); ++I) if ((*DCache)[I].NowPolicyBroken() == true) DCache->MarkInstall(I,true,0, false, true); } @@ -1052,7 +1044,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, if (_config->FindB("APT::Get::Purge",false) == true) { pkgCache::PkgIterator I = Cache->PkgBegin(); - for (; I.end() == false; I++) + for (; I.end() == false; ++I) { if (I.Purge() == false && Cache[I].Mode == pkgDepCache::ModeDelete) Cache->MarkDelete(I,true); @@ -1246,7 +1238,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, if (_config->FindB("APT::Get::Print-URIs") == true) { pkgAcquire::UriIterator I = Fetcher.UriBegin(); - for (; I != Fetcher.UriEnd(); I++) + for (; I != Fetcher.UriEnd(); ++I) cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; return true; @@ -1270,7 +1262,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, { if ((*I)->Local == true) { - I++; + ++I; continue; } @@ -1290,7 +1282,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, // Print out errors bool Failed = false; - for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I) { if ((*I)->Status == pkgAcquire::Item::StatDone && (*I)->Complete == true) @@ -1394,12 +1386,20 @@ bool TryToInstallBuildDep(pkgCache::PkgIterator Pkg,pkgCacheFile &Cache, return AllowFail; } + if (_config->FindB("Debug::BuildDeps",false) == true) + { + if (Remove == true) + cout << " Trying to remove " << Pkg << endl; + else + cout << " Trying to install " << Pkg << endl; + } + if (Remove == true) { - TryToRemove RemoveAction(Cache, Fix); + TryToRemove RemoveAction(Cache, &Fix); RemoveAction(Pkg.VersionList()); } else if (Cache[Pkg].CandidateVer != 0) { - TryToInstall InstallAction(Cache, Fix, BrokenFix); + TryToInstall InstallAction(Cache, &Fix, BrokenFix); InstallAction(Cache[Pkg].CandidateVerIter(Cache)); InstallAction.doAutoInstall(); } else @@ -1442,7 +1442,7 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, // we have a default release, try to locate the pkg. we do it like // this because GetCandidateVer() will not "downgrade", that means // "apt-get source -t stable apt" won't work on a unstable system - for (pkgCache::VerIterator Ver = Pkg.VersionList();; Ver++) + for (pkgCache::VerIterator Ver = Pkg.VersionList();; ++Ver) { // try first only exact matches, later fuzzy matches if (Ver.end() == true) @@ -1463,7 +1463,7 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, continue; for (pkgCache::VerFileIterator VF = Ver.FileList(); - VF.end() == false; VF++) + VF.end() == false; ++VF) { /* If this is the status file, and the current version is not the version in the status file (ie it is not installed, or somesuch) @@ -1615,7 +1615,7 @@ bool DoUpdate(CommandLine &CmdL) return false; pkgAcquire::UriIterator I = Fetcher.UriBegin(); - for (; I != Fetcher.UriEnd(); I++) + for (; I != Fetcher.UriEnd(); ++I) cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; return true; @@ -1659,6 +1659,7 @@ bool DoAutomaticRemove(CacheFile &Cache) string autoremovelist, autoremoveversions; unsigned long autoRemoveCount = 0; + APT::PackageSet tooMuch; // look over the cache to see what can be removed for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++Pkg) { @@ -1681,7 +1682,10 @@ bool DoAutomaticRemove(CacheFile &Cache) // if the package is a new install and already garbage we don't need to // install it in the first place, so nuke it instead of show it if (Cache[Pkg].Install() == true && Pkg.CurrentVer() == 0) + { Cache->MarkDelete(Pkg, false); + tooMuch.insert(Pkg); + } // only show stuff in the list that is not yet marked for removal else if(hideAutoRemove == false && Cache[Pkg].Delete() == false) { @@ -1697,6 +1701,45 @@ bool DoAutomaticRemove(CacheFile &Cache) } } + // we could have removed a new dependency of a garbage package, + // so check if a reverse depends is broken and if so install it again. + if (tooMuch.empty() == false && (Cache->BrokenCount() != 0 || Cache->PolicyBrokenCount() != 0)) + { + bool Changed; + do { + Changed = false; + for (APT::PackageSet::const_iterator P = tooMuch.begin(); + P != tooMuch.end() && Changed == false; ++P) + { + for (pkgCache::DepIterator R = P.RevDependsList(); + R.end() == false; ++R) + { + if (R.IsNegative() == true || + Cache->IsImportantDep(R) == false) + continue; + pkgCache::PkgIterator N = R.ParentPkg(); + if (N.end() == true || (N->CurrentVer == 0 && (*Cache)[N].Install() == false)) + continue; + if (Debug == true) + std::clog << "Save " << P << " as another installed garbage package depends on it" << std::endl; + Cache->MarkInstall(P, false); + if(hideAutoRemove == false) + { + ++autoRemoveCount; + if (smallList == false) + { + autoremovelist += P.FullName(true) + " "; + autoremoveversions += string(Cache[P].CandVersion) + "\n"; + } + } + tooMuch.erase(P); + Changed = true; + break; + } + } + } while (Changed == true); + } + // Now see if we had destroyed anything (if we had done anything) if (Cache->BrokenCount() != 0) { @@ -1759,8 +1802,10 @@ bool DoInstall(CommandLine &CmdL) bool BrokenFix = false; if (Cache->BrokenCount() != 0) BrokenFix = true; - - pkgProblemResolver Fix(Cache); + + pkgProblemResolver* Fix = NULL; + if (_config->FindB("APT::Get::CallResolver", true) == true) + Fix = new pkgProblemResolver(Cache); static const unsigned short MOD_REMOVE = 1; static const unsigned short MOD_INSTALL = 2; @@ -1791,6 +1836,8 @@ bool DoInstall(CommandLine &CmdL) if (_error->PendingError() == true) { helper.showVirtualPackageErrors(Cache); + if (Fix != NULL) + delete Fix; return false; } @@ -1805,17 +1852,29 @@ bool DoInstall(CommandLine &CmdL) for (unsigned short i = 0; order[i] != 0; ++i) { - if (order[i] == MOD_INSTALL) { + if (order[i] == MOD_INSTALL) InstallAction = std::for_each(verset[MOD_INSTALL].begin(), verset[MOD_INSTALL].end(), InstallAction); + else if (order[i] == MOD_REMOVE) + RemoveAction = std::for_each(verset[MOD_REMOVE].begin(), verset[MOD_REMOVE].end(), RemoveAction); + } + + if (Fix != NULL && _config->FindB("APT::Get::AutoSolving", true) == true) + { + for (unsigned short i = 0; order[i] != 0; ++i) + { + if (order[i] != MOD_INSTALL) + continue; InstallAction.propergateReleaseCandiateSwitching(helper.selectedByRelease, c0out); InstallAction.doAutoInstall(); } - else if (order[i] == MOD_REMOVE) - RemoveAction = std::for_each(verset[MOD_REMOVE].begin(), verset[MOD_REMOVE].end(), RemoveAction); } if (_error->PendingError() == true) + { + if (Fix != NULL) + delete Fix; return false; + } /* If we are in the Broken fixing mode we do not attempt to fix the problems. This is if the user invoked install without -f and gave @@ -1824,14 +1883,19 @@ bool DoInstall(CommandLine &CmdL) { c1out << _("You might want to run 'apt-get -f install' to correct these:") << endl; ShowBroken(c1out,Cache,false); - + if (Fix != NULL) + delete Fix; return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).")); } - - // Call the scored problem resolver - Fix.InstallProtect(); - if (Fix.Resolve(true) == false) - _error->Discard(); + + if (Fix != NULL) + { + // Call the scored problem resolver + Fix->InstallProtect(); + if (Fix->Resolve(true) == false) + _error->Discard(); + delete Fix; + } // Now we check the state of the packages, if (Cache->BrokenCount() != 0) @@ -1873,8 +1937,6 @@ bool DoInstall(CommandLine &CmdL) if ((*Cache)[I].Install() == false) continue; pkgCache::VerIterator Cand = Cache[I].CandidateVerIter(Cache); - if (Cand.Pseudo() == true) - continue; if (verset[MOD_INSTALL].find(Cand) != verset[MOD_INSTALL].end()) continue; @@ -1936,7 +1998,7 @@ bool DoInstall(CommandLine &CmdL) if(Start.TargetPkg().ProvidesList() != 0) { pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList(); - for (; I.end() == false; I++) + for (; I.end() == false; ++I) { pkgCache::PkgIterator Pkg = I.OwnerPkg(); if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() && @@ -1959,7 +2021,7 @@ bool DoInstall(CommandLine &CmdL) if (Start >= End) break; - Start++; + ++Start; } if(foundInstalledInOrGroup == false) @@ -1994,8 +2056,8 @@ bool DoInstall(CommandLine &CmdL) return InstallPackages(Cache,false); } - -/* mark packages as automatically/manually installed. */ + /*}}}*/ +/* mark packages as automatically/manually installed. {{{*/ bool DoMarkAuto(CommandLine &CmdL) { bool Action = true; @@ -2030,6 +2092,9 @@ bool DoMarkAuto(CommandLine &CmdL) AutoMarkChanged++; } } + + _error->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead.")); + if (AutoMarkChanged && ! _config->FindB("APT::Get::Simulate",false)) return Cache->writeStateFile(NULL); return false; @@ -2070,7 +2135,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL) // Install everything with the install flag set pkgCache::PkgIterator I = Cache->PkgBegin(); - for (;I.end() != true; I++) + for (;I.end() != true; ++I) { /* Install the package only if it is a new install, the autoupgrader will deal with the rest */ @@ -2080,7 +2145,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL) /* Now install their deps too, if we do this above then order of the status file is significant for | groups */ - for (I = Cache->PkgBegin();I.end() != true; I++) + for (I = Cache->PkgBegin();I.end() != true; ++I) { /* Install the package only if it is a new install, the autoupgrader will deal with the rest */ @@ -2089,7 +2154,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL) } // Apply erasures now, they override everything else. - for (I = Cache->PkgBegin();I.end() != true; I++) + for (I = Cache->PkgBegin();I.end() != true; ++I) { // Remove packages if (I->SelectedState == pkgCache::State::DeInstall || @@ -2106,7 +2171,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL) // Hold back held packages. if (_config->FindB("APT::Ignore-Hold",false) == false) { - for (pkgCache::PkgIterator I = Cache->PkgBegin(); I.end() == false; I++) + for (pkgCache::PkgIterator I = Cache->PkgBegin(); I.end() == false; ++I) { if (I->SelectedState == pkgCache::State::Hold) { @@ -2214,7 +2279,7 @@ bool DoDownload(CommandLine &CmdL) pkgAcquire Fetcher; AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); - if (_config->FindB("APT::Get::Print-URIs") == true) + if (_config->FindB("APT::Get::Print-URIs") == false) Fetcher.Setup(&Stat); pkgRecords Recs(Cache); @@ -2252,7 +2317,7 @@ bool DoDownload(CommandLine &CmdL) if (_config->FindB("APT::Get::Print-URIs") == true) { pkgAcquire::UriIterator I = Fetcher.UriBegin(); - for (; I != Fetcher.UriEnd(); I++) + for (; I != Fetcher.UriEnd(); ++I) cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; return true; @@ -2307,8 +2372,7 @@ bool DoSource(CommandLine &CmdL) // Create the download object AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); pkgAcquire Fetcher; - if (Fetcher.Setup(&Stat) == false) - return false; + Fetcher.SetLog(&Stat); DscFile *Dsc = new DscFile[CmdL.FileSize()]; @@ -2330,8 +2394,10 @@ bool DoSource(CommandLine &CmdL) string Src; pkgSrcRecords::Parser *Last = FindSrc(*I,Recs,SrcRecs,Src,*Cache); - if (Last == 0) + if (Last == 0) { + delete[] Dsc; return _error->Error(_("Unable to find a source package for %s"),Src.c_str()); + } string srec = Last->AsStr(); string::size_type pos = srec.find("\nVcs-"); @@ -2362,12 +2428,14 @@ bool DoSource(CommandLine &CmdL) // Back track vector Lst; - if (Last->Files(Lst) == false) + if (Last->Files(Lst) == false) { + delete[] Dsc; return false; + } // Load them into the fetcher for (vector::const_iterator I = Lst.begin(); - I != Lst.end(); I++) + I != Lst.end(); ++I) { // Try to guess what sort of file it is we are getting. if (I->Type == "dsc") @@ -2424,6 +2492,7 @@ bool DoSource(CommandLine &CmdL) struct statvfs Buf; string OutputDir = "."; if (statvfs(OutputDir.c_str(),&Buf) != 0) { + delete[] Dsc; if (errno == EOVERFLOW) return _error->WarningE("statvfs",_("Couldn't determine free space in %s"), OutputDir.c_str()); @@ -2437,10 +2506,12 @@ bool DoSource(CommandLine &CmdL) #if HAVE_STRUCT_STATFS_F_TYPE || unsigned(Stat.f_type) != RAMFS_MAGIC #endif - ) + ) { + delete[] Dsc; return _error->Error(_("You don't have enough free space in %s"), OutputDir.c_str()); - } + } + } // Number of bytes if (DebBytes != FetchBytes) @@ -2466,7 +2537,7 @@ bool DoSource(CommandLine &CmdL) if (_config->FindB("APT::Get::Print-URIs") == true) { pkgAcquire::UriIterator I = Fetcher.UriBegin(); - for (; I != Fetcher.UriEnd(); I++) + for (; I != Fetcher.UriEnd(); ++I) cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; delete[] Dsc; @@ -2475,11 +2546,14 @@ bool DoSource(CommandLine &CmdL) // Run it if (Fetcher.Run() == pkgAcquire::Failed) + { + delete[] Dsc; return false; + } // Print error messages bool Failed = false; - for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I) { if ((*I)->Status == pkgAcquire::Item::StatDone && (*I)->Complete == true) @@ -2490,8 +2564,11 @@ bool DoSource(CommandLine &CmdL) Failed = true; } if (Failed == true) + { + delete[] Dsc; 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; @@ -2505,7 +2582,7 @@ bool DoSource(CommandLine &CmdL) if (Process == 0) { bool const fixBroken = _config->FindB("APT::Get::Fix-Broken", false); - for (unsigned I = 0; I != J; I++) + for (unsigned I = 0; I != J; ++I) { string Dir = Dsc[I].Package + '-' + Cache->VS().UpstreamVersion(Dsc[I].Version.c_str()); @@ -2541,12 +2618,17 @@ bool DoSource(CommandLine &CmdL) // Try to compile it with dpkg-buildpackage if (_config->FindB("APT::Get::Compile",false) == true) { + string buildopts = _config->Find("APT::Get::Host-Architecture"); + if (buildopts.empty() == false) + buildopts = "-a " + buildopts + " "; + buildopts.append(_config->Find("DPkg::Build-Options","-b -uc")); + // 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()); + buildopts.c_str()); if (system(S) != 0) { @@ -2582,6 +2664,9 @@ bool DoSource(CommandLine &CmdL) bool DoBuildDep(CommandLine &CmdL) { CacheFile Cache; + + _config->Set("APT::Install-Recommends", false); + if (Cache.Open(true) == false) return false; @@ -2605,8 +2690,19 @@ bool DoBuildDep(CommandLine &CmdL) if (Fetcher.Setup(&Stat) == false) return false; + bool StripMultiArch; + string hostArch = _config->Find("APT::Get::Host-Architecture"); + if (hostArch.empty() == false) + { + std::vector archs = APT::Configuration::getArchitectures(); + if (std::find(archs.begin(), archs.end(), hostArch) == archs.end()) + return _error->Error(_("No architecture information available for %s. See apt.conf(5) APT::Architectures for setup"), hostArch.c_str()); + StripMultiArch = false; + } + else + StripMultiArch = true; + unsigned J = 0; - bool const StripMultiArch = APT::Configuration::getArchitectures().size() <= 1; for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) { string Src; @@ -2635,22 +2731,32 @@ bool DoBuildDep(CommandLine &CmdL) BuildDeps.push_back(rec); } - if (BuildDeps.size() == 0) + if (BuildDeps.empty() == true) { ioprintf(c1out,_("%s has no build depends.\n"),Src.c_str()); continue; } - + // Install the requested packages vector ::iterator D; pkgProblemResolver Fix(Cache); bool skipAlternatives = false; // skip remaining alternatives in an or group - for (D = BuildDeps.begin(); D != BuildDeps.end(); D++) + for (D = BuildDeps.begin(); D != BuildDeps.end(); ++D) { bool hasAlternatives = (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or); if (skipAlternatives == true) { + /* + * 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 (!hasAlternatives) skipAlternatives = false; // end of or group continue; @@ -2659,27 +2765,117 @@ bool DoBuildDep(CommandLine &CmdL) if ((*D).Type == pkgSrcRecords::Parser::BuildConflict || (*D).Type == pkgSrcRecords::Parser::BuildConflictIndep) { - pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package); + pkgCache::GrpIterator Grp = Cache->FindGrp((*D).Package); // Build-conflicts on unknown packages are silently ignored - if (Pkg.end() == true) + if (Grp.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) - TryToInstallBuildDep(Pkg,Cache,Fix,true,false); + for (pkgCache::PkgIterator Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg)) + { + 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) + TryToInstallBuildDep(Pkg,Cache,Fix,true,false); + } } else // BuildDep || BuildDepIndep { - pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package); if (_config->FindB("Debug::BuildDeps",false) == true) cout << "Looking for " << (*D).Package << "...\n"; + pkgCache::PkgIterator Pkg; + + // Cross-Building? + if (StripMultiArch == false) + { + size_t const colon = D->Package.find(":"); + if (colon != string::npos && + (strcmp(D->Package.c_str() + colon, ":any") == 0 || strcmp(D->Package.c_str() + colon, ":native") == 0)) + Pkg = Cache->FindPkg(D->Package.substr(0,colon)); + else + Pkg = Cache->FindPkg(D->Package); + + // We need to decide if host or build arch, so find a version we can look at + pkgCache::VerIterator Ver; + + // a bad version either is invalid or doesn't satify dependency + #define BADVER(Ver) Ver.end() == true || \ + (Ver.end() == false && D->Version.empty() == false && \ + Cache->VS().CheckDep(Ver.VerStr(),D->Op,D->Version.c_str()) == false) + + if (Pkg.end() == false) + { + Ver = (*Cache)[Pkg].InstVerIter(*Cache); + if (BADVER(Ver)) + Ver = (*Cache)[Pkg].CandidateVerIter(*Cache); + } + if (BADVER(Ver)) + { + pkgCache::PkgIterator HostPkg = Cache->FindPkg(D->Package, hostArch); + if (HostPkg.end() == false) + { + Ver = (*Cache)[HostPkg].InstVerIter(*Cache); + if (BADVER(Ver)) + Ver = (*Cache)[HostPkg].CandidateVerIter(*Cache); + } + } + if ((BADVER(Ver)) == false) + { + string forbidden; + if (Ver->MultiArch == pkgCache::Version::None || Ver->MultiArch == pkgCache::Version::All); + else if (Ver->MultiArch == pkgCache::Version::Same) + { + if (colon != string::npos) + Pkg = Ver.ParentPkg().Group().FindPkg(hostArch); + else if (strcmp(D->Package.c_str() + colon, ":any") == 0) + forbidden = "Multi-Arch: same"; + // :native gets the buildArch + } + else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign) + { + if (colon != string::npos) + forbidden = "Multi-Arch: foreign"; + } + else if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed) + { + if (colon == string::npos) + Pkg = Ver.ParentPkg().Group().FindPkg(hostArch); + else if (strcmp(D->Package.c_str() + colon, ":any") == 0) + { + // prefer any installed over preferred non-installed architectures + pkgCache::GrpIterator Grp = Ver.ParentPkg().Group(); + // we don't check for version here as we are better of with upgrading than remove and install + for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg)) + if (Pkg.CurrentVer().end() == false) + break; + if (Pkg.end() == true) + Pkg = Grp.FindPreferredPkg(true); + } + // native gets buildArch + } + if (forbidden.empty() == false) + { + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " :any is not allowed from M-A: same package " << (*D).Package << endl; + if (hasAlternatives) + continue; + return _error->Error(_("%s dependency for %s can't be satisfied " + "because %s is not allowed on '%s' packages"), + Last->BuildDepType(D->Type), Src.c_str(), + D->Package.c_str(), "Multi-Arch: same"); + } + } + else if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " No multiarch info as we have no satisfying installed nor candidate for " << D->Package << " on build or host arch" << endl; + #undef BADVER + } + else + Pkg = Cache->FindPkg(D->Package); + if (Pkg.end() == true) { if (_config->FindB("Debug::BuildDeps",false) == true) @@ -2694,99 +2890,74 @@ bool DoBuildDep(CommandLine &CmdL) (*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().FullName() << 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 (IV.end() == false) + { + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " Is installed\n"; - 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().FullName() << endl; - skipAlternatives = hasAlternatives; - continue; - } - } + if (D->Version.empty() == true || + Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true) + { + skipAlternatives = hasAlternatives; + continue; + } - if (IV.end() == false) - { - if (_config->FindB("Debug::BuildDeps",false) == true) - cout << " Is installed\n"; + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " ...but the installed version doesn't meet the version requirement\n"; - if (Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true) - { - skipAlternatives = hasAlternatives; - continue; - } + 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.FullName(true).c_str()); + } - 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.FullName(true).c_str()); - } - } + // Only consider virtual packages if there is no versioned dependency + if ((*D).Version.empty() == true) + { + /* + * 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().FullName() << endl; + if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false) + break; + } - if (_config->FindB("Debug::BuildDeps",false) == true) - cout << " Trying to install " << (*D).Package << endl; + if (Prv.end() == false) + { + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " Is provided by installed package " << Prv.OwnerPkg().FullName() << endl; + skipAlternatives = hasAlternatives; + continue; + } + } + else // versioned dependency + { + pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache); + if (CV.end() == true || + Cache->VS().CheckDep(CV.VerStr(),(*D).Op,(*D).Version.c_str()) == false) + { + if (hasAlternatives) + continue; + else if (CV.end() == false) + return _error->Error(_("%s dependency for %s cannot be satisfied " + "because candidate version of package %s " + "can't satisfy version requirements"), + Last->BuildDepType(D->Type), Src.c_str(), + D->Package.c_str()); + else + return _error->Error(_("%s dependency for %s cannot be satisfied " + "because package %s has no candidate version"), + Last->BuildDepType(D->Type), Src.c_str(), + D->Package.c_str()); + } + } if (TryToInstallBuildDep(Pkg,Cache,Fix,false,false) == true) { @@ -3112,8 +3283,6 @@ bool ShowHelp(CommandLine &CmdL) " clean - Erase downloaded archive files\n" " autoclean - Erase old downloaded archive files\n" " check - Verify that there are no broken dependencies\n" - " markauto - Mark the given packages as automatically installed\n" - " unmarkauto - Mark the given packages as manually installed\n" " changelog - Download and display the changelog for the given package\n" " download - Download the binary package into the current directory\n" "\n" @@ -3174,6 +3343,7 @@ int main(int argc,const char *argv[]) /*{{{*/ {'m',"ignore-missing","APT::Get::Fix-Missing",0}, {'t',"target-release","APT::Default-Release",CommandLine::HasArg}, {'t',"default-release","APT::Default-Release",CommandLine::HasArg}, + {'a',"host-architecture","APT::Get::Host-Architecture",CommandLine::HasArg}, {0,"download","APT::Get::Download",0}, {0,"fix-missing","APT::Get::Fix-Missing",0}, {0,"ignore-hold","APT::Ignore-Hold",0}, @@ -3248,7 +3418,10 @@ int main(int argc,const char *argv[]) /*{{{*/ } // simulate user-friendly if apt-get has no root privileges - if (getuid() != 0 && _config->FindB("APT::Get::Simulate") == true) + if (getuid() != 0 && _config->FindB("APT::Get::Simulate") == true && + (CmdL.FileSize() == 0 || + (strcmp(CmdL.FileList[0], "source") != 0 && strcmp(CmdL.FileList[0], "download") != 0 && + strcmp(CmdL.FileList[0], "changelog") != 0))) { if (_config->FindB("APT::Get::Show-User-Simulation-Note",true) == true) cout << _("NOTE: This is only a simulation!\n"