diff options
author | Michael Vogt <mvo@debian.org> | 2010-07-09 19:10:28 +0200 |
---|---|---|
committer | Michael Vogt <mvo@debian.org> | 2010-07-09 19:10:28 +0200 |
commit | 358f10d9d47a88cbf0568f042caccfef8678cbc8 (patch) | |
tree | 711c7ddc538476e8b88dfb8b6d76361db5754c1e /cmdline | |
parent | fd3b761e8cba6ed626639b50b1221246098c7b3a (diff) | |
parent | a9fe592842bfa17d91f4904d7fb0e3af3adebb17 (diff) |
merged from donkult
Diffstat (limited to 'cmdline')
-rw-r--r-- | cmdline/apt-cache.cc | 21 | ||||
-rw-r--r-- | cmdline/apt-cdrom.cc | 14 | ||||
-rw-r--r-- | cmdline/apt-get.cc | 709 | ||||
-rw-r--r-- | cmdline/cacheset.cc | 515 | ||||
-rw-r--r-- | cmdline/cacheset.h | 375 | ||||
-rw-r--r-- | cmdline/makefile | 4 |
6 files changed, 1231 insertions, 407 deletions
diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 7cb95b3f8..c790559e7 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -29,7 +29,8 @@ #include <apt-pkg/tagfile.h> #include <apt-pkg/algorithms.h> #include <apt-pkg/sptr.h> -#include <apt-pkg/cacheset.h> + +#include "cacheset.h" #include <config.h> #include <apti18n.h> @@ -1867,21 +1868,21 @@ int main(int argc,const char *argv[]) /*{{{*/ } // Deal with stdout not being a tty - if (isatty(STDOUT_FILENO) && _config->FindI("quiet",0) < 1) + if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1) _config->Set("quiet","1"); -// if (_config->FindB("APT::Cache::Generate",true) == false) + if (_config->Exists("APT::Cache::Generate") == true) + _config->Set("pkgCacheFile::Generate", _config->FindB("APT::Cache::Generate", true)); + if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false) CmdL.DispatchArg(CmdsB); // Print any errors or warnings found during parsing - if (_error->empty() == false) - { - bool Errors = _error->PendingError(); + bool const Errors = _error->PendingError(); + if (_config->FindI("quiet",0) > 0) _error->DumpErrors(); - return Errors == true?100:0; - } - - return 0; + else + _error->DumpErrors(GlobalError::DEBUG); + return Errors == true ? 100 : 0; } /*}}}*/ diff --git a/cmdline/apt-cdrom.cc b/cmdline/apt-cdrom.cc index 8b9eacae6..d1268edf9 100644 --- a/cmdline/apt-cdrom.cc +++ b/cmdline/apt-cdrom.cc @@ -266,20 +266,18 @@ int main(int argc,const char *argv[]) /*{{{*/ return ShowHelp(); // Deal with stdout not being a tty - if (isatty(STDOUT_FILENO) && _config->FindI("quiet",0) < 1) + if (isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1) _config->Set("quiet","1"); // Match the operation CmdL.DispatchArg(Cmds); // Print any errors or warnings found during parsing - if (_error->empty() == false) - { - bool Errors = _error->PendingError(); + bool const Errors = _error->PendingError(); + if (_config->FindI("quiet",0) > 0) _error->DumpErrors(); - return Errors == true?100:0; - } - - return 0; + else + _error->DumpErrors(GlobalError::DEBUG); + return Errors == true ? 100 : 0; } /*}}}*/ diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 0ada46c73..7cf760c27 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -40,12 +40,12 @@ #include <apt-pkg/sptr.h> #include <apt-pkg/md5.h> #include <apt-pkg/versionmatch.h> -#include <apt-pkg/cacheset.h> #include <config.h> #include <apti18n.h> #include "acqprogress.h" +#include "cacheset.h" #include <set> #include <locale.h> @@ -609,6 +609,253 @@ 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: + 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()); + } + + 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()) { + out << " " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr(); + if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false) + out << _(" [Installed]"); + out << 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++) + out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr() + << _(" [Not candidate version]") << endl; + else + out << _("You should explicitly select one to install.") << endl; + } else { + ioprintf(out, + _("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<bool> 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(out,_("However the following packages replace it:"),List,VersionsList); + } + out << 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()); + 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) { + 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()); + 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) { + 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 { + 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++; + } + } + + 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 FixBroken; + unsigned long AutoMarkChanged; + + TryToRemove(pkgCacheFile &Cache, pkgProblemResolver &PM) : Cache(&Cache), Fix(&PM) {}; + + void operator() (pkgCache::VerIterator const &Ver) + { + pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + + Fix->Clear(Pkg); + Fix->Protect(Pkg); + Fix->Remove(Pkg); + + if (Pkg->CurrentVer == 0) + ioprintf(c1out,_("Package %s is not installed, so not removed\n"),Pkg.FullName(true).c_str()); + else + Cache->GetDepCache()->MarkDelete(Pkg,_config->FindB("APT::Get::Purge",false)); + } +}; + /*}}}*/ // CacheFile::NameComp - QSort compare by name /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -1073,219 +1320,35 @@ 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, - unsigned int &ExpectedInst,bool AllowFail = true) + bool AllowFail = true) { - /* This is a pure virtual package and there is a single available - candidate providing it. */ if (Cache[Pkg].CandidateVer == 0 && Pkg->ProvidesList != 0) { - 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(c1out,_("Note, selecting %s instead of %s\n"), - Prov.FullName(true).c_str(),Pkg.FullName(true).c_str()); - Pkg = Prov; - } + 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; } - // 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 (AllowFail == true) - ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"), - Pkg.Name()); - return true; - } - - // 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 (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; - } - 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<bool> 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; - } - - 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()); - } - } - else - ExpectedInst++; - - // 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); - - return true; -} - /*}}}*/ -// TryToChangeVer - Try to change a candidate version /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool TryToChangeVer(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, - const char *VerTag,bool IsRel) -{ - pkgVersionMatch Match(VerTag,(IsRel == true?pkgVersionMatch::Release : - pkgVersionMatch::Version)); - - pkgCache::VerIterator Ver = Match.Find(Pkg); - - if (Ver.end() == true) - { - if (IsRel == true) - return _error->Error(_("Release '%s' for '%s' was not found"), - VerTag,Pkg.FullName(true).c_str()); - return _error->Error(_("Version '%s' for '%s' was not found"), - VerTag,Pkg.FullName(true).c_str()); - } - - if (strcmp(VerTag,Ver.VerStr()) != 0) - { - ioprintf(c1out,_("Selected version %s (%s) for %s\n"), - Ver.VerStr(),Ver.RelStr().c_str(),Pkg.FullName(true).c_str()); - } - - Cache.SetCandidateVersion(Ver); - - // Set the all package to the same candidate - if (Ver.Pseudo() == true) - Cache.SetCandidateVersion(Match.Find(Pkg.Group().FindPkg("all"))); + 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; } @@ -1624,61 +1687,6 @@ bool DoUpgrade(CommandLine &CmdL) return InstallPackages(Cache,true); } /*}}}*/ -// DoInstallTask - Install task from the command line /*{{{*/ -// --------------------------------------------------------------------- -/* Install named task */ -bool TryInstallTask(pkgDepCache &Cache, pkgProblemResolver &Fix, - bool BrokenFix, - unsigned int& ExpectedInst, - const char *taskname, - bool Remove) -{ - const char *start, *end; - pkgCache::PkgIterator Pkg; - char buf[64*1024]; - regex_t Pattern; - - // get the records - pkgRecords Recs(Cache); - - // build regexp for the task - char S[300]; - snprintf(S, sizeof(S), "^Task:.*[, ]%s([, ]|$)", taskname); - if(regcomp(&Pattern,S, REG_EXTENDED | REG_NOSUB | REG_NEWLINE) != 0) - return _error->Error("Failed to compile task regexp"); - - bool found = false; - bool res = true; - - // two runs, first ignore dependencies, second install any missing - for(int IgnoreBroken=1; IgnoreBroken >= 0; IgnoreBroken--) - { - for (Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++) - { - pkgCache::VerIterator ver = Cache[Pkg].CandidateVerIter(Cache); - if(ver.end()) - continue; - pkgRecords::Parser &parser = Recs.Lookup(ver.FileList()); - parser.GetRec(start,end); - strncpy(buf, start, end-start); - buf[end-start] = 0x0; - if (regexec(&Pattern,buf,0,0,0) != 0) - continue; - res &= TryToInstall(Pkg,Cache,Fix,Remove,IgnoreBroken,ExpectedInst); - found = true; - } - } - - // now let the problem resolver deal with any issues - Fix.Resolve(true); - - if(!found) - _error->Error(_("Couldn't find task %s"),taskname); - - regfree(&Pattern); - return res; -} - /*}}}*/ // DoInstall - Install packages from the command line /*{{{*/ // --------------------------------------------------------------------- /* Install named packages */ @@ -1694,140 +1702,69 @@ bool DoInstall(CommandLine &CmdL) if (Cache->BrokenCount() != 0) BrokenFix = true; - unsigned int AutoMarkChanged = 0; - unsigned int ExpectedInst = 0; - unsigned int Packages = 0; pkgProblemResolver Fix(Cache); - - bool DefRemove = false; + + static const unsigned short MOD_REMOVE = 1; + static const unsigned short MOD_INSTALL = 2; + + unsigned short fallback = MOD_INSTALL; if (strcasecmp(CmdL.FileList[0],"remove") == 0) - DefRemove = true; + fallback = MOD_REMOVE; else if (strcasecmp(CmdL.FileList[0], "purge") == 0) { _config->Set("APT::Get::Purge", true); - DefRemove = true; + fallback = MOD_REMOVE; } else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0) { _config->Set("APT::Get::AutomaticRemove", "true"); - DefRemove = true; + fallback = MOD_REMOVE; } - // new scope for the ActionGroup - { - pkgDepCache::ActionGroup group(Cache); - for (const char **I = CmdL.FileList + 1; *I != 0; I++) - { - // Duplicate the string - unsigned int Length = strlen(*I); - char S[300]; - if (Length >= sizeof(S)) - continue; - strcpy(S,*I); - - // See if we are removing and special indicators.. - bool Remove = DefRemove; - char *VerTag = 0; - bool VerIsRel = false; - // this is a task! - if (Length >= 1 && S[Length - 1] == '^') - { - S[--Length] = 0; - // tasks must always be confirmed - ExpectedInst += 1000; - // see if we can install it - TryInstallTask(Cache, Fix, BrokenFix, ExpectedInst, S, Remove); - continue; - } + std::list<APT::VersionSet::Modifier> mods; + mods.push_back(APT::VersionSet::Modifier(MOD_INSTALL, "+", + APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDIDATE)); + mods.push_back(APT::VersionSet::Modifier(MOD_REMOVE, "-", + APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::NEWEST)); + CacheSetHelperAPTGet helper(c0out); + std::map<unsigned short, APT::VersionSet> verset = APT::VersionSet::GroupedFromCommandLine(Cache, + CmdL.FileList + 1, mods, fallback, helper); - while (Cache->FindPkg(S).end() == true) - { - // Handle an optional end tag indicating what to do - if (Length >= 1 && S[Length - 1] == '-') - { - Remove = true; - S[--Length] = 0; - continue; - } - - if (Length >= 1 && S[Length - 1] == '+') - { - Remove = false; - S[--Length] = 0; - continue; - } - - char *Slash = strchr(S,'='); - if (Slash != 0) - { - VerIsRel = false; - *Slash = 0; - VerTag = Slash + 1; - } - - Slash = strchr(S,'/'); - if (Slash != 0) - { - VerIsRel = true; - *Slash = 0; - VerTag = Slash + 1; - } - - break; - } - - // Locate the package - pkgCache::PkgIterator Pkg = Cache->FindPkg(S); - Packages++; - if (Pkg.end() == true) - { - APT::PackageSet pkgset = APT::PackageSet::FromRegEx(Cache, S, c1out); - if (pkgset.empty() == true) - return _error->Error(_("Couldn't find package %s"),S); + if (_error->PendingError() == true) + { + helper.showVirtualPackageErrors(Cache); + return false; + } - // Regexs must always be confirmed - ExpectedInst += 1000; + 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; + } - bool Hit = false; - for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg) - { - if (VerTag != 0) - if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false) - return false; + TryToInstall InstallAction(Cache, Fix, BrokenFix); + TryToRemove RemoveAction(Cache, Fix); - Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix, - ExpectedInst,false); - } + // new scope for the ActionGroup + { + pkgDepCache::ActionGroup group(Cache); - if (Hit == false) - return _error->Error(_("Couldn't find package %s"),S); + for (unsigned short i = 0; order[i] != 0; ++i) + { + if (order[i] == MOD_INSTALL) { + InstallAction = std::for_each(verset[MOD_INSTALL].begin(), verset[MOD_INSTALL].end(), InstallAction); + InstallAction.doAutoInstall(); } - else - { - if (VerTag != 0) - if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false) - return false; - if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == 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(!Remove && - 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++; - } - } + else if (order[i] == MOD_REMOVE) + RemoveAction = std::for_each(verset[MOD_REMOVE].begin(), verset[MOD_REMOVE].end(), RemoveAction); } + if (_error->PendingError() == true) + 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 packages */ @@ -1874,7 +1811,7 @@ bool DoInstall(CommandLine &CmdL) /* Print out a list of packages that are going to be installed extra to what the user asked */ - if (Cache->InstCount() != ExpectedInst) + if (Cache->InstCount() != verset[MOD_INSTALL].size()) { string List; string VersionsList; @@ -1993,14 +1930,15 @@ 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) Cache->writeStateFile(NULL); // See if we need to prompt - if (Cache->InstCount() == ExpectedInst && Cache->DelCount() == 0) + // FIXME: check if really the packages in the set are going to be installed + if (Cache->InstCount() == verset[MOD_INSTALL].size() && Cache->DelCount() == 0) return InstallPackages(Cache,false,false); return InstallPackages(Cache,false); @@ -2584,7 +2522,6 @@ bool DoBuildDep(CommandLine &CmdL) } // Install the requested packages - unsigned int ExpectedInst = 0; vector <pkgSrcRecords::Parser::BuildDepRec>::iterator D; pkgProblemResolver Fix(Cache); bool skipAlternatives = false; // skip remaining alternatives in an or group @@ -2615,7 +2552,7 @@ bool DoBuildDep(CommandLine &CmdL) */ if (IV.end() == false && Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true) - TryToInstall(Pkg,Cache,Fix,true,false,ExpectedInst); + TryToInstallBuildDep(Pkg,Cache,Fix,true,false); } else // BuildDep || BuildDepIndep { @@ -2731,7 +2668,7 @@ bool DoBuildDep(CommandLine &CmdL) if (_config->FindB("Debug::BuildDeps",false) == true) cout << " Trying to install " << (*D).Package << endl; - if (TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst) == true) + if (TryToInstallBuildDep(Pkg,Cache,Fix,false,false) == true) { // We successfully installed something; skip remaining alternatives skipAlternatives = hasAlternatives; @@ -3021,7 +2958,7 @@ int main(int argc,const char *argv[]) /*{{{*/ } // Deal with stdout not being a tty - if (!isatty(STDOUT_FILENO) && _config->FindI("quiet",0) < 1) + if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1) _config->Set("quiet","1"); // Setup the output streams @@ -3042,13 +2979,11 @@ int main(int argc,const char *argv[]) /*{{{*/ CmdL.DispatchArg(Cmds); // Print any errors or warnings found during parsing - if (_error->empty() == false) - { - bool Errors = _error->PendingError(); + bool const Errors = _error->PendingError(); + if (_config->FindI("quiet",0) > 0) _error->DumpErrors(); - return Errors == true?100:0; - } - - return 0; + else + _error->DumpErrors(GlobalError::DEBUG); + return Errors == true ? 100 : 0; } /*}}}*/ diff --git a/cmdline/cacheset.cc b/cmdline/cacheset.cc new file mode 100644 index 000000000..78c9d3f6c --- /dev/null +++ b/cmdline/cacheset.cc @@ -0,0 +1,515 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + Simple wrapper around a std::set to provide a similar interface to + a set of cache structures as to the complete set of all structures + in the pkgCache. Currently only Package is supported. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include <apt-pkg/aptconfiguration.h> +#include <apt-pkg/error.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/versionmatch.h> + +#include <apti18n.h> + +#include "cacheset.h" + +#include <vector> + +#include <regex.h> + /*}}}*/ +namespace APT { +// FromTask - Return all packages in the cache from a specific task /*{{{*/ +PackageSet PackageSet::FromTask(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) { + size_t const archfound = pattern.find_last_of(':'); + std::string arch = "native"; + if (archfound != std::string::npos) { + arch = pattern.substr(archfound+1); + pattern.erase(archfound); + } + + if (pattern[pattern.length() -1] != '^') + return APT::PackageSet(TASK); + pattern.erase(pattern.length()-1); + + if (unlikely(Cache.GetPkgCache() == 0 || Cache.GetDepCache() == 0)) + return APT::PackageSet(TASK); + + PackageSet pkgset(TASK); + // get the records + pkgRecords Recs(Cache); + + // build regexp for the task + regex_t Pattern; + char S[300]; + snprintf(S, sizeof(S), "^Task:.*[, ]%s([, ]|$)", pattern.c_str()); + if(regcomp(&Pattern,S, REG_EXTENDED | REG_NOSUB | REG_NEWLINE) != 0) { + _error->Error("Failed to compile task regexp"); + return pkgset; + } + + for (pkgCache::GrpIterator Grp = Cache->GrpBegin(); Grp.end() == false; ++Grp) { + pkgCache::PkgIterator Pkg = Grp.FindPkg(arch); + if (Pkg.end() == true) + continue; + pkgCache::VerIterator ver = Cache[Pkg].CandidateVerIter(Cache); + if(ver.end() == true) + continue; + + pkgRecords::Parser &parser = Recs.Lookup(ver.FileList()); + const char *start, *end; + parser.GetRec(start,end); + unsigned int const length = end - start; + char buf[length]; + strncpy(buf, start, length); + buf[length-1] = '\0'; + if (regexec(&Pattern, buf, 0, 0, 0) != 0) + continue; + + pkgset.insert(Pkg); + } + regfree(&Pattern); + + if (pkgset.empty() == true) + return helper.canNotFindTask(Cache, pattern); + + helper.showTaskSelection(pkgset, pattern); + return pkgset; +} + /*}}}*/ +// FromRegEx - Return all packages in the cache matching a pattern /*{{{*/ +PackageSet PackageSet::FromRegEx(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) { + static const char * const isregex = ".?+*|[^$"; + if (pattern.find_first_of(isregex) == std::string::npos) + return PackageSet(REGEX); + + size_t archfound = pattern.find_last_of(':'); + std::string arch = "native"; + if (archfound != std::string::npos) { + arch = pattern.substr(archfound+1); + if (arch.find_first_of(isregex) == std::string::npos) + pattern.erase(archfound); + else + arch = "native"; + } + + regex_t Pattern; + int Res; + if ((Res = regcomp(&Pattern, pattern.c_str() , REG_EXTENDED | REG_ICASE | REG_NOSUB)) != 0) { + char Error[300]; + regerror(Res, &Pattern, Error, sizeof(Error)); + _error->Error(_("Regex compilation error - %s"), Error); + return PackageSet(REGEX); + } + + if (unlikely(Cache.GetPkgCache() == 0)) + return PackageSet(REGEX); + + PackageSet pkgset(REGEX); + for (pkgCache::GrpIterator Grp = Cache.GetPkgCache()->GrpBegin(); Grp.end() == false; ++Grp) + { + if (regexec(&Pattern, Grp.Name(), 0, 0, 0) != 0) + continue; + pkgCache::PkgIterator Pkg = Grp.FindPkg(arch); + if (Pkg.end() == true) { + if (archfound == std::string::npos) { + std::vector<std::string> archs = APT::Configuration::getArchitectures(); + for (std::vector<std::string>::const_iterator a = archs.begin(); + a != archs.end() && Pkg.end() != true; ++a) + Pkg = Grp.FindPkg(*a); + } + if (Pkg.end() == true) + continue; + } + + pkgset.insert(Pkg); + } + regfree(&Pattern); + + if (pkgset.empty() == true) + return helper.canNotFindRegEx(Cache, pattern); + + helper.showRegExSelection(pkgset, pattern); + return pkgset; +} + /*}}}*/ +// FromName - Returns the package defined by this string /*{{{*/ +pkgCache::PkgIterator PackageSet::FromName(pkgCacheFile &Cache, + std::string const &str, CacheSetHelper &helper) { + std::string pkg = str; + size_t archfound = pkg.find_last_of(':'); + std::string arch; + if (archfound != std::string::npos) { + arch = pkg.substr(archfound+1); + pkg.erase(archfound); + } + + if (Cache.GetPkgCache() == 0) + return pkgCache::PkgIterator(Cache, 0); + + pkgCache::PkgIterator Pkg(Cache, 0); + if (arch.empty() == true) { + pkgCache::GrpIterator Grp = Cache.GetPkgCache()->FindGrp(pkg); + if (Grp.end() == false) + Pkg = Grp.FindPreferredPkg(); + } else + Pkg = Cache.GetPkgCache()->FindPkg(pkg, arch); + + if (Pkg.end() == true) + return helper.canNotFindPkgName(Cache, str); + return Pkg; +} + /*}}}*/ +// GroupedFromCommandLine - Return all versions specified on commandline/*{{{*/ +std::map<unsigned short, PackageSet> PackageSet::GroupedFromCommandLine( + pkgCacheFile &Cache, const char **cmdline, + std::list<PackageSet::Modifier> const &mods, + unsigned short const &fallback, CacheSetHelper &helper) { + std::map<unsigned short, PackageSet> pkgsets; + for (const char **I = cmdline; *I != 0; ++I) { + unsigned short modID = fallback; + std::string str = *I; + bool modifierPresent = false; + for (std::list<PackageSet::Modifier>::const_iterator mod = mods.begin(); + mod != mods.end(); ++mod) { + size_t const alength = strlen(mod->Alias); + switch(mod->Pos) { + case PackageSet::Modifier::POSTFIX: + if (str.compare(str.length() - alength, alength, + mod->Alias, 0, alength) != 0) + continue; + str.erase(str.length() - alength); + modID = mod->ID; + break; + case PackageSet::Modifier::PREFIX: + continue; + case PackageSet::Modifier::NONE: + continue; + } + modifierPresent = true; + break; + } + if (modifierPresent == true) { + bool const errors = helper.showErrors(false); + pkgCache::PkgIterator Pkg = FromName(Cache, *I, helper); + helper.showErrors(errors); + if (Pkg.end() == false) { + pkgsets[fallback].insert(Pkg); + continue; + } + } + pkgsets[modID].insert(PackageSet::FromString(Cache, str, helper)); + } + return pkgsets; +} + /*}}}*/ +// FromCommandLine - Return all packages specified on commandline /*{{{*/ +PackageSet PackageSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper) { + PackageSet pkgset; + for (const char **I = cmdline; *I != 0; ++I) { + PackageSet pset = FromString(Cache, *I, helper); + pkgset.insert(pset.begin(), pset.end()); + } + return pkgset; +} + /*}}}*/ +// FromString - Return all packages matching a specific string /*{{{*/ +PackageSet PackageSet::FromString(pkgCacheFile &Cache, std::string const &str, CacheSetHelper &helper) { + _error->PushToStack(); + + PackageSet pkgset; + pkgCache::PkgIterator Pkg = FromName(Cache, str, helper); + if (Pkg.end() == false) + pkgset.insert(Pkg); + else { + pkgset = FromTask(Cache, str, helper); + if (pkgset.empty() == true) { + pkgset = FromRegEx(Cache, str, helper); + if (pkgset.empty() == true) + pkgset = helper.canNotFindPackage(Cache, str); + } + } + + if (pkgset.empty() == false) + _error->RevertToStack(); + else + _error->MergeWithStack(); + return pkgset; +} + /*}}}*/ +// GroupedFromCommandLine - Return all versions specified on commandline/*{{{*/ +std::map<unsigned short, VersionSet> VersionSet::GroupedFromCommandLine( + pkgCacheFile &Cache, const char **cmdline, + std::list<VersionSet::Modifier> const &mods, + unsigned short const &fallback, CacheSetHelper &helper) { + std::map<unsigned short, VersionSet> versets; + for (const char **I = cmdline; *I != 0; ++I) { + unsigned short modID = fallback; + VersionSet::Version select = VersionSet::NEWEST; + std::string str = *I; + bool modifierPresent = false; + for (std::list<VersionSet::Modifier>::const_iterator mod = mods.begin(); + mod != mods.end(); ++mod) { + if (modID == fallback && mod->ID == fallback) + select = mod->SelectVersion; + size_t const alength = strlen(mod->Alias); + switch(mod->Pos) { + case VersionSet::Modifier::POSTFIX: + if (str.compare(str.length() - alength, alength, + mod->Alias, 0, alength) != 0) + continue; + str.erase(str.length() - alength); + modID = mod->ID; + select = mod->SelectVersion; + break; + case VersionSet::Modifier::PREFIX: + continue; + case VersionSet::Modifier::NONE: + continue; + } + modifierPresent = true; + break; + } + + if (modifierPresent == true) { + bool const errors = helper.showErrors(false); + VersionSet const vset = VersionSet::FromString(Cache, std::string(*I), select, helper, true); + helper.showErrors(errors); + if (vset.empty() == false) { + versets[fallback].insert(vset); + continue; + } + } + versets[modID].insert(VersionSet::FromString(Cache, str, select , helper)); + } + return versets; +} + /*}}}*/ +// FromCommandLine - Return all versions specified on commandline /*{{{*/ +APT::VersionSet VersionSet::FromCommandLine(pkgCacheFile &Cache, const char **cmdline, + APT::VersionSet::Version const &fallback, CacheSetHelper &helper) { + VersionSet verset; + for (const char **I = cmdline; *I != 0; ++I) + verset.insert(VersionSet::FromString(Cache, *I, fallback, helper)); + return verset; +} + /*}}}*/ +// FromString - Returns all versions spedcified by a string /*{{{*/ +APT::VersionSet VersionSet::FromString(pkgCacheFile &Cache, std::string pkg, + APT::VersionSet::Version const &fallback, CacheSetHelper &helper, + bool const &onlyFromName) { + std::string ver; + bool verIsRel = false; + size_t const vertag = pkg.find_last_of("/="); + if (vertag != string::npos) { + ver = pkg.substr(vertag+1); + verIsRel = (pkg[vertag] == '/'); + pkg.erase(vertag); + } + PackageSet pkgset; + if (onlyFromName == false) + pkgset = PackageSet::FromString(Cache, pkg, helper); + else { + pkgset.insert(PackageSet::FromName(Cache, pkg, helper)); + } + + VersionSet verset; + bool errors = true; + if (pkgset.getConstructor() != PackageSet::UNKNOWN) + errors = helper.showErrors(false); + for (PackageSet::const_iterator P = pkgset.begin(); + P != pkgset.end(); ++P) { + if (vertag == string::npos) { + verset.insert(VersionSet::FromPackage(Cache, P, fallback, helper)); + continue; + } + pkgCache::VerIterator V; + if (ver == "installed") + V = getInstalledVer(Cache, P, helper); + else if (ver == "candidate") + V = getCandidateVer(Cache, P, helper); + else { + pkgVersionMatch Match(ver, (verIsRel == true ? pkgVersionMatch::Release : + pkgVersionMatch::Version)); + V = Match.Find(P); + if (V.end() == true) { + if (verIsRel == true) + _error->Error(_("Release '%s' for '%s' was not found"), + ver.c_str(), P.FullName(true).c_str()); + else + _error->Error(_("Version '%s' for '%s' was not found"), + ver.c_str(), P.FullName(true).c_str()); + continue; + } + } + if (V.end() == true) + continue; + helper.showSelectedVersion(P, V, ver, verIsRel); + verset.insert(V); + } + if (pkgset.getConstructor() != PackageSet::UNKNOWN) + helper.showErrors(errors); + return verset; +} + /*}}}*/ +// FromPackage - versions from package based on fallback /*{{{*/ +VersionSet VersionSet::FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P, + VersionSet::Version const &fallback, CacheSetHelper &helper) { + VersionSet verset; + pkgCache::VerIterator V; + bool showErrors; + switch(fallback) { + case VersionSet::ALL: + if (P->VersionList != 0) + for (V = P.VersionList(); V.end() != true; ++V) + verset.insert(V); + else + verset.insert(helper.canNotFindAllVer(Cache, P)); + break; + case VersionSet::CANDANDINST: + verset.insert(getInstalledVer(Cache, P, helper)); + verset.insert(getCandidateVer(Cache, P, helper)); + break; + case VersionSet::CANDIDATE: + verset.insert(getCandidateVer(Cache, P, helper)); + break; + case VersionSet::INSTALLED: + verset.insert(getInstalledVer(Cache, P, helper)); + break; + case VersionSet::CANDINST: + showErrors = helper.showErrors(false); + V = getCandidateVer(Cache, P, helper); + if (V.end() == true) + V = getInstalledVer(Cache, P, helper); + helper.showErrors(showErrors); + if (V.end() == false) + verset.insert(V); + else + verset.insert(helper.canNotFindInstCandVer(Cache, P)); + break; + case VersionSet::INSTCAND: + showErrors = helper.showErrors(false); + V = getInstalledVer(Cache, P, helper); + if (V.end() == true) + V = getCandidateVer(Cache, P, helper); + helper.showErrors(showErrors); + if (V.end() == false) + verset.insert(V); + else + verset.insert(helper.canNotFindInstCandVer(Cache, P)); + break; + case VersionSet::NEWEST: + if (P->VersionList != 0) + verset.insert(P.VersionList()); + else + verset.insert(helper.canNotFindNewestVer(Cache, P)); + break; + } + return verset; +} + /*}}}*/ +// getCandidateVer - Returns the candidate version of the given package /*{{{*/ +pkgCache::VerIterator VersionSet::getCandidateVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper) { + pkgCache::VerIterator Cand; + if (Cache.IsPolicyBuilt() == true || Cache.IsDepCacheBuilt() == false) + { + if (unlikely(Cache.GetPolicy() == 0)) + return pkgCache::VerIterator(Cache); + Cand = Cache.GetPolicy()->GetCandidateVer(Pkg); + } else { + Cand = Cache[Pkg].CandidateVerIter(Cache); + } + if (Cand.end() == true) + return helper.canNotFindCandidateVer(Cache, Pkg); + return Cand; +} + /*}}}*/ +// getInstalledVer - Returns the installed version of the given package /*{{{*/ +pkgCache::VerIterator VersionSet::getInstalledVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper) { + if (Pkg->CurrentVer == 0) + return helper.canNotFindInstalledVer(Cache, Pkg); + return Pkg.CurrentVer(); +} + /*}}}*/ +// canNotFindPkgName - handle the case no package has this name /*{{{*/ +pkgCache::PkgIterator CacheSetHelper::canNotFindPkgName(pkgCacheFile &Cache, + std::string const &str) { + if (ShowError == true) + _error->Error(_("Unable to locate package %s"), str.c_str()); + return pkgCache::PkgIterator(Cache, 0); +} + /*}}}*/ +// canNotFindTask - handle the case no package is found for a task /*{{{*/ +PackageSet CacheSetHelper::canNotFindTask(pkgCacheFile &Cache, std::string pattern) { + if (ShowError == true) + _error->Error(_("Couldn't find task '%s'"), pattern.c_str()); + return PackageSet(); +} + /*}}}*/ +// canNotFindRegEx - handle the case no package is found by a regex /*{{{*/ +PackageSet CacheSetHelper::canNotFindRegEx(pkgCacheFile &Cache, std::string pattern) { + if (ShowError == true) + _error->Error(_("Couldn't find any package by regex '%s'"), pattern.c_str()); + return PackageSet(); +} + /*}}}*/ +// canNotFindPackage - handle the case no package is found from a string/*{{{*/ +PackageSet CacheSetHelper::canNotFindPackage(pkgCacheFile &Cache, std::string const &str) { + return PackageSet(); +} + /*}}}*/ +// canNotFindAllVer /*{{{*/ +VersionSet CacheSetHelper::canNotFindAllVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg) { + if (ShowError == true) + _error->Error(_("Can't select versions from package '%s' as it purely virtual"), Pkg.FullName(true).c_str()); + return VersionSet(); +} + /*}}}*/ +// canNotFindInstCandVer /*{{{*/ +VersionSet CacheSetHelper::canNotFindInstCandVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg) { + if (ShowError == true) + _error->Error(_("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str()); + return VersionSet(); +} + /*}}}*/ +// canNotFindInstCandVer /*{{{*/ +VersionSet CacheSetHelper::canNotFindCandInstVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg) { + if (ShowError == true) + _error->Error(_("Can't select installed nor candidate version from package '%s' as it has neither of them"), Pkg.FullName(true).c_str()); + return VersionSet(); +} + /*}}}*/ +// canNotFindNewestVer /*{{{*/ +pkgCache::VerIterator CacheSetHelper::canNotFindNewestVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg) { + if (ShowError == true) + _error->Error(_("Can't select newest version from package '%s' as it is purely virtual"), Pkg.FullName(true).c_str()); + return pkgCache::VerIterator(Cache, 0); +} + /*}}}*/ +// canNotFindCandidateVer /*{{{*/ +pkgCache::VerIterator CacheSetHelper::canNotFindCandidateVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg) { + if (ShowError == true) + _error->Error(_("Can't select candidate version from package %s as it has no candidate"), Pkg.FullName(true).c_str()); + return pkgCache::VerIterator(Cache, 0); +} + /*}}}*/ +// canNotFindInstalledVer /*{{{*/ +pkgCache::VerIterator CacheSetHelper::canNotFindInstalledVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg) { + if (ShowError == true) + _error->Error(_("Can't select installed version from package %s as it is not installed"), Pkg.FullName(true).c_str()); + return pkgCache::VerIterator(Cache, 0); +} + /*}}}*/ +} diff --git a/cmdline/cacheset.h b/cmdline/cacheset.h new file mode 100644 index 000000000..c8c3dd096 --- /dev/null +++ b/cmdline/cacheset.h @@ -0,0 +1,375 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/** \file cacheset.h + Wrappers around std::set to have set::iterators which behave + similar to the Iterators of the cache structures. + + Provides also a few helper methods which work with these sets */ + /*}}}*/ +#ifndef APT_CACHESET_H +#define APT_CACHESET_H +// Include Files /*{{{*/ +#include <iostream> +#include <fstream> +#include <list> +#include <map> +#include <set> +#include <string> + +#include <apt-pkg/cachefile.h> +#include <apt-pkg/pkgcache.h> + /*}}}*/ +namespace APT { +class PackageSet; +class VersionSet; +class CacheSetHelper { /*{{{*/ +/** \class APT::CacheSetHelper + Simple base class with a lot of virtual methods which can be overridden + to alter the behavior or the output of the CacheSets. + + This helper is passed around by the static methods in the CacheSets and + used every time they hit an error condition or something could be + printed out. +*/ +public: /*{{{*/ + CacheSetHelper(bool const &ShowError = true) : ShowError(ShowError) {}; + virtual ~CacheSetHelper() {}; + + virtual void showTaskSelection(PackageSet const &pkgset, string const &pattern) {}; + virtual void showRegExSelection(PackageSet const &pkgset, string const &pattern) {}; + virtual void showSelectedVersion(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const Ver, + string const &ver, bool const &verIsRel) {}; + + virtual pkgCache::PkgIterator canNotFindPkgName(pkgCacheFile &Cache, std::string const &str); + virtual PackageSet canNotFindTask(pkgCacheFile &Cache, std::string pattern); + virtual PackageSet canNotFindRegEx(pkgCacheFile &Cache, std::string pattern); + virtual PackageSet canNotFindPackage(pkgCacheFile &Cache, std::string const &str); + virtual VersionSet canNotFindAllVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg); + virtual VersionSet canNotFindInstCandVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg); + virtual VersionSet canNotFindCandInstVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg); + virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg); + virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg); + virtual pkgCache::VerIterator canNotFindInstalledVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg); + + bool showErrors() const { return ShowError; }; + bool showErrors(bool const &newValue) { if (ShowError == newValue) return ShowError; else return ((ShowError = newValue) == false); }; + /*}}}*/ +protected: + bool ShowError; +}; /*}}}*/ +class PackageSet : public std::set<pkgCache::PkgIterator> { /*{{{*/ +/** \class APT::PackageSet + + Simple wrapper around a std::set to provide a similar interface to + a set of packages as to the complete set of all packages in the + pkgCache. */ +public: /*{{{*/ + /** \brief smell like a pkgCache::PkgIterator */ + class const_iterator : public std::set<pkgCache::PkgIterator>::const_iterator {/*{{{*/ + public: + const_iterator(std::set<pkgCache::PkgIterator>::const_iterator x) : + std::set<pkgCache::PkgIterator>::const_iterator(x) {} + + operator pkgCache::PkgIterator(void) { return **this; } + + inline const char *Name() const {return (**this).Name(); } + inline std::string FullName(bool const &Pretty) const { return (**this).FullName(Pretty); } + inline std::string FullName() const { return (**this).FullName(); } + inline const char *Section() const {return (**this).Section(); } + inline bool Purge() const {return (**this).Purge(); } + inline const char *Arch() const {return (**this).Arch(); } + inline pkgCache::GrpIterator Group() const { return (**this).Group(); } + inline pkgCache::VerIterator VersionList() const { return (**this).VersionList(); } + inline pkgCache::VerIterator CurrentVer() const { return (**this).CurrentVer(); } + inline pkgCache::DepIterator RevDependsList() const { return (**this).RevDependsList(); } + inline pkgCache::PrvIterator ProvidesList() const { return (**this).ProvidesList(); } + inline pkgCache::PkgIterator::OkState State() const { return (**this).State(); } + inline const char *CandVersion() const { return (**this).CandVersion(); } + inline const char *CurVersion() const { return (**this).CurVersion(); } + inline pkgCache *Cache() const { return (**this).Cache(); }; + inline unsigned long Index() const {return (**this).Index();}; + // we have only valid iterators here + inline bool end() const { return false; }; + + friend std::ostream& operator<<(std::ostream& out, const_iterator i) { return operator<<(out, (*i)); } + + inline pkgCache::Package const * operator->() const { + return &***this; + }; + }; + // 103. set::iterator is required to be modifiable, but this allows modification of keys + typedef APT::PackageSet::const_iterator iterator; + /*}}}*/ + + using std::set<pkgCache::PkgIterator>::insert; + inline void insert(pkgCache::PkgIterator const &P) { if (P.end() == false) std::set<pkgCache::PkgIterator>::insert(P); }; + inline void insert(PackageSet const &pkgset) { insert(pkgset.begin(), pkgset.end()); }; + + /** \brief returns all packages in the cache who belong to the given task + + A simple helper responsible for search for all members of a task + in the cache. Optional it prints a a notice about the + packages chosen cause of the given task. + \param Cache the packages are in + \param pattern name of the task + \param helper responsible for error and message handling */ + static APT::PackageSet FromTask(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper); + static APT::PackageSet FromTask(pkgCacheFile &Cache, std::string const &pattern) { + CacheSetHelper helper; + return APT::PackageSet::FromTask(Cache, pattern, helper); + } + + /** \brief returns all packages in the cache whose name matchs a given pattern + + A simple helper responsible for executing a regular expression on all + package names in the cache. Optional it prints a a notice about the + packages chosen cause of the given package. + \param Cache the packages are in + \param pattern regular expression for package names + \param helper responsible for error and message handling */ + static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper); + static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string const &pattern) { + CacheSetHelper helper; + return APT::PackageSet::FromRegEx(Cache, pattern, helper); + } + + /** \brief returns all packages specified by a string + + \param Cache the packages are in + \param string String the package name(s) should be extracted from + \param helper responsible for error and message handling */ + static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string, CacheSetHelper &helper); + static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string) { + CacheSetHelper helper; + return APT::PackageSet::FromString(Cache, string, helper); + } + + /** \brief returns a package specified by a string + + \param Cache the package is in + \param string String the package name should be extracted from + \param helper responsible for error and message handling */ + static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &string, CacheSetHelper &helper); + static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &string) { + CacheSetHelper helper; + return APT::PackageSet::FromName(Cache, string, helper); + } + + /** \brief returns all packages specified on the commandline + + Get all package names from the commandline and executes regex's if needed. + No special package command is supported, just plain names. + \param Cache the packages are in + \param cmdline Command line the package names should be extracted from + \param helper responsible for error and message handling */ + static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper); + static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline) { + CacheSetHelper helper; + return APT::PackageSet::FromCommandLine(Cache, cmdline, helper); + } + + struct Modifier { + enum Position { NONE, PREFIX, POSTFIX }; + unsigned short ID; + const char * const Alias; + Position Pos; + Modifier (unsigned short const &id, const char * const alias, Position const &pos) : ID(id), Alias(alias), Pos(pos) {}; + }; + + /** \brief group packages by a action modifiers + + At some point it is needed to get from the same commandline + different package sets grouped by a modifier. Take + apt-get install apt awesome- + as an example. + \param Cache the packages are in + \param cmdline Command line the package names should be extracted from + \param mods list of modifiers the method should accept + \param fallback the default modifier group for a package + \param helper responsible for error and message handling */ + static std::map<unsigned short, PackageSet> GroupedFromCommandLine( + pkgCacheFile &Cache, const char **cmdline, + std::list<PackageSet::Modifier> const &mods, + unsigned short const &fallback, CacheSetHelper &helper); + static std::map<unsigned short, PackageSet> GroupedFromCommandLine( + pkgCacheFile &Cache, const char **cmdline, + std::list<PackageSet::Modifier> const &mods, + unsigned short const &fallback) { + CacheSetHelper helper; + return APT::PackageSet::GroupedFromCommandLine(Cache, cmdline, + mods, fallback, helper); + } + + enum Constructor { UNKNOWN, REGEX, TASK }; + Constructor getConstructor() const { return ConstructedBy; }; + + PackageSet() : ConstructedBy(UNKNOWN) {}; + PackageSet(Constructor const &by) : ConstructedBy(by) {}; + /*}}}*/ +private: /*{{{*/ + Constructor ConstructedBy; + /*}}}*/ +}; /*}}}*/ +class VersionSet : public std::set<pkgCache::VerIterator> { /*{{{*/ +/** \class APT::VersionSet + + Simple wrapper around a std::set to provide a similar interface to + a set of versions as to the complete set of all versions in the + pkgCache. */ +public: /*{{{*/ + /** \brief smell like a pkgCache::VerIterator */ + class const_iterator : public std::set<pkgCache::VerIterator>::const_iterator {/*{{{*/ + public: + const_iterator(std::set<pkgCache::VerIterator>::const_iterator x) : + std::set<pkgCache::VerIterator>::const_iterator(x) {} + + operator pkgCache::VerIterator(void) { return **this; } + + inline pkgCache *Cache() const { return (**this).Cache(); }; + inline unsigned long Index() const {return (**this).Index();}; + // we have only valid iterators here + inline bool end() const { return false; }; + + inline pkgCache::Version const * operator->() const { + return &***this; + }; + + inline int CompareVer(const pkgCache::VerIterator &B) const { return (**this).CompareVer(B); }; + inline const char *VerStr() const { return (**this).VerStr(); }; + inline const char *Section() const { return (**this).Section(); }; + inline const char *Arch() const { return (**this).Arch(); }; + inline const char *Arch(bool const pseudo) const { return (**this).Arch(pseudo); }; + inline pkgCache::PkgIterator ParentPkg() const { return (**this).ParentPkg(); }; + inline pkgCache::DescIterator DescriptionList() const { return (**this).DescriptionList(); }; + inline pkgCache::DescIterator TranslatedDescription() const { return (**this).TranslatedDescription(); }; + inline pkgCache::DepIterator DependsList() const { return (**this).DependsList(); }; + inline pkgCache::PrvIterator ProvidesList() const { return (**this).ProvidesList(); }; + inline pkgCache::VerFileIterator FileList() const { return (**this).FileList(); }; + inline bool Downloadable() const { return (**this).Downloadable(); }; + inline const char *PriorityType() const { return (**this).PriorityType(); }; + inline string RelStr() const { return (**this).RelStr(); }; + inline bool Automatic() const { return (**this).Automatic(); }; + inline bool Pseudo() const { return (**this).Pseudo(); }; + inline pkgCache::VerFileIterator NewestFile() const { return (**this).NewestFile(); }; + }; + /*}}}*/ + // 103. set::iterator is required to be modifiable, but this allows modification of keys + typedef APT::VersionSet::const_iterator iterator; + + using std::set<pkgCache::VerIterator>::insert; + inline void insert(pkgCache::VerIterator const &V) { if (V.end() == false) std::set<pkgCache::VerIterator>::insert(V); }; + inline void insert(VersionSet const &verset) { insert(verset.begin(), verset.end()); }; + + /** \brief specifies which version(s) will be returned if non is given */ + enum Version { + /** All versions */ + ALL, + /** Candidate and installed version */ + CANDANDINST, + /** Candidate version */ + CANDIDATE, + /** Installed version */ + INSTALLED, + /** Candidate or if non installed version */ + CANDINST, + /** Installed or if non candidate version */ + INSTCAND, + /** Newest version */ + NEWEST + }; + + /** \brief returns all versions specified on the commandline + + Get all versions from the commandline, uses given default version if + non specifically requested and executes regex's if needed on names. + \param Cache the packages and versions are in + \param cmdline Command line the versions should be extracted from + \param helper responsible for error and message handling */ + static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline, + APT::VersionSet::Version const &fallback, CacheSetHelper &helper); + static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline, + APT::VersionSet::Version const &fallback) { + CacheSetHelper helper; + return APT::VersionSet::FromCommandLine(Cache, cmdline, fallback, helper); + } + static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline) { + return APT::VersionSet::FromCommandLine(Cache, cmdline, CANDINST); + } + + static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg, + APT::VersionSet::Version const &fallback, CacheSetHelper &helper, + bool const &onlyFromName = false); + static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg, + APT::VersionSet::Version const &fallback) { + CacheSetHelper helper; + return APT::VersionSet::FromString(Cache, pkg, fallback, helper); + } + static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg) { + return APT::VersionSet::FromString(Cache, pkg, CANDINST); + } + + /** \brief returns all versions specified for the package + + \param Cache the package and versions are in + \param P the package in question + \param fallback the version(s) you want to get + \param helper the helper used for display and error handling */ + static APT::VersionSet FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P, + VersionSet::Version const &fallback, CacheSetHelper &helper); + static APT::VersionSet FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P, + APT::VersionSet::Version const &fallback) { + CacheSetHelper helper; + return APT::VersionSet::FromPackage(Cache, P, fallback, helper); + } + static APT::VersionSet FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P) { + return APT::VersionSet::FromPackage(Cache, P, CANDINST); + } + + struct Modifier { + enum Position { NONE, PREFIX, POSTFIX }; + unsigned short ID; + const char * const Alias; + Position Pos; + VersionSet::Version SelectVersion; + Modifier (unsigned short const &id, const char * const alias, Position const &pos, + VersionSet::Version const &select) : ID(id), Alias(alias), Pos(pos), + SelectVersion(select) {}; + }; + + static std::map<unsigned short, VersionSet> GroupedFromCommandLine( + pkgCacheFile &Cache, const char **cmdline, + std::list<VersionSet::Modifier> const &mods, + unsigned short const &fallback, CacheSetHelper &helper); + static std::map<unsigned short, VersionSet> GroupedFromCommandLine( + pkgCacheFile &Cache, const char **cmdline, + std::list<VersionSet::Modifier> const &mods, + unsigned short const &fallback) { + CacheSetHelper helper; + return APT::VersionSet::GroupedFromCommandLine(Cache, cmdline, + mods, fallback, helper); + } + /*}}}*/ +protected: /*{{{*/ + + /** \brief returns the candidate version of the package + + \param Cache to be used to query for information + \param Pkg we want the candidate version from this package */ + static pkgCache::VerIterator getCandidateVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper); + + /** \brief returns the installed version of the package + + \param Cache to be used to query for information + \param Pkg we want the installed version from this package */ + static pkgCache::VerIterator getInstalledVer(pkgCacheFile &Cache, + pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper); + /*}}}*/ +}; /*}}}*/ +} +#endif diff --git a/cmdline/makefile b/cmdline/makefile index 917ccc96a..4ffe49ee0 100644 --- a/cmdline/makefile +++ b/cmdline/makefile @@ -9,14 +9,14 @@ include ../buildlib/defaults.mak PROGRAM=apt-cache SLIBS = -lapt-pkg $(INTLLIBS) LIB_MAKES = apt-pkg/makefile -SOURCE = apt-cache.cc +SOURCE = apt-cache.cc cacheset.cc include $(PROGRAM_H) # The apt-get program PROGRAM=apt-get SLIBS = -lapt-pkg -lutil $(INTLLIBS) LIB_MAKES = apt-pkg/makefile -SOURCE = apt-get.cc acqprogress.cc +SOURCE = apt-get.cc acqprogress.cc cacheset.cc include $(PROGRAM_H) # The apt-config program |