Просмотр исходного кода

Use an abstract helper for error handling and output
instead of doing this directly in the CacheSets.
With this method an application like apt-get can change
the behavior of the CacheSets to his liking.
It can for example easily keep track of how packages
were added to the set: by names or with regex's…

David Kalnischkies лет назад: 16
Родитель
Сommit
70e706adf7
3 измененных файлов с 244 добавлено и 118 удалено
  1. 56 23
      cmdline/apt-get.cc
  2. 117 62
      cmdline/cacheset.cc
  3. 71 33
      cmdline/cacheset.h

+ 56 - 23
cmdline/apt-get.cc

@@ -1079,7 +1079,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
    name matching it was split out.. */
 bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &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. */
@@ -1244,9 +1244,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
 		     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)
@@ -1589,6 +1587,41 @@ 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;
+
+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());
+	}
+
+	inline bool allPkgNamedExplicitly() const { return explicitlyNamed; }
+
+};
+									/*}}}*/
 // DoInstall - Install packages from the command line			/*{{{*/
 // ---------------------------------------------------------------------
 /* Install named packages */
@@ -1605,7 +1638,6 @@ bool DoInstall(CommandLine &CmdL)
       BrokenFix = true;
    
    unsigned int AutoMarkChanged = 0;
-   unsigned int ExpectedInst = 0;
    pkgProblemResolver Fix(Cache);
 
    unsigned short fallback = 0;
@@ -1621,28 +1653,29 @@ bool DoInstall(CommandLine &CmdL)
       _config->Set("APT::Get::AutomaticRemove", "true");
       fallback = 1;
    }
