#include <apt-pkg/sptr.h>
#include <apt-pkg/md5.h>
#include <apt-pkg/versionmatch.h>
-
+
#include <config.h>
#include <apti18n.h>
#include "acqprogress.h"
+#include "cacheset.h"
#include <set>
#include <locale.h>
bool BuildCaches(bool WithLock = true)
{
OpTextProgress Prog(*_config);
- if (pkgCacheFile::BuildCaches(Prog,WithLock) == false)
+ if (pkgCacheFile::BuildCaches(&Prog,WithLock) == false)
return false;
return true;
}
bool Open(bool WithLock = true)
{
OpTextProgress Prog(*_config);
- if (pkgCacheFile::Open(Prog,WithLock) == false)
+ if (pkgCacheFile::Open(&Prog,WithLock) == false)
return false;
Sort();
return false;
// Display statistics
- double FetchBytes = Fetcher.FetchNeeded();
- double FetchPBytes = Fetcher.PartialPresent();
- double DebBytes = Fetcher.TotalNeeded();
+ unsigned long long FetchBytes = Fetcher.FetchNeeded();
+ unsigned long long FetchPBytes = Fetcher.PartialPresent();
+ unsigned long long DebBytes = Fetcher.TotalNeeded();
if (DebBytes != Cache->DebSize())
{
c0out << DebBytes << ',' << Cache->DebSize() << endl;
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. */
- 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;
- }
- }
// Handle the no-upgrade case
if (_config->FindB("APT::Get::upgrade",true) == false &&
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")));
-
return true;
}
/*}}}*/
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);
+// 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());
+ }
+
+ virtual APT::VersionSet canNotFindCandInstVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
+ return tryVirtualPackage(Cache, Pkg, APT::VersionSet::CANDINST);
+ }
+
+ virtual APT::VersionSet canNotFindInstCandVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) {
+ return tryVirtualPackage(Cache, Pkg, APT::VersionSet::INSTCAND);
+ }
+
+ APT::VersionSet tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg,
+ APT::VersionSet::Version const &select) {
+ /* This is a pure virtual package and there is a single available
+ candidate providing it. */
+ if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0) {
+ if (select == APT::VersionSet::CANDINST)
+ return APT::CacheSetHelper::canNotFindCandInstVer(Cache, Pkg);
+ return APT::CacheSetHelper::canNotFindInstCandVer(Cache, Pkg);
+ }
+
+ pkgCache::PkgIterator Prov;
+ bool found_one = false;
+ for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; ++P) {
+ pkgCache::VerIterator const PVer = P.OwnerVer();
+ pkgCache::PkgIterator const PPkg = PVer.ParentPkg();
+
+ /* Ignore versions that are not a candidate. */
+ if (Cache[PPkg].CandidateVer != PVer)
+ continue;
+
+ if (found_one == false) {
+ Prov = PPkg;
+ found_one = true;
+ } else if (PPkg != Prov) {
+ found_one = false; // we found at least two
+ break;
+ }
+ }
+
+ if (found_one == true) {
+ ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"),
+ Prov.FullName(true).c_str(), Pkg.FullName(true).c_str());
+ return APT::VersionSet::FromPackage(Cache, Prov, select, *this);
+ }
+ if (select == APT::VersionSet::CANDINST)
+ return APT::CacheSetHelper::canNotFindCandInstVer(Cache, Pkg);
+ return APT::CacheSetHelper::canNotFindInstCandVer(Cache, Pkg);
+ }
+
+ inline bool allPkgNamedExplicitly() const { return explicitlyNamed; }
- regfree(&Pattern);
- return res;
-}
+};
/*}}}*/
// DoInstall - Install packages from the command line /*{{{*/
// ---------------------------------------------------------------------
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;
+ }
+
+ std::list<APT::VersionSet::Modifier> mods;
+ mods.push_back(APT::VersionSet::Modifier(MOD_INSTALL, "+",
+ APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDINST));
+ mods.push_back(APT::VersionSet::Modifier(MOD_REMOVE, "-",
+ APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::INSTCAND));
+ 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;
+
+ 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;
}
+
// new scope for the ActionGroup
{
pkgDepCache::ActionGroup group(Cache);
- for (const char **I = CmdL.FileList + 1; *I != 0; I++)
+ for (unsigned short i = 0; order[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;
- }
-
- while (Cache->FindPkg(S).end() == true)
- {
- // Handle an optional end tag indicating what to do
- if (Length >= 1 && S[Length - 1] == '-')
+ if (order[i] == MOD_INSTALL)
+ for (APT::VersionSet::const_iterator Ver = verset[MOD_INSTALL].begin();
+ Ver != verset[MOD_INSTALL].end(); ++Ver)
{
- 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)
- {
- // Check if the name is a regex
- const char *I;
- for (I = S; *I != 0; I++)
- if (*I == '?' || *I == '*' || *I == '|' ||
- *I == '[' || *I == '^' || *I == '$')
- break;
- if (*I == 0)
- return _error->Error(_("Couldn't find package %s"),S);
+ pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+ Cache->SetCandidateVersion(Ver);
- // Regexs must always be confirmed
- ExpectedInst += 1000;
-
- // Compile the regex pattern
- regex_t Pattern;
- int Res;
- if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE |
- REG_NOSUB)) != 0)
- {
- char Error[300];
- regerror(Res,&Pattern,Error,sizeof(Error));
- return _error->Error(_("Regex compilation error - %s"),Error);
+ if (TryToInstall(Pkg, Cache, Fix, false, BrokenFix) == false)
+ return false;
+
+ // see if we need to fix the auto-mark flag
+ // e.g. apt-get install foo
+ // where foo is marked automatic
+ if (Cache[Pkg].Install() == false &&
+ (Cache[Pkg].Flags & pkgCache::Flag::Auto) &&
+ _config->FindB("APT::Get::ReInstall",false) == false &&
+ _config->FindB("APT::Get::Only-Upgrade",false) == false &&
+ _config->FindB("APT::Get::Download-Only",false) == false)
+ {
+ ioprintf(c1out,_("%s set to manually installed.\n"),
+ Pkg.FullName(true).c_str());
+ Cache->MarkAuto(Pkg,false);
+ AutoMarkChanged++;
+ }
}
-
- // Run over the matches
- bool Hit = false;
- for (pkgCache::GrpIterator Grp = Cache->GrpBegin(); Grp.end() == false; ++Grp)
+ else if (order[i] == MOD_REMOVE)
+ for (APT::VersionSet::const_iterator Ver = verset[MOD_REMOVE].begin();
+ Ver != verset[MOD_REMOVE].end(); ++Ver)
{
- if (regexec(&Pattern,Grp.Name(),0,0,0) != 0)
- continue;
- Pkg = Grp.FindPkg("native");
- if (unlikely(Pkg.end() == true))
- continue;
+ pkgCache::PkgIterator Pkg = Ver.ParentPkg();
- ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"),
- Pkg.Name(),S);
-
- if (VerTag != 0)
- if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
- return false;
-
- Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,
- ExpectedInst,false);
- }
- regfree(&Pattern);
-
- if (Hit == false)
- return _error->Error(_("Couldn't find package %s"),S);
- }
- else
- {
- if (VerTag != 0)
- if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
+ if (TryToInstall(Pkg, Cache, Fix, true, BrokenFix) == 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++;
}
- }
}
+ 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 */
/* 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;
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);
}
// Display statistics
- double FetchBytes = Fetcher.FetchNeeded();
- double FetchPBytes = Fetcher.PartialPresent();
- double DebBytes = Fetcher.TotalNeeded();
+ unsigned long long FetchBytes = Fetcher.FetchNeeded();
+ unsigned long long FetchPBytes = Fetcher.PartialPresent();
+ unsigned long long DebBytes = Fetcher.TotalNeeded();
// Check for enough free space
struct statvfs Buf;
}
// 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
*/
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
{
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;
}
// 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
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;
}
/*}}}*/