X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/59d6e5b06c25acdd6583ea801740c36acabc19ac..a249b3e6fd798935a02b769149c9791a6fa6ef16:/apt-private/private-install.cc diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index a365d4294..3f57b55e2 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -19,16 +19,16 @@ #include #include #include +#include +#include -#include #include #include -#include -#include #include #include #include #include +#include #include #include @@ -41,6 +41,37 @@ /*}}}*/ class pkgSourceList; +bool CheckNothingBroken(CacheFile &Cache) /*{{{*/ +{ + // Now we check the state of the packages, + if (Cache->BrokenCount() == 0) + return true; + + c1out << + _("Some packages could not be installed. This may mean that you have\n" + "requested an impossible situation or if you are using the unstable\n" + "distribution that some required packages have not yet been created\n" + "or been moved out of Incoming.") << std::endl; + /* + if (Packages == 1) + { + c1out << std::endl; + c1out << + _("Since you only requested a single operation it is extremely likely that\n" + "the package is simply not installable and a bug report against\n" + "that package should be filed.") << std::endl; + } + */ + + c1out << _("The following information may help to resolve the situation:") << std::endl; + c1out << std::endl; + ShowBroken(c1out,Cache,false); + if (_error->PendingError() == true) + return false; + else + return _error->Error(_("Broken packages")); +} + /*}}}*/ // InstallPackages - Actually download and install the packages /*{{{*/ // --------------------------------------------------------------------- /* This displays the informative messages describing what is going to @@ -57,7 +88,8 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) } } - bool Fail = false; + bool Hold = false; + bool Downgrade = false; bool Essential = false; // Show all the various warning indicators @@ -65,13 +97,17 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) ShowNew(c1out,Cache); if (ShwKept == true) ShowKept(c1out,Cache); - Fail |= !ShowHold(c1out,Cache); + Hold = !ShowHold(c1out,Cache); if (_config->FindB("APT::Get::Show-Upgraded",true) == true) ShowUpgraded(c1out,Cache); - Fail |= !ShowDowngraded(c1out,Cache); + Downgrade = !ShowDowngraded(c1out,Cache); + if (_config->FindB("APT::Get::Download-Only",false) == false) Essential = !ShowEssential(c1out,Cache); - Fail |= Essential; + + // All kinds of failures + bool Fail = (Essential || Downgrade || Hold); + Stats(c1out,Cache); // Sanity check @@ -88,20 +124,33 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) // No remove flag if (Cache->DelCount() != 0 && _config->FindB("APT::Get::Remove",true) == false) return _error->Error(_("Packages need to be removed but remove is disabled.")); - + + // Fail safe check + if (_config->FindI("quiet",0) >= 2 || + _config->FindB("APT::Get::Assume-Yes",false) == true) + { + if (_config->FindB("APT::Get::Force-Yes",false) == true) { + _error->Warning(_("--force-yes is deprecated, use one of the options starting with --allow instead.")); + } + + if (Fail == true && _config->FindB("APT::Get::Force-Yes",false) == false) { + if (Essential == true && _config->FindB("APT::Get::allow-remove-essential", false) == false) + return _error->Error(_("Essential packages were removed and -y was used without --allow-remove-essential.")); + if (Downgrade == true && _config->FindB("APT::Get::allow-downgrades", false) == false) + return _error->Error(_("Packages were downgraded and -y was used without --allow-downgrades.")); + if (Hold == true && _config->FindB("APT::Get::allow-change-held-packages", false) == false) + return _error->Error(_("Held packages were changed and -y was used without --allow-change-held-packages.")); + } + } + // Run the simulator .. if (_config->FindB("APT::Get::Simulate") == true) { pkgSimulate PM(Cache); -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) APT::Progress::PackageManager *progress = APT::Progress::PackageManagerProgressFactory(); pkgPackageManager::OrderResult Res = PM.DoInstall(progress); delete progress; -#else - int status_fd = _config->FindI("APT::Status-Fd",-1); - pkgPackageManager::OrderResult Res = PM.DoInstall(status_fd); -#endif if (Res == pkgPackageManager::Failed) return false; @@ -116,14 +165,13 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) return false; // Create the download object - pkgAcquire Fetcher; - AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); + aptAcquireWithTextStatus Fetcher; if (_config->FindB("APT::Get::Print-URIs", false) == true) { // force a hashsum for compatibility reasons _config->CndSet("Acquire::ForceHash", "md5sum"); } - else if (Fetcher.Setup(&Stat, _config->FindDir("Dir::Cache::Archives")) == false) + else if (Fetcher.GetLock(_config->FindDir("Dir::Cache::Archives")) == false) return false; // Read the source list @@ -132,7 +180,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) pkgSourceList *List = Cache.GetSourceList(); // Create the package manager and prepare to download - SPtr PM= _system->CreatePM(Cache); + std::unique_ptr PM(_system->CreatePM(Cache)); if (PM->GetArchives(&Fetcher,List,&Recs) == false || _error->PendingError() == true) return false; @@ -174,42 +222,10 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) if (_error->PendingError() == true) return false; - /* Check for enough free space, but only if we are actually going to - download */ - if (_config->FindB("APT::Get::Print-URIs") == false && - _config->FindB("APT::Get::Download",true) == true) - { - struct statvfs Buf; - std::string OutputDir = _config->FindDir("Dir::Cache::Archives"); - if (statvfs(OutputDir.c_str(),&Buf) != 0) { - if (errno == EOVERFLOW) - return _error->WarningE("statvfs",_("Couldn't determine free space in %s"), - OutputDir.c_str()); - else - return _error->Errno("statvfs",_("Couldn't determine free space in %s"), - OutputDir.c_str()); - } else if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) - { - struct statfs Stat; - if (statfs(OutputDir.c_str(),&Stat) != 0 -#if HAVE_STRUCT_STATFS_F_TYPE - || unsigned(Stat.f_type) != RAMFS_MAGIC -#endif - ) - return _error->Error(_("You don't have enough free space in %s."), - OutputDir.c_str()); - } - } - - // Fail safe check - if (_config->FindI("quiet",0) >= 2 || - _config->FindB("APT::Get::Assume-Yes",false) == true) - { - if (Fail == true && _config->FindB("APT::Get::Force-Yes",false) == false) - return _error->Error(_("There are problems and -y was used without --force-yes")); - } + if (CheckFreeSpaceBeforeDownload(_config->FindDir("Dir::Cache::Archives"), (FetchBytes - FetchPBytes)) == false) + return false; - if (Essential == true && Safety == true) + if (Essential == true && Safety == true && _config->FindB("APT::Get::allow-remove-essential", false) == false) { if (_config->FindB("APT::Get::Trivial-Only",false) == true) return _error->Error(_("Trivial Only specified but this is not a trivial operation.")); @@ -330,15 +346,10 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) } _system->UnLock(); - -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) + APT::Progress::PackageManager *progress = APT::Progress::PackageManagerProgressFactory(); pkgPackageManager::OrderResult Res = PM->DoInstall(progress); delete progress; -#else - int status_fd = _config->FindI("APT::Status-Fd", -1); - pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd); -#endif if (Res == pkgPackageManager::Failed || _error->PendingError() == true) return false; @@ -354,19 +365,29 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) } std::set const disappearedPkgs = PM->GetDisappearedPackages(); - if (disappearedPkgs.empty() == true) - return true; - - std::string disappear; - for (std::set::const_iterator d = disappearedPkgs.begin(); - d != disappearedPkgs.end(); ++d) - disappear.append(*d).append(" "); + if (disappearedPkgs.empty() == false) + { + ShowList(c1out, P_("The following package disappeared from your system as\n" + "all files have been overwritten by other packages:", + "The following packages disappeared from your system as\n" + "all files have been overwritten by other packages:", disappearedPkgs.size()), disappearedPkgs, + [](std::string const &Pkg) { return Pkg.empty() == false; }, + [](std::string const &Pkg) { return Pkg; }, + [](std::string const &) { return std::string(); }); + c0out << _("Note: This is done automatically and on purpose by dpkg.") << std::endl; + } - ShowList(c1out, P_("The following package disappeared from your system as\n" - "all files have been overwritten by other packages:", - "The following packages disappeared from your system as\n" - "all files have been overwritten by other packages:", disappearedPkgs.size()), disappear, ""); - c0out << _("Note: This is done automatically and on purpose by dpkg.") << std::endl; + // cleanup downloaded debs + if (_config->FindB("APT::Keep-Downloaded-Packages", true) == false) + { + std::string const archivedir = _config->FindDir("Dir::Cache::archives"); + for (auto I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I) + { + if (flNotFile((*I)->DestFile) != archivedir || (*I)->Local) + continue; + RemoveFile("Keep-Downloaded-Packages=false", (*I)->DestFile); + } + } return true; } @@ -374,7 +395,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) // DoAutomaticRemove - Remove all automatic unused packages /*{{{*/ // --------------------------------------------------------------------- /* Remove unused automatic packages */ -static bool DoAutomaticRemove(CacheFile &Cache) +bool DoAutomaticRemove(CacheFile &Cache) { bool Debug = _config->FindI("Debug::pkgAutoRemove",false); bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false); @@ -398,11 +419,10 @@ static bool DoAutomaticRemove(CacheFile &Cache) unsigned long autoRemoveCount = 0; APT::PackageSet tooMuch; - APT::PackageList autoRemoveList; + SortedPackageUniverse Universe(Cache); // look over the cache to see what can be removed - for (unsigned J = 0; J < Cache->Head().PackageCount; ++J) + for (auto const &Pkg: Universe) { - pkgCache::PkgIterator Pkg(Cache,Cache.List[J]); if (Cache[Pkg].Garbage) { if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install()) @@ -419,8 +439,6 @@ static bool DoAutomaticRemove(CacheFile &Cache) } else { - if (hideAutoRemove == false && Cache[Pkg].Delete() == false) - autoRemoveList.insert(Pkg); // 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) @@ -443,7 +461,7 @@ static bool DoAutomaticRemove(CacheFile &Cache) bool Changed; do { Changed = false; - for (APT::PackageSet::const_iterator Pkg = tooMuch.begin(); + for (APT::PackageSet::iterator Pkg = tooMuch.begin(); Pkg != tooMuch.end(); ++Pkg) { APT::PackageSet too; @@ -480,18 +498,6 @@ static bool DoAutomaticRemove(CacheFile &Cache) } while (Changed == true); } - std::string autoremovelist, autoremoveversions; - if (smallList == false && autoRemoveCount != 0) - { - for (APT::PackageList::const_iterator Pkg = autoRemoveList.begin(); Pkg != autoRemoveList.end(); ++Pkg) - { - if (Cache[Pkg].Garbage == false) - continue; - autoremovelist += Pkg.FullName(true) + " "; - autoremoveversions += std::string(Cache[Pkg].CandVersion) + "\n"; - } - } - // Now see if we had destroyed anything (if we had done anything) if (Cache->BrokenCount() != 0) { @@ -506,16 +512,25 @@ static bool DoAutomaticRemove(CacheFile &Cache) } // if we don't remove them, we should show them! - if (doAutoRemove == false && (autoremovelist.empty() == false || autoRemoveCount != 0)) + if (doAutoRemove == false && autoRemoveCount != 0) { if (smallList == false) + { + SortedPackageUniverse Universe(Cache); 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); + autoRemoveCount), Universe, + [&Cache](pkgCache::PkgIterator const &Pkg) { return (*Cache)[Pkg].Garbage == true && (*Cache)[Pkg].Delete() == false; }, + &PrettyFullName, CandidateVersion(&Cache)); + } 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 << P_("Use 'apt-get autoremove' to remove it.", "Use 'apt-get autoremove' to remove them.", autoRemoveCount) << std::endl; + std::string autocmd = "apt autoremove"; + if (getenv("SUDO_USER") != NULL) + autocmd = "sudo " + autocmd; + ioprintf(c1out, P_("Use '%s' to remove it.", "Use '%s' to remove them.", autoRemoveCount), autocmd.c_str()); + c1out << std::endl; } return true; } @@ -524,23 +539,27 @@ static bool DoAutomaticRemove(CacheFile &Cache) static const unsigned short MOD_REMOVE = 1; static const unsigned short MOD_INSTALL = 2; -bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache) +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, int UpgradeMode) +{ + std::vector VolatileCmdL; + return DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, UpgradeMode); +} +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, int UpgradeMode) { std::map verset; - return DoCacheManipulationFromCommandLine(CmdL, Cache, verset); + return DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, verset, UpgradeMode); } -bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, - std::map &verset) +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, + std::map &verset, int UpgradeMode) { - // Enter the special broken fixing mode if the user specified arguments bool BrokenFix = false; if (Cache->BrokenCount() != 0) BrokenFix = true; - SPtr Fix; + std::unique_ptr Fix(nullptr); if (_config->FindB("APT::Get::CallResolver", true) == true) - Fix = new pkgProblemResolver(Cache); + Fix.reset(new pkgProblemResolver(Cache)); unsigned short fallback = MOD_INSTALL; if (strcasecmp(CmdL.FileList[0],"remove") == 0) @@ -550,7 +569,8 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, _config->Set("APT::Get::Purge", true); fallback = MOD_REMOVE; } - else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0) + else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0 || + strcasecmp(CmdL.FileList[0], "auto-remove") == 0) { _config->Set("APT::Get::AutomaticRemove", "true"); fallback = MOD_REMOVE; @@ -558,13 +578,27 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, std::list mods; mods.push_back(APT::VersionSet::Modifier(MOD_INSTALL, "+", - APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDIDATE)); + APT::VersionSet::Modifier::POSTFIX, APT::CacheSetHelper::CANDIDATE)); mods.push_back(APT::VersionSet::Modifier(MOD_REMOVE, "-", - APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::NEWEST)); + APT::VersionSet::Modifier::POSTFIX, APT::CacheSetHelper::NEWEST)); CacheSetHelperAPTGet helper(c0out); verset = APT::VersionSet::GroupedFromCommandLine(Cache, CmdL.FileList + 1, mods, fallback, helper); + for (auto const &I: VolatileCmdL) + { + pkgCache::PkgIterator const P = Cache->FindPkg(I); + if (P.end()) + continue; + + // Set any version providing the .deb as the candidate. + for (auto Prv = P.ProvidesList(); Prv.end() == false; Prv++) + Cache.GetDepCache()->SetCandidateVersion(Prv.OwnerVer()); + + // via cacheset to have our usual virtual handling + APT::VersionContainerInterface::FromPackage(&(verset[MOD_INSTALL]), Cache, P, APT::CacheSetHelper::CANDIDATE, helper); + } + if (_error->PendingError() == true) { helper.showVirtualPackageErrors(Cache); @@ -572,8 +606,8 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, } - TryToInstall InstallAction(Cache, Fix, BrokenFix); - TryToRemove RemoveAction(Cache, Fix); + TryToInstall InstallAction(Cache, Fix.get(), BrokenFix); + TryToRemove RemoveAction(Cache, Fix.get()); // new scope for the ActionGroup { @@ -590,13 +624,8 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, 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(); - } + InstallAction.propergateReleaseCandiateSwitching(helper.selectedByRelease, c0out); + InstallAction.doAutoInstall(); } if (_error->PendingError() == true) @@ -617,37 +646,21 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, if (Fix != NULL) { // Call the scored problem resolver - if (Fix->Resolve(true) == false && Cache->BrokenCount() == 0) - return false; - } + OpTextProgress Progress(*_config); + bool const distUpgradeMode = strcmp(CmdL.FileList[0], "dist-upgrade") == 0 || strcmp(CmdL.FileList[0], "full-upgrade") == 0; - // Now we check the state of the packages, - if (Cache->BrokenCount() != 0) - { - c1out << - _("Some packages could not be installed. This may mean that you have\n" - "requested an impossible situation or if you are using the unstable\n" - "distribution that some required packages have not yet been created\n" - "or been moved out of Incoming.") << std::endl; - /* - if (Packages == 1) - { - c1out << std::endl; - c1out << - _("Since you only requested a single operation it is extremely likely that\n" - "the package is simply not installable and a bug report against\n" - "that package should be filed.") << std::endl; - } - */ + bool resolver_fail = false; + if (distUpgradeMode == true || UpgradeMode != APT::Upgrade::ALLOW_EVERYTHING) + resolver_fail = APT::Upgrade::Upgrade(Cache, UpgradeMode, &Progress); + else + resolver_fail = Fix->Resolve(true, &Progress); - c1out << _("The following information may help to resolve the situation:") << std::endl; - c1out << std::endl; - ShowBroken(c1out,Cache,false); - if (_error->PendingError() == true) + if (resolver_fail == false && Cache->BrokenCount() == 0) return false; - else - return _error->Error(_("Broken packages")); } + + if (CheckNothingBroken(Cache) == false) + return false; } if (!DoAutomaticRemove(Cache)) return false; @@ -667,49 +680,46 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, // DoInstall - Install packages from the command line /*{{{*/ // --------------------------------------------------------------------- /* Install named packages */ +struct PkgIsExtraInstalled { + pkgCacheFile * const Cache; + APT::VersionSet const * const verset; + PkgIsExtraInstalled(pkgCacheFile * const Cache, APT::VersionSet const * const Container) : Cache(Cache), verset(Container) {} + bool operator() (pkgCache::PkgIterator const &Pkg) + { + if ((*Cache)[Pkg].Install() == false) + return false; + pkgCache::VerIterator const Cand = (*Cache)[Pkg].CandidateVerIter(*Cache); + return verset->find(Cand) == verset->end(); + } +}; bool DoInstall(CommandLine &CmdL) { CacheFile Cache; + std::vector VolatileCmdL; + Cache.GetSourceList()->AddVolatileFiles(CmdL, &VolatileCmdL); + + // then open the cache if (Cache.OpenForInstall() == false || Cache.CheckDeps(CmdL.FileSize() != 1) == false) return false; std::map verset; - - if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset)) + if(!DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, verset, 0)) return false; /* Print out a list of packages that are going to be installed extra to what the user asked */ + SortedPackageUniverse Universe(Cache); if (Cache->InstCount() != verset[MOD_INSTALL].size()) - { - std::string List; - std::string VersionsList; - for (unsigned J = 0; J < Cache->Head().PackageCount; J++) - { - pkgCache::PkgIterator I(Cache,Cache.List[J]); - if ((*Cache)[I].Install() == false) - continue; - pkgCache::VerIterator Cand = Cache[I].CandidateVerIter(Cache); - - if (verset[MOD_INSTALL].find(Cand) != verset[MOD_INSTALL].end()) - continue; - - List += I.FullName(true) + " "; - VersionsList += std::string(Cache[I].CandVersion) + "\n"; - } - - ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList); - } + ShowList(c1out, _("The following additional packages will be installed:"), Universe, + PkgIsExtraInstalled(&Cache, &verset[MOD_INSTALL]), + &PrettyFullName, CandidateVersion(&Cache)); /* Print out a list of suggested and recommended packages */ { - std::string SuggestsList, RecommendsList; - std::string SuggestsVersions, RecommendsVersions; - for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + std::list Recommends, Suggests, SingleRecommends, SingleSuggests; + for (auto const &Pkg: Universe) { - pkgCache::PkgIterator Pkg(Cache,Cache.List[J]); - /* Just look at the ones we want to install */ if ((*Cache)[Pkg].Install() == false) continue; @@ -721,77 +731,79 @@ bool DoInstall(CommandLine &CmdL) pkgCache::DepIterator Start; pkgCache::DepIterator End; D.GlobOr(Start,End); // advances D + if (Start->Type != pkgCache::Dep::Recommends && Start->Type != pkgCache::Dep::Suggests) + continue; - // FIXME: we really should display a or-group as a or-group to the user - // the problem is that ShowList is incapable of doing this - std::string RecommendsOrList,RecommendsOrVersions; - std::string SuggestsOrList,SuggestsOrVersions; - bool foundInstalledInOrGroup = false; - for(;;) { - /* Skip if package is installed already, or is about to be */ - std::string target = Start.TargetPkg().FullName(true) + " "; - pkgCache::PkgIterator const TarPkg = Start.TargetPkg(); - if (TarPkg->SelectedState == pkgCache::State::Install || - TarPkg->SelectedState == pkgCache::State::Hold || - Cache[Start.TargetPkg()].Install()) + // Skip if we already saw this + std::string target; + for (pkgCache::DepIterator I = Start; I != D; ++I) { - foundInstalledInOrGroup=true; - break; - } - - /* Skip if we already saw it */ - if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1) - { - foundInstalledInOrGroup=true; - break; + if (target.empty() == false) + target.append(" | "); + target.append(I.TargetPkg().FullName(true)); } + std::list &Type = Start->Type == pkgCache::Dep::Recommends ? SingleRecommends : SingleSuggests; + if (std::find(Type.begin(), Type.end(), target) != Type.end()) + continue; + Type.push_back(target); + } - // this is a dep on a virtual pkg, check if any package that provides it - // should be installed - if(Start.TargetPkg().ProvidesList() != 0) + std::list OrList; + bool foundInstalledInOrGroup = false; + for (pkgCache::DepIterator I = Start; I != D; ++I) + { { - pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList(); - for (; I.end() == false; ++I) + // satisfying package is installed and not marked for deletion + APT::VersionList installed = APT::VersionList::FromDependency(Cache, I, APT::CacheSetHelper::INSTALLED); + if (std::find_if(installed.begin(), installed.end(), + [&Cache](pkgCache::VerIterator const &Ver) { return Cache[Ver.ParentPkg()].Delete() == false; }) != installed.end()) { - pkgCache::PkgIterator Pkg = I.OwnerPkg(); - if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() && - Pkg.CurrentVer() != 0) - foundInstalledInOrGroup=true; + foundInstalledInOrGroup = true; + break; } } - if (Start->Type == pkgCache::Dep::Suggests) { - SuggestsOrList += target; - SuggestsOrVersions += std::string(Cache[Start.TargetPkg()].CandVersion) + "\n"; - } - - if (Start->Type == pkgCache::Dep::Recommends) - { - RecommendsOrList += target; - RecommendsOrVersions += std::string(Cache[Start.TargetPkg()].CandVersion) + "\n"; + // satisfying package is upgraded to/new install + APT::VersionList upgrades = APT::VersionList::FromDependency(Cache, I, APT::CacheSetHelper::CANDIDATE); + if (std::find_if(upgrades.begin(), upgrades.end(), + [&Cache](pkgCache::VerIterator const &Ver) { return Cache[Ver.ParentPkg()].Upgrade(); }) != upgrades.end()) + { + foundInstalledInOrGroup = true; + break; + } } - if (Start >= End) - break; - ++Start; + if (OrList.empty()) + OrList.push_back(I.TargetPkg().FullName(true)); + else + OrList.push_back("| " + I.TargetPkg().FullName(true)); } - + if(foundInstalledInOrGroup == false) { - RecommendsList += RecommendsOrList; - RecommendsVersions += RecommendsOrVersions; - SuggestsList += SuggestsOrList; - SuggestsVersions += SuggestsOrVersions; + std::list &Type = Start->Type == pkgCache::Dep::Recommends ? Recommends : Suggests; + std::move(OrList.begin(), OrList.end(), std::back_inserter(Type)); } - } } - - ShowList(c1out,_("Suggested packages:"),SuggestsList,SuggestsVersions); - ShowList(c1out,_("Recommended packages:"),RecommendsList,RecommendsVersions); - + auto always_true = [](std::string const&) { return true; }; + auto string_ident = [](std::string const&str) { return str; }; + auto verbose_show_candidate = + [&Cache](std::string str) + { + if (APT::String::Startswith(str, "| ")) + str.erase(0, 2); + pkgCache::PkgIterator const Pkg = Cache->FindPkg(str); + if (Pkg.end() == true) + return ""; + return (*Cache)[Pkg].CandVersion; + }; + ShowList(c1out,_("Suggested packages:"), Suggests, + always_true, string_ident, verbose_show_candidate); + ShowList(c1out,_("Recommended packages:"), Recommends, + always_true, string_ident, verbose_show_candidate); } // See if we need to prompt @@ -799,13 +811,23 @@ bool DoInstall(CommandLine &CmdL) if (Cache->InstCount() == verset[MOD_INSTALL].size() && Cache->DelCount() == 0) return InstallPackages(Cache,false,false); - return InstallPackages(Cache,false); + return InstallPackages(Cache,false); } /*}}}*/ // TryToInstall - Mark a package for installation /*{{{*/ void TryToInstall::operator() (pkgCache::VerIterator const &Ver) { + if (unlikely(Ver.end())) + { + _error->Fatal("The given version to TryToInstall is invalid!"); + return; + } pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + if (unlikely(Pkg.end())) + { + _error->Fatal("The given version to TryToInstall has an invalid parent package!"); + return; + } Cache->GetDepCache()->SetCandidateVersion(Ver); pkgDepCache::StateCache &State = (*Cache)[Pkg]; @@ -833,8 +855,9 @@ void TryToInstall::operator() (pkgCache::VerIterator const &Ver) { else Cache->GetDepCache()->SetReInstall(Pkg, true); } else - ioprintf(c1out,_("%s is already the newest version.\n"), - Pkg.FullName(true).c_str()); + // TRANSLATORS: First string is package name, second is version + ioprintf(c1out,_("%s is already the newest version (%s).\n"), + Pkg.FullName(true).c_str(), Pkg.CurrentVer().VerStr()); } // Install it with autoinstalling enabled (if we not respect the minial