-   // new scope for the ActionGroup
-   {
-      // TODO: Howto get an ExpectedInst count ?
-      pkgDepCache::ActionGroup group(Cache);
-      std::list<APT::VersionSet::Modifier> mods;
-      mods.push_back(APT::VersionSet::Modifier(0, "+",
+
+   std::list<APT::VersionSet::Modifier> mods;
+   mods.push_back(APT::VersionSet::Modifier(0, "+",
 		APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDINST));
-      mods.push_back(APT::VersionSet::Modifier(1, "-",
+   mods.push_back(APT::VersionSet::Modifier(1, "-",
 		APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::INSTCAND));
-      std::map<unsigned short, APT::VersionSet> verset = APT::VersionSet::GroupedFromCommandLine(Cache,
-		CmdL.FileList + 1, mods, fallback, c0out);
+   CacheSetHelperAPTGet helper(c0out);
+   std::map<unsigned short, APT::VersionSet> verset = APT::VersionSet::GroupedFromCommandLine(Cache,
+		CmdL.FileList + 1, mods, fallback, helper);
 
-      if (_error->PendingError() == true)
-	 return false;
+   if (_error->PendingError() == true)
+      return false;
 
+   // new scope for the ActionGroup
+   {
+      pkgDepCache::ActionGroup group(Cache);
       for (APT::VersionSet::const_iterator Ver = verset[0].begin();
 	   Ver != verset[0].end(); ++Ver)
       {
 	 pkgCache::PkgIterator Pkg = Ver.ParentPkg();
 	 Cache->SetCandidateVersion(Ver);
 
-	 if (TryToInstall(Pkg, Cache, Fix, false, BrokenFix, ExpectedInst) == false)
+	 if (TryToInstall(Pkg, Cache, Fix, false, BrokenFix) == false)
 	    return false;
 
 	 // see if we need to fix the auto-mark flag
@@ -1666,7 +1699,7 @@ bool DoInstall(CommandLine &CmdL)
       {
 	 pkgCache::PkgIterator Pkg = Ver.ParentPkg();
 
-	 if (TryToInstall(Pkg, Cache, Fix, true, BrokenFix, ExpectedInst) == false)
+	 if (TryToInstall(Pkg, Cache, Fix, true, BrokenFix) == false)
 	    return false;
       }
 
@@ -1719,7 +1752,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[0].size())
    {
       string List;
       string VersionsList;
@@ -1845,7 +1878,8 @@ bool DoInstall(CommandLine &CmdL)
       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[0].size() && Cache->DelCount() == 0)
       return InstallPackages(Cache,false,false);
 
    return InstallPackages(Cache,false);   
@@ -2429,7 +2463,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
@@ -2460,7 +2493,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);
+               TryToInstall(Pkg,Cache,Fix,true,false);
          }
 	 else // BuildDep || BuildDepIndep
          {
@@ -2576,7 +2609,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 (TryToInstall(Pkg,Cache,Fix,false,false) == true)
             {
                // We successfully installed something; skip remaining alternatives
                skipAlternatives = hasAlternatives;

+ 117 - 62
cmdline/cacheset.cc

@@ -24,7 +24,7 @@
 									/*}}}*/
 namespace APT {
 // FromTask - Return all packages in the cache from a specific task	/*{{{*/
-PackageSet PackageSet::FromTask(pkgCacheFile &Cache, std::string pattern, std::ostream &out) {
+PackageSet PackageSet::FromTask(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
 	PackageSet pkgset;
 	if (Cache.BuildCaches() == false || Cache.BuildDepCache() == false)
 		return pkgset;
@@ -67,19 +67,22 @@ PackageSet PackageSet::FromTask(pkgCacheFile &Cache, std::string pattern, std::o
 		char buf[length];
 		strncpy(buf, start, length);
 		buf[length-1] = '\0';
-		if (regexec(&Pattern, buf, 0, 0, 0) == 0)
-			pkgset.insert(Pkg);
+		if (regexec(&Pattern, buf, 0, 0, 0) != 0)
+			continue;
+
+		pkgset.insert(Pkg);
 	}
+	regfree(&Pattern);
 
 	if (pkgset.empty() == true)
-		_error->Error(_("Couldn't find task %s"), pattern.c_str());
+		return helper.canNotFindTask(Cache, pattern);
 
-	regfree(&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, std::ostream &out) {
+PackageSet PackageSet::FromRegEx(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) {
 	PackageSet pkgset;
 	static const char * const isregex = ".?+*|[^$";
 
@@ -121,14 +124,14 @@ PackageSet PackageSet::FromRegEx(pkgCacheFile &Cache, std::string pattern, std::
 				continue;
 		}
 
-		ioprintf(out, _("Note, selecting %s for regex '%s'\n"),
-			 Pkg.FullName(true).c_str(), pattern.c_str());
-
 		pkgset.insert(Pkg);
 	}
-
 	regfree(&Pattern);
 
+	if (pkgset.empty() == true)
+		return helper.canNotFindRegEx(Cache, pattern);
+
+	helper.showRegExSelection(pkgset, pattern);
 	return pkgset;
 }
 									/*}}}*/
@@ -136,7 +139,7 @@ PackageSet PackageSet::FromRegEx(pkgCacheFile &Cache, std::string pattern, std::
 std::map<unsigned short, PackageSet> PackageSet::GroupedFromCommandLine(
 		pkgCacheFile &Cache, const char **cmdline,
 		std::list<PackageSet::Modifier> const &mods,
-		unsigned short const &fallback, std::ostream &out) {
+		unsigned short const &fallback, CacheSetHelper &helper) {
 	std::map<unsigned short, PackageSet> pkgsets;
 	for (const char **I = cmdline; *I != 0; ++I) {
 		unsigned short modID = fallback;
@@ -159,24 +162,23 @@ std::map<unsigned short, PackageSet> PackageSet::GroupedFromCommandLine(
 			}
 			break;
 		}
-		PackageSet pset = PackageSet::FromString(Cache, str, out);
-		pkgsets[modID].insert(pset.begin(), pset.end());
+		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, std::ostream &out) {
+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, out);
+		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, std::ostream &out) {
+PackageSet PackageSet::FromString(pkgCacheFile &Cache, std::string const &str, CacheSetHelper &helper) {
 	std::string pkg = str;
 	size_t archfound = pkg.find_last_of(':');
 	std::string arch;
@@ -198,23 +200,22 @@ PackageSet PackageSet::FromString(pkgCacheFile &Cache, std::string const &str, s
 		pkgset.insert(Pkg);
 		return pkgset;
 	}
-	PackageSet pset = FromTask(Cache, str, out);
+	PackageSet pset = FromTask(Cache, str, helper);
 	if (pset.empty() == false)
 		return pset;
 
-	pset = FromRegEx(Cache, str, out);
+	pset = FromRegEx(Cache, str, helper);
 	if (pset.empty() == false)
 		return pset;
 
-	_error->Warning(_("Unable to locate package %s"), str.c_str());
-	return pset;
+	return helper.canNotFindPackage(Cache, str);
 }
 									/*}}}*/
 // 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, std::ostream &out) {
+		unsigned short const &fallback, CacheSetHelper &helper) {
 	std::map<unsigned short, VersionSet> versets;
 	for (const char **I = cmdline; *I != 0; ++I) {
 		unsigned short modID = fallback;
@@ -241,18 +242,17 @@ std::map<unsigned short, VersionSet> VersionSet::GroupedFromCommandLine(
 			}
 			break;
 		}
-		VersionSet vset = VersionSet::FromString(Cache, str, select , out);
-		versets[modID].insert(vset.begin(), vset.end());
+		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, std::ostream &out) {
+		APT::VersionSet::Version const &fallback, CacheSetHelper &helper) {
 	VersionSet verset;
 	for (const char **I = cmdline; *I != 0; ++I) {
-		VersionSet vset = VersionSet::FromString(Cache, *I, fallback, out);
+		VersionSet vset = VersionSet::FromString(Cache, *I, fallback, helper);
 		verset.insert(vset.begin(), vset.end());
 	}
 	return verset;
@@ -260,7 +260,7 @@ APT::VersionSet VersionSet::FromCommandLine(pkgCacheFile &Cache, const char **cm
 									/*}}}*/
 // FromString - Returns all versions spedcified by a string		/*{{{*/
 APT::VersionSet VersionSet::FromString(pkgCacheFile &Cache, std::string pkg,
-		APT::VersionSet::Version const &fallback, std::ostream &out) {
+		APT::VersionSet::Version const &fallback, CacheSetHelper &helper) {
 	std::string ver;
 	bool verIsRel = false;
 	size_t const vertag = pkg.find_last_of("/=");
@@ -269,19 +269,19 @@ APT::VersionSet VersionSet::FromString(pkgCacheFile &Cache, std::string pkg,
 		verIsRel = (pkg[vertag] == '/');
 		pkg.erase(vertag);
 	}
-	PackageSet pkgset = PackageSet::FromString(Cache, pkg.c_str(), out);
+	PackageSet pkgset = PackageSet::FromString(Cache, pkg.c_str(), helper);
 	VersionSet verset;
 	for (PackageSet::const_iterator P = pkgset.begin();
 	     P != pkgset.end(); ++P) {
 		if (vertag == string::npos) {
-			AddSelectedVersion(Cache, verset, P, fallback);
+			AddSelectedVersion(Cache, verset, P, fallback, helper);
 			continue;
 		}
 		pkgCache::VerIterator V;
 		if (ver == "installed")
-			V = getInstalledVer(Cache, P);
+			V = getInstalledVer(Cache, P, helper);
 		else if (ver == "candidate")
-			V = getCandidateVer(Cache, P);
+			V = getCandidateVer(Cache, P, helper);
 		else {
 			pkgVersionMatch Match(ver, (verIsRel == true ? pkgVersionMatch::Release :
 					pkgVersionMatch::Version));
@@ -298,76 +298,70 @@ APT::VersionSet VersionSet::FromString(pkgCacheFile &Cache, std::string pkg,
 		}
 		if (V.end() == true)
 			continue;
-		if (ver != V.VerStr())
-			ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"),
-				 V.VerStr(), V.RelStr().c_str(), P.FullName(true).c_str());
+		helper.showSelectedVersion(P, V, ver, verIsRel);
 		verset.insert(V);
 	}
 	return verset;
 }
 									/*}}}*/
 // AddSelectedVersion - add version from package based on fallback	/*{{{*/
-bool VersionSet::AddSelectedVersion(pkgCacheFile &Cache, VersionSet &verset,
+void VersionSet::AddSelectedVersion(pkgCacheFile &Cache, VersionSet &verset,
 		pkgCache::PkgIterator const &P, VersionSet::Version const &fallback,
-		bool const &AllowError) {
+		CacheSetHelper &helper) {
 	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 if (AllowError == false)
-			return _error->Error(_("Can't select versions from package '%s' as it purely virtual"), P.FullName(true).c_str());
 		else
-			return false;
+			verset.insert(helper.canNotFindAllVer(Cache, P));
 		break;
 	case VersionSet::CANDANDINST:
-		verset.insert(getInstalledVer(Cache, P, AllowError));
-		verset.insert(getCandidateVer(Cache, P, AllowError));
+		verset.insert(getInstalledVer(Cache, P, helper));
+		verset.insert(getCandidateVer(Cache, P, helper));
 		break;
 	case VersionSet::CANDIDATE:
-		verset.insert(getCandidateVer(Cache, P, AllowError));
+		verset.insert(getCandidateVer(Cache, P, helper));
 		break;
 	case VersionSet::INSTALLED:
-		verset.insert(getInstalledVer(Cache, P, AllowError));
+		verset.insert(getInstalledVer(Cache, P, helper));
 		break;
 	case VersionSet::CANDINST:
-		V = getCandidateVer(Cache, P, true);
+		showErrors = helper.showErrors(false);
+		V = getCandidateVer(Cache, P, helper);
 		if (V.end() == true)
-			V = getInstalledVer(Cache, P, true);
+			V = getInstalledVer(Cache, P, helper);
+		helper.showErrors(showErrors);
 		if (V.end() == false)
 			verset.insert(V);
-		else if (AllowError == false)
-			return _error->Error(_("Can't select installed nor candidate version from package '%s' as it has neither of them"), P.FullName(true).c_str());
 		else
-			return false;
+			verset.insert(helper.canNotFindInstCandVer(Cache, P));
 		break;
 	case VersionSet::INSTCAND:
-		V = getInstalledVer(Cache, P, true);
+		showErrors = helper.showErrors(false);
+		V = getInstalledVer(Cache, P, helper);
 		if (V.end() == true)
-			V = getCandidateVer(Cache, P, true);
+			V = getCandidateVer(Cache, P, helper);
+		helper.showErrors(showErrors);
 		if (V.end() == false)
 			verset.insert(V);
-		else if (AllowError == false)
-			return _error->Error(_("Can't select installed nor candidate version from package '%s' as it has neither of them"), P.FullName(true).c_str());
 		else
-			return false;
+			verset.insert(helper.canNotFindInstCandVer(Cache, P));
 		break;
 	case VersionSet::NEWEST:
 		if (P->VersionList != 0)
 			verset.insert(P.VersionList());
-		else if (AllowError == false)
-			return _error->Error(_("Can't select newest version from package '%s' as it is purely virtual"), P.FullName(true).c_str());
 		else
-			return false;
+			verset.insert(helper.canNotFindNewestVer(Cache, P));
 		break;
 	}
-	return true;
 }
 									/*}}}*/
 // getCandidateVer - Returns the candidate version of the given package	/*{{{*/
 pkgCache::VerIterator VersionSet::getCandidateVer(pkgCacheFile &Cache,
-		pkgCache::PkgIterator const &Pkg, bool const &AllowError) {
+		pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper) {
 	pkgCache::VerIterator Cand;
 	if (Cache.IsDepCacheBuilt() == true)
 		Cand = Cache[Pkg].CandidateVerIter(Cache);
@@ -376,17 +370,78 @@ pkgCache::VerIterator VersionSet::getCandidateVer(pkgCacheFile &Cache,
 			return pkgCache::VerIterator(*Cache);
 		Cand = Cache.GetPolicy()->GetCandidateVer(Pkg);
 	}
-	if (AllowError == false && Cand.end() == true)
-		_error->Error(_("Can't select candidate version from package %s as it has no candidate"), Pkg.FullName(true).c_str());
+	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, bool const &AllowError) {
-	if (AllowError == false && Pkg->CurrentVer == 0)
-		_error->Error(_("Can't select installed version from package %s as it is not installed"), Pkg.FullName(true).c_str());
+		pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper) {
+	if (Pkg->CurrentVer == 0)
+		return helper.canNotFindInstalledVer(Cache, Pkg);
 	return Pkg.CurrentVer();
 }
 									/*}}}*/
+// 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) {
+	if (ShowError == true)
+		_error->Error(_("Unable to locate package %s"), str.c_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();
+}
+									/*}}}*/
+// 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);
+}
+									/*}}}*/
+// 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);
+}
+									/*}}}*/
+// 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);
+}
+									/*}}}*/
 }

+ 71 - 33
cmdline/cacheset.h

@@ -20,6 +20,45 @@
 #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 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 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
 
@@ -66,6 +105,7 @@ public:									/*{{{*/
 
 	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
 
@@ -75,10 +115,10 @@ public:									/*{{{*/
 	    \param Cache the packages are in
 	    \param pattern name of the task
 	    \param out stream to print the notice to */
-	static APT::PackageSet FromTask(pkgCacheFile &Cache, std::string pattern, std::ostream &out);
+	static APT::PackageSet FromTask(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
 	static APT::PackageSet FromTask(pkgCacheFile &Cache, std::string const &pattern) {
-		std::ostream out (std::ofstream("/dev/null").rdbuf());
-		return APT::PackageSet::FromTask(Cache, pattern, out);
+		CacheSetHelper helper;
+		return APT::PackageSet::FromTask(Cache, pattern, helper);
 	}
 
 	/** \brief returns all packages in the cache whose name matchs a given pattern
@@ -89,10 +129,10 @@ public:									/*{{{*/
 	    \param Cache the packages are in
 	    \param pattern regular expression for package names
 	    \param out stream to print the notice to */
-	static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string pattern, std::ostream &out);
+	static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
 	static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string const &pattern) {
-		std::ostream out (std::ofstream("/dev/null").rdbuf());
-		return APT::PackageSet::FromRegEx(Cache, pattern, out);
+		CacheSetHelper helper;
+		return APT::PackageSet::FromRegEx(Cache, pattern, helper);
 	}
 
 	/** \brief returns all packages specified by a string
@@ -100,10 +140,10 @@ public:									/*{{{*/
 	    \param Cache the packages are in
 	    \param string String the package name(s) should be extracted from
 	    \param out stream to print various notices to */
-	static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string, std::ostream &out);
+	static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string, CacheSetHelper &helper);
 	static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string) {
-		std::ostream out (std::ofstream("/dev/null").rdbuf());
-		return APT::PackageSet::FromString(Cache, string, out);
+		CacheSetHelper helper;
+		return APT::PackageSet::FromString(Cache, string, helper);
 	}
 
 	/** \brief returns all packages specified on the commandline
@@ -113,10 +153,10 @@ public:									/*{{{*/
 	    \param Cache the packages are in
 	    \param cmdline Command line the package names should be extracted from
 	    \param out stream to print various notices to */
-	static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline, std::ostream &out);
+	static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper);
 	static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline) {
-		std::ostream out (std::ofstream("/dev/null").rdbuf());
-		return APT::PackageSet::FromCommandLine(Cache, cmdline, out);
+		CacheSetHelper helper;
+		return APT::PackageSet::FromCommandLine(Cache, cmdline, helper);
 	}
 
 	struct Modifier {
@@ -130,14 +170,14 @@ public:									/*{{{*/
 	static std::map<unsigned short, PackageSet> GroupedFromCommandLine(
 		pkgCacheFile &Cache, const char **cmdline,
 		std::list<PackageSet::Modifier> const &mods,
-		unsigned short const &fallback, std::ostream &out);
+		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) {
-		std::ostream out (std::ofstream("/dev/null").rdbuf());
+		CacheSetHelper helper;
 		return APT::PackageSet::GroupedFromCommandLine(Cache, cmdline,
-				mods, fallback, out);
+				mods, fallback, helper);
 	}
 									/*}}}*/
 };									/*}}}*/
