X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/cf28bcadb301d00f6534fea97ccf1fde63041e7b..6d0527822b8c240c929687f68b5f171d3ef2af3c:/cmdline/apt-get.cc diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index d3ddcbfe8..f4ad75d1c 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -25,6 +25,9 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ +#include + +#include #include #include #include @@ -33,19 +36,21 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include - -#include -#include +#include +#include +#include +#include #include "acqprogress.h" -#include "cacheset.h" #include #include @@ -63,6 +68,8 @@ #include #include #include + +#include /*}}}*/ #define RAMFS_MAGIC 0x858458f6 @@ -128,6 +135,11 @@ bool YnPrompt(bool Default=true) c1out << _("Y") << endl; return true; } + else if (_config->FindB("APT::Get::Assume-No",false) == true) + { + c1out << _("N") << endl; + return false; + } char response[1024] = ""; cin.getline(response, sizeof(response)); @@ -356,7 +368,7 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now) if (Start == End) break; - Start++; + ++Start; } } } @@ -375,8 +387,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"; } @@ -399,8 +409,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 @@ -449,8 +457,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"; @@ -472,8 +478,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"; @@ -531,12 +535,14 @@ bool ShowEssential(ostream &out,CacheFile &Cache) //VersionsList += string(Cache[I].CurVersion) + "\n"; ??? } } - + else + continue; + if (I->CurrentVer == 0) 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 && @@ -573,11 +579,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 @@ -609,6 +612,344 @@ void Stats(ostream &out,pkgDepCache &Dep) Dep.BadCount()); } /*}}}*/ +// CacheSetHelperAPTGet - responsible for message telling from the CacheSets/*{{{*/ +class CacheSetHelperAPTGet : public APT::CacheSetHelper { + /** \brief stream message should be printed to */ + std::ostream &out; + /** \brief were things like Task or RegEx used to select packages? */ + bool explicitlyNamed; + + APT::PackageSet virtualPkgs; + +public: + std::list > selectedByRelease; + + CacheSetHelperAPTGet(std::ostream &out) : APT::CacheSetHelper(true), out(out) { + explicitlyNamed = true; + } + + virtual void showTaskSelection(pkgCache::PkgIterator const &Pkg, string const &pattern) { + ioprintf(out, _("Note, selecting '%s' for task '%s'\n"), + Pkg.FullName(true).c_str(), pattern.c_str()); + explicitlyNamed = false; + } + virtual void showRegExSelection(pkgCache::PkgIterator const &Pkg, string const &pattern) { + ioprintf(out, _("Note, selecting '%s' for regex '%s'\n"), + Pkg.FullName(true).c_str(), pattern.c_str()); + explicitlyNamed = false; + } + virtual void showSelectedVersion(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const Ver, + string const &ver, bool const verIsRel) { + if (ver == Ver.VerStr()) + return; + selectedByRelease.push_back(make_pair(Ver, ver)); + } + + bool showVirtualPackageErrors(pkgCacheFile &Cache) { + if (virtualPkgs.empty() == true) + return true; + for (APT::PackageSet::const_iterator Pkg = virtualPkgs.begin(); + Pkg != virtualPkgs.end(); ++Pkg) { + if (Pkg->ProvidesList != 0) { + ioprintf(c1out,_("Package %s is a virtual package provided by:\n"), + Pkg.FullName(true).c_str()); + + pkgCache::PrvIterator I = Pkg.ProvidesList(); + unsigned short provider = 0; + for (; I.end() == false; ++I) { + pkgCache::PkgIterator Pkg = I.OwnerPkg(); + + if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer()) { + c1out << " " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr(); + if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false) + c1out << _(" [Installed]"); + c1out << endl; + ++provider; + } + } + // if we found no candidate which provide this package, show non-candidates + if (provider == 0) + for (I = Pkg.ProvidesList(); I.end() == false; ++I) + c1out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr() + << _(" [Not candidate version]") << endl; + else + out << _("You should explicitly select one to install.") << endl; + } else { + ioprintf(c1out, + _("Package %s is not available, but is referred to by another package.\n" + "This may mean that the package is missing, has been obsoleted, or\n" + "is only available from another source\n"),Pkg.FullName(true).c_str()); + + string List; + string VersionsList; + 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) { + if (Dep->Type != pkgCache::Dep::Replaces) + continue; + if (Seen[Dep.ParentPkg()->ID] == true) + continue; + Seen[Dep.ParentPkg()->ID] = true; + List += Dep.ParentPkg().FullName(true) + " "; + //VersionsList += string(Dep.ParentPkg().CurVersion) + "\n"; ??? + } + ShowList(c1out,_("However the following packages replace it:"),List,VersionsList); + } + c1out << std::endl; + } + return false; + } + + virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { + APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::CANDIDATE); + if (verset.empty() == false) + return *(verset.begin()); + else if (ShowError == true) { + _error->Error(_("Package '%s' has no installation candidate"),Pkg.FullName(true).c_str()); + virtualPkgs.insert(Pkg); + } + return pkgCache::VerIterator(Cache, 0); + } + + virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { + if (Pkg->ProvidesList != 0) + { + APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::NEWEST); + if (verset.empty() == false) + return *(verset.begin()); + if (ShowError == true) + ioprintf(out, _("Virtual packages like '%s' can't be removed\n"), Pkg.FullName(true).c_str()); + } + else + { + pkgCache::GrpIterator Grp = Pkg.Group(); + pkgCache::PkgIterator P = Grp.PackageList(); + for (; P.end() != true; P = Grp.NextPkg(P)) + { + if (P == Pkg) + continue; + if (P->CurrentVer != 0) { + // TRANSLATORS: Note, this is not an interactive question + ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"), + Pkg.FullName(true).c_str(), P.FullName(true).c_str()); + break; + } + } + if (P.end() == true) + ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str()); + } + return pkgCache::VerIterator(Cache, 0); + } + + APT::VersionSet tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg, + APT::VersionSet::Version const &select) { + /* This is a pure virtual package and there is a single available + candidate providing it. */ + if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0) + return APT::VersionSet(); + + pkgCache::PkgIterator Prov; + bool found_one = false; + for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; ++P) { + pkgCache::VerIterator const PVer = P.OwnerVer(); + pkgCache::PkgIterator const PPkg = PVer.ParentPkg(); + + /* Ignore versions that are not a candidate. */ + if (Cache[PPkg].CandidateVer != PVer) + continue; + + if (found_one == false) { + Prov = PPkg; + found_one = true; + } else if (PPkg != Prov) { + // same group, so it's a foreign package + if (PPkg->Group == Prov->Group) { + // do we already have the requested arch? + if (strcmp(Pkg.Arch(), Prov.Arch()) == 0 || + strcmp(Prov.Arch(), "all") == 0 || + unlikely(strcmp(PPkg.Arch(), Prov.Arch()) == 0)) // packages have only on candidate, but just to be sure + continue; + // see which architecture we prefer more and switch to it + std::vector archs = APT::Configuration::getArchitectures(); + if (std::find(archs.begin(), archs.end(), PPkg.Arch()) < std::find(archs.begin(), archs.end(), Prov.Arch())) + Prov = PPkg; + continue; + } + found_one = false; // we found at least two + break; + } + } + + if (found_one == true) { + ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"), + Prov.FullName(true).c_str(), Pkg.FullName(true).c_str()); + return APT::VersionSet::FromPackage(Cache, Prov, select, *this); + } + return APT::VersionSet(); + } + + inline bool allPkgNamedExplicitly() const { return explicitlyNamed; } + +}; + /*}}}*/ +// TryToInstall - Mark a package for installation /*{{{*/ +struct TryToInstall { + pkgCacheFile* Cache; + pkgProblemResolver* Fix; + bool FixBroken; + unsigned long AutoMarkChanged; + APT::PackageSet doAutoInstallLater; + + TryToInstall(pkgCacheFile &Cache, pkgProblemResolver *PM, bool const FixBroken) : Cache(&Cache), Fix(PM), + FixBroken(FixBroken), AutoMarkChanged(0) {}; + + void operator() (pkgCache::VerIterator const &Ver) { + pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + + Cache->GetDepCache()->SetCandidateVersion(Ver); + pkgDepCache::StateCache &State = (*Cache)[Pkg]; + + // Handle the no-upgrade case + if (_config->FindB("APT::Get::upgrade",true) == false && Pkg->CurrentVer != 0) + ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"), + Pkg.FullName(true).c_str()); + // Ignore request for install if package would be new + else if (_config->FindB("APT::Get::Only-Upgrade", false) == true && Pkg->CurrentVer == 0) + ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"), + Pkg.FullName(true).c_str()); + else { + if (Fix != NULL) { + Fix->Clear(Pkg); + Fix->Protect(Pkg); + } + Cache->GetDepCache()->MarkInstall(Pkg,false); + + if (State.Install() == false) { + if (_config->FindB("APT::Get::ReInstall",false) == true) { + if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false) + ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"), + Pkg.FullName(true).c_str()); + else + Cache->GetDepCache()->SetReInstall(Pkg, true); + } else + ioprintf(c1out,_("%s is already the newest version.\n"), + Pkg.FullName(true).c_str()); + } + + // Install it with autoinstalling enabled (if we not respect the minial + // required deps or the policy) + if (FixBroken == false) + doAutoInstallLater.insert(Pkg); + } + + // see if we need to fix the auto-mark flag + // e.g. apt-get install foo + // where foo is marked automatic + if (State.Install() == false && + (State.Flags & pkgCache::Flag::Auto) && + _config->FindB("APT::Get::ReInstall",false) == false && + _config->FindB("APT::Get::Only-Upgrade",false) == false && + _config->FindB("APT::Get::Download-Only",false) == false) + { + ioprintf(c1out,_("%s set to manually installed.\n"), + Pkg.FullName(true).c_str()); + Cache->GetDepCache()->MarkAuto(Pkg,false); + AutoMarkChanged++; + } + } + + bool propergateReleaseCandiateSwitching(std::list > start, std::ostream &out) + { + for (std::list >::const_iterator s = start.begin(); + s != start.end(); ++s) + Cache->GetDepCache()->SetCandidateVersion(s->first); + + bool Success = true; + std::list > Changed; + for (std::list >::const_iterator s = start.begin(); + s != start.end(); ++s) + { + Changed.push_back(std::make_pair(s->first, pkgCache::VerIterator(*Cache))); + // We continue here even if it failed to enhance the ShowBroken output + Success &= Cache->GetDepCache()->SetCandidateRelease(s->first, s->second, Changed); + } + for (std::list >::const_iterator c = Changed.begin(); + c != Changed.end(); ++c) + { + if (c->second.end() == true) + ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"), + c->first.VerStr(), c->first.RelStr().c_str(), c->first.ParentPkg().FullName(true).c_str()); + else if (c->first.ParentPkg()->Group != c->second.ParentPkg()->Group) + { + pkgCache::VerIterator V = (*Cache)[c->first.ParentPkg()].CandidateVerIter(*Cache); + ioprintf(out, _("Selected version '%s' (%s) for '%s' because of '%s'\n"), V.VerStr(), + V.RelStr().c_str(), V.ParentPkg().FullName(true).c_str(), c->second.ParentPkg().FullName(true).c_str()); + } + } + return Success; + } + + void doAutoInstall() { + for (APT::PackageSet::const_iterator P = doAutoInstallLater.begin(); + P != doAutoInstallLater.end(); ++P) { + pkgDepCache::StateCache &State = (*Cache)[P]; + if (State.InstBroken() == false && State.InstPolicyBroken() == false) + continue; + Cache->GetDepCache()->MarkInstall(P, true); + } + doAutoInstallLater.clear(); + } +}; + /*}}}*/ +// TryToRemove - Mark a package for removal /*{{{*/ +struct TryToRemove { + pkgCacheFile* Cache; + pkgProblemResolver* Fix; + bool PurgePkgs; + + 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(); + + 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)) + { + pkgCache::GrpIterator Grp = Pkg.Group(); + pkgCache::PkgIterator P = Grp.PackageList(); + for (; P.end() != true; P = Grp.NextPkg(P)) + { + if (P == Pkg) + continue; + if (P->CurrentVer != 0 || (PurgePkgs == true && P->CurrentState != pkgCache::State::NotInstalled)) + { + // TRANSLATORS: Note, this is not an interactive question + ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"), + Pkg.FullName(true).c_str(), P.FullName(true).c_str()); + break; + } + } + if (P.end() == true) + ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str()); + + // MarkInstall refuses to install packages on hold + Pkg->SelectedState = pkgCache::State::Hold; + } + else + Cache->GetDepCache()->MarkDelete(Pkg, PurgePkgs); + } +}; + /*}}}*/ // CacheFile::NameComp - QSort compare by name /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -633,7 +974,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; @@ -665,7 +1006,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); } @@ -756,7 +1097,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); @@ -820,20 +1161,18 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, { // force a hashsum for compatibility reasons _config->CndSet("Acquire::ForceHash", "md5sum"); - if (Fetcher.Setup(&Stat, "") == false) - return false; } else if (Fetcher.Setup(&Stat, _config->FindDir("Dir::Cache::Archives")) == false) return false; // Read the source list - pkgSourceList List; - if (List.ReadMainList() == false) - return _error->Error(_("The list of sources could not be read.")); + if (Cache.BuildSourceList() == false) + return false; + pkgSourceList *List = Cache.GetSourceList(); // Create the package manager and prepare to download SPtr PM= _system->CreatePM(Cache); - if (PM->GetArchives(&Fetcher,&List,&Recs) == false || + if (PM->GetArchives(&Fetcher,List,&Recs) == false || _error->PendingError() == true) return false; @@ -849,17 +1188,25 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, // Number of bytes if (DebBytes != FetchBytes) + //TRANSLATOR: The required space between number and unit is already included + // in the replacement strings, so %sB will be correctly translate in e.g. 1,5 MB ioprintf(c1out,_("Need to get %sB/%sB of archives.\n"), SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str()); else if (DebBytes != 0) + //TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB ioprintf(c1out,_("Need to get %sB of archives.\n"), SizeToStr(DebBytes).c_str()); // Size delta if (Cache->UsrSize() >= 0) + //TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB ioprintf(c1out,_("After this operation, %sB of additional disk space will be used.\n"), SizeToStr(Cache->UsrSize()).c_str()); else + //TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB ioprintf(c1out,_("After this operation, %sB disk space will be freed.\n"), SizeToStr(-1*Cache->UsrSize()).c_str()); @@ -944,7 +1291,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; @@ -968,7 +1315,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, { if ((*I)->Local == true) { - I++; + ++I; continue; } @@ -988,7 +1335,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) @@ -1049,7 +1396,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, // Reload the fetcher object and loop again for media swapping Fetcher.Shutdown(); - if (PM->GetArchives(&Fetcher,&List,&Recs) == false) + if (PM->GetArchives(&Fetcher,List,&Recs) == false) return false; _system->Lock(); @@ -1073,147 +1420,43 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, return true; } /*}}}*/ -// TryToInstall - Try to install a single package /*{{{*/ +// TryToInstallBuildDep - Try to install a single package /*{{{*/ // --------------------------------------------------------------------- /* This used to be inlined in DoInstall, but with the advent of regex package name matching it was split out.. */ -bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, +bool TryToInstallBuildDep(pkgCache::PkgIterator Pkg,pkgCacheFile &Cache, pkgProblemResolver &Fix,bool Remove,bool BrokenFix, bool AllowFail = true) { - - // Handle the no-upgrade case - if (_config->FindB("APT::Get::upgrade",true) == false && - Pkg->CurrentVer != 0) - { - if (AllowFail == true) - ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"), - Pkg.FullName(true).c_str()); - return true; - } - - // Ignore request for install if package would be new - if (_config->FindB("APT::Get::Only-Upgrade", false) == true && - Pkg->CurrentVer == 0) + if (Cache[Pkg].CandidateVer == 0 && Pkg->ProvidesList != 0) { - if (AllowFail == true) - ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"), - Pkg.Name()); - return true; + CacheSetHelperAPTGet helper(c1out); + helper.showErrors(AllowFail == false); + pkgCache::VerIterator Ver = helper.canNotFindNewestVer(Cache, Pkg); + if (Ver.end() == false) + Pkg = Ver.ParentPkg(); + else if (helper.showVirtualPackageErrors(Cache) == false) + return AllowFail; } - // Check if there is something at all to install - pkgDepCache::StateCache &State = Cache[Pkg]; - if (Remove == true && Pkg->CurrentVer == 0) - { - Fix.Clear(Pkg); - Fix.Protect(Pkg); - Fix.Remove(Pkg); - - /* We want to continue searching for regex hits, so we return false here - otherwise this is not really an error. */ - if (AllowFail == false) - return false; - - ioprintf(c1out,_("Package %s is not installed, so not removed\n"),Pkg.FullName(true).c_str()); - return true; - } - - if (State.CandidateVer == 0 && Remove == false) + if (_config->FindB("Debug::BuildDeps",false) == true) { - if (AllowFail == false) - return false; - - if (Pkg->ProvidesList != 0) - { - ioprintf(c1out,_("Package %s is a virtual package provided by:\n"), - Pkg.FullName(true).c_str()); - - pkgCache::PrvIterator I = Pkg.ProvidesList(); - unsigned short provider = 0; - for (; I.end() == false; I++) - { - pkgCache::PkgIterator Pkg = I.OwnerPkg(); - - if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer()) - { - c1out << " " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr(); - if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false) - c1out << _(" [Installed]"); - c1out << endl; - ++provider; - } - } - // if we found no candidate which provide this package, show non-candidates - if (provider == 0) - for (I = Pkg.ProvidesList(); I.end() == false; I++) - c1out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr() - << _(" [Not candidate version]") << endl; - else - c1out << _("You should explicitly select one to install.") << endl; - } + if (Remove == true) + cout << " Trying to remove " << Pkg << endl; else - { - ioprintf(c1out, - _("Package %s is not available, but is referred to by another package.\n" - "This may mean that the package is missing, has been obsoleted, or\n" - "is only available from another source\n"),Pkg.FullName(true).c_str()); - - string List; - string VersionsList; - SPtrArray Seen = new bool[Cache.Head().PackageCount]; - memset(Seen,0,Cache.Head().PackageCount*sizeof(*Seen)); - pkgCache::DepIterator Dep = Pkg.RevDependsList(); - for (; Dep.end() == false; Dep++) - { - if (Dep->Type != pkgCache::Dep::Replaces) - continue; - if (Seen[Dep.ParentPkg()->ID] == true) - continue; - Seen[Dep.ParentPkg()->ID] = true; - List += Dep.ParentPkg().FullName(true) + " "; - //VersionsList += string(Dep.ParentPkg().CurVersion) + "\n"; ??? - } - ShowList(c1out,_("However the following packages replace it:"),List,VersionsList); - } - - _error->Error(_("Package %s has no installation candidate"),Pkg.FullName(true).c_str()); - return false; + cout << " Trying to install " << Pkg << endl; } - Fix.Clear(Pkg); - Fix.Protect(Pkg); if (Remove == true) { - Fix.Remove(Pkg); - Cache.MarkDelete(Pkg,_config->FindB("APT::Get::Purge",false)); - return true; - } - - // Install it - Cache.MarkInstall(Pkg,false); - if (State.Install() == false) - { - if (_config->FindB("APT::Get::ReInstall",false) == true) - { - if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false) - ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"), - Pkg.FullName(true).c_str()); - else - Cache.SetReInstall(Pkg,true); - } - else - { - if (AllowFail == true) - ioprintf(c1out,_("%s is already the newest version.\n"), - Pkg.FullName(true).c_str()); - } - } - - // Install it with autoinstalling enabled (if we not respect the minial - // required deps or the policy) - if ((State.InstBroken() == true || State.InstPolicyBroken() == true) && BrokenFix == false) - Cache.MarkInstall(Pkg,true); + TryToRemove RemoveAction(Cache, &Fix); + RemoveAction(Pkg.VersionList()); + } else if (Cache[Pkg].CandidateVer != 0) { + TryToInstall InstallAction(Cache, &Fix, BrokenFix); + InstallAction(Cache[Pkg].CandidateVerIter(Cache)); + InstallAction.doAutoInstall(); + } else + return AllowFail; return true; } @@ -1252,7 +1495,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) @@ -1273,7 +1516,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) @@ -1397,11 +1640,13 @@ bool DoUpdate(CommandLine &CmdL) { if (CmdL.FileSize() != 1) return _error->Error(_("The update command takes no arguments")); - + + CacheFile Cache; + // Get the source list - pkgSourceList List; - if (List.ReadMainList() == false) + if (Cache.BuildSourceList() == false) return false; + pkgSourceList *List = Cache.GetSourceList(); // Create the progress AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); @@ -1419,22 +1664,22 @@ bool DoUpdate(CommandLine &CmdL) // Populate it with the source selection and get all Indexes // (GetAll=true) - if (List.GetIndexes(&Fetcher,true) == false) + if (List->GetIndexes(&Fetcher,true) == false) 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; } // do the work - CacheFile Cache; if (_config->FindB("APT::Get::Download",true) == true) - ListUpdate(Stat, List); + ListUpdate(Stat, *List); - // Rebuild the cache. + // Rebuild the cache. + pkgCacheFile::RemoveCaches(); if (Cache.BuildCaches() == false) return false; @@ -1454,10 +1699,6 @@ bool DoAutomaticRemove(CacheFile &Cache) if(Debug) std::cout << "DoAutomaticRemove()" << std::endl; - // we don't want to autoremove and we don't want to see it, so why calculating? - if (doAutoRemove == false && hideAutoRemove == true) - return true; - if (doAutoRemove == true && _config->FindB("APT::Get::Remove",true) == false) { @@ -1468,10 +1709,11 @@ bool DoAutomaticRemove(CacheFile &Cache) bool purgePkgs = _config->FindB("APT::Get::Purge", false); bool smallList = (hideAutoRemove == false && - strcasecmp(_config->Find("APT::Get::HideAutoRemove","").c_str(),"small") == 0); + strcasecmp(_config->Find("APT::Get::HideAutoRemove","").c_str(),"small") == 0); 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) { @@ -1491,8 +1733,16 @@ bool DoAutomaticRemove(CacheFile &Cache) } else { + // 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) + { + if (Pkg.CandVersion() != 0) + tooMuch.insert(Pkg); + Cache->MarkDelete(Pkg, false); + } // only show stuff in the list that is not yet marked for removal - if(Cache[Pkg].Delete() == false) + else if(hideAutoRemove == false && Cache[Pkg].Delete() == false) { ++autoRemoveCount; // we don't need to fill the strings if we don't need them @@ -1505,20 +1755,56 @@ bool DoAutomaticRemove(CacheFile &Cache) } } } - // if we don't remove them, we should show them! - if (doAutoRemove == false && (autoremovelist.empty() == false || autoRemoveCount != 0)) + + // 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)) { - if (smallList == false) - ShowList(c1out, P_("The following package is automatically installed and is no longer required:", - "The following packages were automatically installed and are no longer required:", - autoRemoveCount), autoremovelist, autoremoveversions); - else - ioprintf(c1out, P_("%lu package was automatically installed and is no longer required.\n", - "%lu packages were automatically installed and are no longer required.\n", autoRemoveCount), autoRemoveCount); - c1out << _("Use 'apt-get autoremove' to remove them.") << std::endl; + bool Changed; + do { + Changed = false; + for (APT::PackageSet::const_iterator Pkg = tooMuch.begin(); + Pkg != tooMuch.end() && Changed == false; ++Pkg) + { + APT::PackageSet too; + too.insert(*Pkg); + for (pkgCache::PrvIterator Prv = Cache[Pkg].CandidateVerIter(Cache).ProvidesList(); + Prv.end() == false; ++Prv) + too.insert(Prv.ParentPkg()); + for (APT::PackageSet::const_iterator P = too.begin(); + P != too.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 " << Pkg << " as another installed garbage package depends on it" << std::endl; + Cache->MarkInstall(Pkg, false); + if (hideAutoRemove == false) + { + ++autoRemoveCount; + if (smallList == false) + { + autoremovelist += Pkg.FullName(true) + " "; + autoremoveversions += string(Cache[Pkg].CandVersion) + "\n"; + } + } + tooMuch.erase(Pkg); + Changed = true; + break; + } + } + } + } while (Changed == true); } + // Now see if we had destroyed anything (if we had done anything) - else if (Cache->BrokenCount() != 0) + if (Cache->BrokenCount() != 0) { c1out << _("Hmm, seems like the AutoRemover destroyed something which really\n" "shouldn't happen. Please file a bug report against apt.") << endl; @@ -1529,6 +1815,19 @@ bool DoAutomaticRemove(CacheFile &Cache) return _error->Error(_("Internal Error, AutoRemover broke stuff")); } + + // if we don't remove them, we should show them! + if (doAutoRemove == false && (autoremovelist.empty() == false || autoRemoveCount != 0)) + { + if (smallList == false) + ShowList(c1out, P_("The following package was automatically installed and is no longer required:", + "The following packages were automatically installed and are no longer required:", + autoRemoveCount), autoremovelist, autoremoveversions); + else + ioprintf(c1out, P_("%lu package was automatically installed and is no longer required.\n", + "%lu packages were automatically installed and are no longer required.\n", autoRemoveCount), autoRemoveCount); + c1out << _("Use 'apt-get autoremove' to remove them.") << std::endl; + } return true; } /*}}}*/ @@ -1552,105 +1851,24 @@ bool DoUpgrade(CommandLine &CmdL) return InstallPackages(Cache,true); } /*}}}*/ -// CacheSetHelperAPTGet - responsible for message telling from the CacheSets/*{{{*/ -class CacheSetHelperAPTGet : public APT::CacheSetHelper { - /** \brief stream message should be printed to */ - std::ostream &out; - /** \brief were things like Task or RegEx used to select packages? */ - bool explicitlyNamed; +// DoInstall - Install packages from the command line /*{{{*/ +// --------------------------------------------------------------------- +/* Install named packages */ +bool DoInstall(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.OpenForInstall() == false || + Cache.CheckDeps(CmdL.FileSize() != 1) == false) + return false; + + // Enter the special broken fixing mode if the user specified arguments + bool BrokenFix = false; + if (Cache->BrokenCount() != 0) + BrokenFix = true; -public: - CacheSetHelperAPTGet(std::ostream &out) : APT::CacheSetHelper(true), out(out) { - explicitlyNamed = true; - } - - virtual void showTaskSelection(APT::PackageSet const &pkgset, string const &pattern) { - for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg) - ioprintf(out, _("Note, selecting '%s' for task '%s'\n"), - Pkg.FullName(true).c_str(), pattern.c_str()); - explicitlyNamed = false; - } - virtual void showRegExSelection(APT::PackageSet const &pkgset, string const &pattern) { - for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg) - ioprintf(out, _("Note, selecting '%s' for regex '%s'\n"), - Pkg.FullName(true).c_str(), pattern.c_str()); - explicitlyNamed = false; - } - virtual void showSelectedVersion(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const Ver, - string const &ver, bool const &verIsRel) { - if (ver != Ver.VerStr()) - ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"), - Ver.VerStr(), Ver.RelStr().c_str(), Pkg.FullName(true).c_str()); - } - - virtual APT::VersionSet canNotFindCandInstVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { - return tryVirtualPackage(Cache, Pkg, APT::VersionSet::CANDINST); - } - - virtual APT::VersionSet canNotFindInstCandVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { - return tryVirtualPackage(Cache, Pkg, APT::VersionSet::INSTCAND); - } - - APT::VersionSet tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg, - APT::VersionSet::Version const &select) { - /* This is a pure virtual package and there is a single available - candidate providing it. */ - if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0) { - if (select == APT::VersionSet::CANDINST) - return APT::CacheSetHelper::canNotFindCandInstVer(Cache, Pkg); - return APT::CacheSetHelper::canNotFindInstCandVer(Cache, Pkg); - } - - pkgCache::PkgIterator Prov; - bool found_one = false; - for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; ++P) { - pkgCache::VerIterator const PVer = P.OwnerVer(); - pkgCache::PkgIterator const PPkg = PVer.ParentPkg(); - - /* Ignore versions that are not a candidate. */ - if (Cache[PPkg].CandidateVer != PVer) - continue; - - if (found_one == false) { - Prov = PPkg; - found_one = true; - } else if (PPkg != Prov) { - found_one = false; // we found at least two - break; - } - } - - if (found_one == true) { - ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"), - Prov.FullName(true).c_str(), Pkg.FullName(true).c_str()); - return APT::VersionSet::FromPackage(Cache, Prov, select, *this); - } - if (select == APT::VersionSet::CANDINST) - return APT::CacheSetHelper::canNotFindCandInstVer(Cache, Pkg); - return APT::CacheSetHelper::canNotFindInstCandVer(Cache, Pkg); - } - - inline bool allPkgNamedExplicitly() const { return explicitlyNamed; } - -}; - /*}}}*/ -// DoInstall - Install packages from the command line /*{{{*/ -// --------------------------------------------------------------------- -/* Install named packages */ -bool DoInstall(CommandLine &CmdL) -{ - CacheFile Cache; - if (Cache.OpenForInstall() == false || - Cache.CheckDeps(CmdL.FileSize() != 1) == false) - return false; - - // Enter the special broken fixing mode if the user specified arguments - bool BrokenFix = false; - if (Cache->BrokenCount() != 0) - BrokenFix = true; - - unsigned int AutoMarkChanged = 0; - 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; @@ -1671,68 +1889,55 @@ bool DoInstall(CommandLine &CmdL) std::list mods; mods.push_back(APT::VersionSet::Modifier(MOD_INSTALL, "+", - APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDINST)); + APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDIDATE)); mods.push_back(APT::VersionSet::Modifier(MOD_REMOVE, "-", - APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::INSTCAND)); + APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::NEWEST)); CacheSetHelperAPTGet helper(c0out); std::map verset = APT::VersionSet::GroupedFromCommandLine(Cache, CmdL.FileList + 1, mods, fallback, helper); if (_error->PendingError() == true) + { + helper.showVirtualPackageErrors(Cache); + if (Fix != NULL) + delete Fix; return false; - - unsigned short order[] = { 0, 0, 0 }; - if (fallback == MOD_INSTALL) { - order[0] = MOD_INSTALL; - order[1] = MOD_REMOVE; - } else { - order[0] = MOD_REMOVE; - order[1] = MOD_INSTALL; } + unsigned short const order[] = { MOD_REMOVE, MOD_INSTALL, 0 }; + + TryToInstall InstallAction(Cache, Fix, BrokenFix); + TryToRemove RemoveAction(Cache, Fix); + // new scope for the ActionGroup { pkgDepCache::ActionGroup group(Cache); + for (unsigned short i = 0; order[i] != 0; ++i) { if (order[i] == MOD_INSTALL) - for (APT::VersionSet::const_iterator Ver = verset[MOD_INSTALL].begin(); - Ver != verset[MOD_INSTALL].end(); ++Ver) - { - pkgCache::PkgIterator Pkg = Ver.ParentPkg(); - Cache->SetCandidateVersion(Ver); - - if (TryToInstall(Pkg, Cache, Fix, false, BrokenFix) == false) - return false; - - // see if we need to fix the auto-mark flag - // e.g. apt-get install foo - // where foo is marked automatic - if (Cache[Pkg].Install() == false && - (Cache[Pkg].Flags & pkgCache::Flag::Auto) && - _config->FindB("APT::Get::ReInstall",false) == false && - _config->FindB("APT::Get::Only-Upgrade",false) == false && - _config->FindB("APT::Get::Download-Only",false) == false) - { - ioprintf(c1out,_("%s set to manually installed.\n"), - Pkg.FullName(true).c_str()); - Cache->MarkAuto(Pkg,false); - AutoMarkChanged++; - } - } + InstallAction = std::for_each(verset[MOD_INSTALL].begin(), verset[MOD_INSTALL].end(), InstallAction); else if (order[i] == MOD_REMOVE) - for (APT::VersionSet::const_iterator Ver = verset[MOD_REMOVE].begin(); - Ver != verset[MOD_REMOVE].end(); ++Ver) - { - pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + RemoveAction = std::for_each(verset[MOD_REMOVE].begin(), verset[MOD_REMOVE].end(), RemoveAction); + } - if (TryToInstall(Pkg, Cache, Fix, true, BrokenFix) == false) - return false; - } + 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(); + } } 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 @@ -1741,14 +1946,18 @@ 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(); + Fix->Resolve(true); + delete Fix; + } // Now we check the state of the packages, if (Cache->BrokenCount() != 0) @@ -1772,8 +1981,11 @@ bool DoInstall(CommandLine &CmdL) c1out << _("The following information may help to resolve the situation:") << endl; c1out << endl; ShowBroken(c1out,Cache,false); - return _error->Error(_("Broken packages")); - } + if (_error->PendingError() == true) + return false; + else + return _error->Error(_("Broken packages")); + } } if (!DoAutomaticRemove(Cache)) return false; @@ -1789,16 +2001,13 @@ bool DoInstall(CommandLine &CmdL) pkgCache::PkgIterator I(Cache,Cache.List[J]); if ((*Cache)[I].Install() == false) continue; + pkgCache::VerIterator Cand = Cache[I].CandidateVerIter(Cache); - const char **J; - for (J = CmdL.FileList + 1; *J != 0; J++) - if (strcmp(*J,I.Name()) == 0) - break; - - if (*J == 0) { - List += I.FullName(true) + " "; - VersionsList += string(Cache[I].CandVersion) + "\n"; - } + if (verset[MOD_INSTALL].find(Cand) != verset[MOD_INSTALL].end()) + continue; + + List += I.FullName(true) + " "; + VersionsList += string(Cache[I].CandVersion) + "\n"; } ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList); @@ -1854,7 +2063,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() && @@ -1877,7 +2086,7 @@ bool DoInstall(CommandLine &CmdL) if (Start >= End) break; - Start++; + ++Start; } if(foundInstalledInOrGroup == false) @@ -1899,7 +2108,7 @@ bool DoInstall(CommandLine &CmdL) // if nothing changed in the cache, but only the automark information // we write the StateFile here, otherwise it will be written in // cache.commit() - if (AutoMarkChanged > 0 && + if (InstallAction.AutoMarkChanged > 0 && Cache->DelCount() == 0 && Cache->InstCount() == 0 && Cache->BadCount() == 0 && _config->FindB("APT::Get::Simulate",false) == false) @@ -1912,8 +2121,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; @@ -1948,6 +2157,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; @@ -1988,7 +2200,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 */ @@ -1998,7 +2210,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 */ @@ -2007,7 +2219,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 || @@ -2024,7 +2236,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) { @@ -2056,10 +2268,14 @@ bool DoDSelectUpgrade(CommandLine &CmdL) /* */ bool DoClean(CommandLine &CmdL) { + std::string const archivedir = _config->FindDir("Dir::Cache::archives"); + std::string const pkgcache = _config->FindFile("Dir::cache::pkgcache"); + std::string const srcpkgcache = _config->FindFile("Dir::cache::srcpkgcache"); + if (_config->FindB("APT::Get::Simulate") == true) { - cout << "Del " << _config->FindDir("Dir::Cache::archives") << "* " << - _config->FindDir("Dir::Cache::archives") << "partial/*" << endl; + cout << "Del " << archivedir << "* " << archivedir << "partial/*"<< endl + << "Del " << pkgcache << " " << srcpkgcache << endl; return true; } @@ -2067,14 +2283,17 @@ bool DoClean(CommandLine &CmdL) FileFd Lock; if (_config->FindB("Debug::NoLocking",false) == false) { - Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock")); + Lock.Fd(GetLock(archivedir + "lock")); if (_error->PendingError() == true) return _error->Error(_("Unable to lock the download directory")); } pkgAcquire Fetcher; - Fetcher.Clean(_config->FindDir("Dir::Cache::archives")); - Fetcher.Clean(_config->FindDir("Dir::Cache::archives") + "partial/"); + Fetcher.Clean(archivedir); + Fetcher.Clean(archivedir + "partial/"); + + pkgCacheFile::RemoveCaches(); + return true; } /*}}}*/ @@ -2115,6 +2334,72 @@ bool DoAutoClean(CommandLine &CmdL) Cleaner.Go(_config->FindDir("Dir::Cache::archives") + "partial/",*Cache); } /*}}}*/ +// DoDownload - download a binary /*{{{*/ +// --------------------------------------------------------------------- +bool DoDownload(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.ReadOnlyOpen() == false) + return false; + + APT::CacheSetHelper helper(c0out); + APT::VersionList verset = APT::VersionList::FromCommandLine(Cache, + CmdL.FileList + 1, APT::VersionList::CANDIDATE, helper); + + if (verset.empty() == true) + return false; + + pkgAcquire Fetcher; + AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); + if (_config->FindB("APT::Get::Print-URIs") == false) + Fetcher.Setup(&Stat); + + pkgRecords Recs(Cache); + pkgSourceList *SrcList = Cache.GetSourceList(); + for (APT::VersionList::const_iterator Ver = verset.begin(); + Ver != verset.end(); + ++Ver) + { + string descr; + // get the right version + pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + pkgRecords::Parser &rec=Recs.Lookup(Ver.FileList()); + pkgCache::VerFileIterator Vf = Ver.FileList(); + if (Vf.end() == true) + return _error->Error("Can not find VerFile"); + pkgCache::PkgFileIterator F = Vf.File(); + pkgIndexFile *index; + if(SrcList->FindIndex(F, index) == false) + return _error->Error("FindIndex failed"); + string uri = index->ArchiveURI(rec.FileName()); + strprintf(descr, _("Downloading %s %s"), Pkg.Name(), Ver.VerStr()); + // get the most appropriate hash + HashString hash; + if (rec.SHA512Hash() != "") + hash = HashString("sha512", rec.SHA512Hash()); + if (rec.SHA256Hash() != "") + hash = HashString("sha256", rec.SHA256Hash()); + else if (rec.SHA1Hash() != "") + hash = HashString("sha1", rec.SHA1Hash()); + else if (rec.MD5Hash() != "") + hash = HashString("md5", rec.MD5Hash()); + // get the file + new pkgAcqFile(&Fetcher, uri, hash.toStr(), (*Ver)->Size, descr, Pkg.Name(), "."); + } + + // Just print out the uris and 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->HashSum() << endl; + return true; + } + + return (Fetcher.Run() == pkgAcquire::Continue); +} + /*}}}*/ // DoCheck - Perform the check operation /*{{{*/ // --------------------------------------------------------------------- /* Opening automatically checks the system, this command is mostly used @@ -2148,21 +2433,20 @@ bool DoSource(CommandLine &CmdL) return _error->Error(_("Must specify at least one package to fetch source for")); // Read the source list - pkgSourceList List; - if (List.ReadMainList() == false) - return _error->Error(_("The list of sources could not be read.")); + if (Cache.BuildSourceList() == false) + return false; + pkgSourceList *List = Cache.GetSourceList(); // Create the text record parsers pkgRecords Recs(Cache); - pkgSrcRecords SrcRecs(List); + pkgSrcRecords SrcRecs(*List); if (_error->PendingError() == true) return false; // 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()]; @@ -2184,8 +2468,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-"); @@ -2216,12 +2502,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") @@ -2278,6 +2566,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()); @@ -2291,16 +2580,22 @@ 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) + //TRANSLATOR: The required space between number and unit is already included + // in the replacement strings, so %sB will be correctly translate in e.g. 1,5 MB ioprintf(c1out,_("Need to get %sB/%sB of source archives.\n"), SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str()); else + //TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB ioprintf(c1out,_("Need to get %sB of source archives.\n"), SizeToStr(DebBytes).c_str()); @@ -2316,7 +2611,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; @@ -2325,11 +2620,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) @@ -2340,8 +2638,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; @@ -2355,7 +2656,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()); @@ -2391,12 +2692,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) { @@ -2432,6 +2738,9 @@ bool DoSource(CommandLine &CmdL) bool DoBuildDep(CommandLine &CmdL) { CacheFile Cache; + + _config->Set("APT::Install-Recommends", false); + if (Cache.Open(true) == false) return false; @@ -2439,13 +2748,13 @@ bool DoBuildDep(CommandLine &CmdL) 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.")); + if (Cache.BuildSourceList() == false) + return false; + pkgSourceList *List = Cache.GetSourceList(); // Create the text record parsers pkgRecords Recs(Cache); - pkgSrcRecords SrcRecs(List); + pkgSrcRecords SrcRecs(*List); if (_error->PendingError() == true) return false; @@ -2455,6 +2764,18 @@ 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; for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) { @@ -2465,7 +2786,7 @@ bool DoBuildDep(CommandLine &CmdL) // Process the build-dependencies vector BuildDeps; - if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",true)) == false) + if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch) == false) return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str()); // Also ensure that build-essential packages are present @@ -2484,22 +2805,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; @@ -2508,27 +2839,123 @@ 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) - TryToInstall(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) + { + if (colon == string::npos) + { + Pkg = Ver.ParentPkg().Group().FindPkg(hostArch); + } + } + 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) == pkgCache::Version::Foreign) + { + if (colon != string::npos) + forbidden = "Multi-Arch: foreign"; + } + else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed) + { + 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) @@ -2543,101 +2970,76 @@ 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 (TryToInstall(Pkg,Cache,Fix,false,false) == true) + if (TryToInstallBuildDep(Pkg,Cache,Fix,false,false) == true) { // We successfully installed something; skip remaining alternatives skipAlternatives = hasAlternatives; @@ -2678,6 +3080,199 @@ bool DoBuildDep(CommandLine &CmdL) return true; } /*}}}*/ +// GetChangelogPath - return a path pointing to a changelog file or dir /*{{{*/ +// --------------------------------------------------------------------- +/* This returns a "path" string for the changelog url construction. + * Please note that its not complete, it either needs a "/changelog" + * appended (for the packages.debian.org/changelogs site) or a + * ".changelog" (for third party sites that store the changelog in the + * pool/ next to the deb itself) + * Example return: "pool/main/a/apt/apt_0.8.8ubuntu3" + */ +string GetChangelogPath(CacheFile &Cache, + pkgCache::PkgIterator Pkg, + pkgCache::VerIterator Ver) +{ + string path; + + pkgRecords Recs(Cache); + pkgRecords::Parser &rec=Recs.Lookup(Ver.FileList()); + string srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg(); + string ver = Ver.VerStr(); + // if there is a source version it always wins + if (rec.SourceVer() != "") + ver = rec.SourceVer(); + path = flNotFile(rec.FileName()); + path += srcpkg + "_" + StripEpoch(ver); + return path; +} + /*}}}*/ +// GuessThirdPartyChangelogUri - return url /*{{{*/ +// --------------------------------------------------------------------- +/* Contruct a changelog file path for third party sites that do not use + * packages.debian.org/changelogs + * This simply uses the ArchiveURI() of the source pkg and looks for + * a .changelog file there, Example for "mediabuntu": + * apt-get changelog mplayer-doc: + * http://packages.medibuntu.org/pool/non-free/m/mplayer/mplayer_1.0~rc4~try1.dsfg1-1ubuntu1+medibuntu1.changelog + */ +bool GuessThirdPartyChangelogUri(CacheFile &Cache, + pkgCache::PkgIterator Pkg, + pkgCache::VerIterator Ver, + string &out_uri) +{ + // get the binary deb server path + pkgCache::VerFileIterator Vf = Ver.FileList(); + if (Vf.end() == true) + return false; + pkgCache::PkgFileIterator F = Vf.File(); + pkgIndexFile *index; + pkgSourceList *SrcList = Cache.GetSourceList(); + if(SrcList->FindIndex(F, index) == false) + return false; + + // get archive uri for the binary deb + string path_without_dot_changelog = GetChangelogPath(Cache, Pkg, Ver); + out_uri = index->ArchiveURI(path_without_dot_changelog + ".changelog"); + + // now strip away the filename and add srcpkg_srcver.changelog + return true; +} + /*}}}*/ +// DownloadChangelog - Download the changelog /*{{{*/ +// --------------------------------------------------------------------- +bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, + pkgCache::VerIterator Ver, string targetfile) +/* Download a changelog file for the given package version to + * targetfile. This will first try the server from Apt::Changelogs::Server + * (http://packages.debian.org/changelogs by default) and if that gives + * a 404 tries to get it from the archive directly (see + * GuessThirdPartyChangelogUri for details how) + */ +{ + string path; + string descr; + string server; + string changelog_uri; + + // data structures we need + pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + + // make the server root configurable + server = _config->Find("Apt::Changelogs::Server", + "http://packages.debian.org/changelogs"); + path = GetChangelogPath(CacheFile, Pkg, Ver); + strprintf(changelog_uri, "%s/%s/changelog", server.c_str(), path.c_str()); + if (_config->FindB("APT::Get::Print-URIs", false) == true) + { + std::cout << '\'' << changelog_uri << '\'' << std::endl; + return true; + } + + strprintf(descr, _("Changelog for %s (%s)"), Pkg.Name(), changelog_uri.c_str()); + // queue it + new pkgAcqFile(&Fetcher, changelog_uri, "", 0, descr, Pkg.Name(), "ignored", targetfile); + + // try downloading it, if that fails, try third-party-changelogs location + // FIXME: Fetcher.Run() is "Continue" even if I get a 404?!? + Fetcher.Run(); + if (!FileExists(targetfile)) + { + string third_party_uri; + if (GuessThirdPartyChangelogUri(CacheFile, Pkg, Ver, third_party_uri)) + { + strprintf(descr, _("Changelog for %s (%s)"), Pkg.Name(), third_party_uri.c_str()); + new pkgAcqFile(&Fetcher, third_party_uri, "", 0, descr, Pkg.Name(), "ignored", targetfile); + Fetcher.Run(); + } + } + + if (FileExists(targetfile)) + return true; + + // error + return _error->Error("changelog download failed"); +} + /*}}}*/ +// DisplayFileInPager - Display File with pager /*{{{*/ +void DisplayFileInPager(string filename) +{ + pid_t Process = ExecFork(); + if (Process == 0) + { + const char *Args[3]; + Args[0] = "/usr/bin/sensible-pager"; + Args[1] = filename.c_str(); + Args[2] = 0; + execvp(Args[0],(char **)Args); + exit(100); + } + + // Wait for the subprocess + ExecWait(Process, "sensible-pager", false); +} + /*}}}*/ +// DoChangelog - Get changelog from the command line /*{{{*/ +// --------------------------------------------------------------------- +bool DoChangelog(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.ReadOnlyOpen() == false) + return false; + + APT::CacheSetHelper helper(c0out); + APT::VersionList verset = APT::VersionList::FromCommandLine(Cache, + CmdL.FileList + 1, APT::VersionList::CANDIDATE, helper); + if (verset.empty() == true) + return false; + pkgAcquire Fetcher; + + if (_config->FindB("APT::Get::Print-URIs", false) == true) + for (APT::VersionList::const_iterator Ver = verset.begin(); + Ver != verset.end(); ++Ver) + return DownloadChangelog(Cache, Fetcher, Ver, ""); + + AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); + Fetcher.Setup(&Stat); + + bool const downOnly = _config->FindB("APT::Get::Download-Only", false); + + char tmpname[100]; + char* tmpdir = NULL; + if (downOnly == false) + { + const char* const tmpDir = getenv("TMPDIR"); + if (tmpDir != NULL && *tmpDir != '\0') + snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", tmpDir); + else + strncpy(tmpname, "/tmp/apt-changelog-XXXXXX", sizeof(tmpname)); + tmpdir = mkdtemp(tmpname); + if (tmpdir == NULL) + return _error->Errno("mkdtemp", "mkdtemp failed"); + } + + for (APT::VersionList::const_iterator Ver = verset.begin(); + Ver != verset.end(); + ++Ver) + { + string changelogfile; + if (downOnly == false) + changelogfile.append(tmpname).append("changelog"); + else + changelogfile.append(Ver.ParentPkg().Name()).append(".changelog"); + if (DownloadChangelog(Cache, Fetcher, Ver, changelogfile) && downOnly == false) + { + DisplayFileInPager(changelogfile); + // cleanup temp file + unlink(changelogfile.c_str()); + } + } + // clenaup tmp dir + if (tmpdir != NULL) + rmdir(tmpdir); + return true; +} + /*}}}*/ // DoMoo - Never Ask, Never Tell /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -2768,8 +3363,8 @@ 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" "Options:\n" " -h This help text.\n" @@ -2791,22 +3386,6 @@ bool ShowHelp(CommandLine &CmdL) return true; } /*}}}*/ -// GetInitialize - Initialize things for apt-get /*{{{*/ -// --------------------------------------------------------------------- -/* */ -void GetInitialize() -{ - _config->Set("quiet",0); - _config->Set("help",false); - _config->Set("APT::Get::Download-Only",false); - _config->Set("APT::Get::Simulate",false); - _config->Set("APT::Get::Assume-Yes",false); - _config->Set("APT::Get::Fix-Broken",false); - _config->Set("APT::Get::Force-Yes",false); - _config->Set("APT::Get::List-Cleanup",true); - _config->Set("APT::Get::AutomaticRemove",false); -} - /*}}}*/ // SigWinch - Window size change signal handler /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -2838,12 +3417,14 @@ int main(int argc,const char *argv[]) /*{{{*/ {'s',"dry-run","APT::Get::Simulate",0}, {'s',"no-act","APT::Get::Simulate",0}, {'y',"yes","APT::Get::Assume-Yes",0}, - {'y',"assume-yes","APT::Get::Assume-Yes",0}, + {'y',"assume-yes","APT::Get::Assume-Yes",0}, + {0,"assume-no","APT::Get::Assume-No",0}, {'f',"fix-broken","APT::Get::Fix-Broken",0}, {'u',"show-upgraded","APT::Get::Show-Upgraded",0}, {'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}, @@ -2865,7 +3446,9 @@ int main(int argc,const char *argv[]) /*{{{*/ {0,"auto-remove","APT::Get::AutomaticRemove",0}, {0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0}, {0,"install-recommends","APT::Install-Recommends",CommandLine::Boolean}, + {0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean}, {0,"fix-policy","APT::Get::Fix-Policy-Broken",0}, + {0,"solver","APT::Solver",CommandLine::HasArg}, {'c',"config-file",0,CommandLine::ConfigFile}, {'o',"option",0,CommandLine::ArbItem}, {0,0,0,0}}; @@ -2884,6 +3467,8 @@ int main(int argc,const char *argv[]) /*{{{*/ {"autoclean",&DoAutoClean}, {"check",&DoCheck}, {"source",&DoSource}, + {"download",&DoDownload}, + {"changelog",&DoChangelog}, {"moo",&DoMoo}, {"help",&ShowHelp}, {0,0}}; @@ -2915,7 +3500,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"