@@ -189,6 +229,7 @@ public:									/*{{{*/
 
 	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 {
@@ -216,22 +257,22 @@ public:									/*{{{*/
 	    \param cmdline Command line the versions should be extracted from
 	    \param out stream to print various notices to */
 	static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
-			APT::VersionSet::Version const &fallback, std::ostream &out);
+			APT::VersionSet::Version const &fallback, CacheSetHelper &helper);
 	static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
 			APT::VersionSet::Version const &fallback) {
-		std::ostream out (std::ofstream("/dev/null").rdbuf());
-		return APT::VersionSet::FromCommandLine(Cache, cmdline, fallback, out);
+		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, std::ostream &out);
+			APT::VersionSet::Version const &fallback, CacheSetHelper &helper);
 	static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg,
 			APT::VersionSet::Version const &fallback) {
-		std::ostream out (std::ofstream("/dev/null").rdbuf());
-		return APT::VersionSet::FromString(Cache, pkg, fallback, out);
+		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);
@@ -251,14 +292,14 @@ public:									/*{{{*/
 	static std::map<unsigned short, VersionSet> GroupedFromCommandLine(
 		pkgCacheFile &Cache, const char **cmdline,
 		std::list<VersionSet::Modifier> const &mods,
-		unsigned short const &fallback, std::ostream &out);
+		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) {
-		std::ostream out (std::ofstream("/dev/null").rdbuf());
+		CacheSetHelper helper;
 		return APT::VersionSet::GroupedFromCommandLine(Cache, cmdline,
-				mods, fallback, out);
+				mods, fallback, helper);
 	}
 									/*}}}*/
 protected:								/*{{{*/
@@ -266,23 +307,20 @@ 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
-	    \param AllowError add an error to the stack if not */
+	    \param Pkg we want the candidate version from this package */
 	static pkgCache::VerIterator getCandidateVer(pkgCacheFile &Cache,
-		pkgCache::PkgIterator const &Pkg, bool const &AllowError = false);
+		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
-	    \param AllowError add an error to the stack if not */
+	    \param Pkg we want the installed version from this package */
 	static pkgCache::VerIterator getInstalledVer(pkgCacheFile &Cache,
-		pkgCache::PkgIterator const &Pkg, bool const &AllowError = false);
-
+		pkgCache::PkgIterator const &Pkg, CacheSetHelper &helper);
 
-	static bool AddSelectedVersion(pkgCacheFile &Cache, VersionSet &verset,
+	static void AddSelectedVersion(pkgCacheFile &Cache, VersionSet &verset,
 		pkgCache::PkgIterator const &P, VersionSet::Version const &fallback,
-		bool const &AllowError = false);
+		CacheSetHelper &helper);
 
 									/*}}}*/
 };									/*}}}*/