#include <errno.h>
#include <regex.h>
#include <sys/wait.h>
+#include <sstream>
/*}}}*/
using namespace std;
cerr << _("Unable to correct missing packages.") << endl;
return _error->Error(_("Aborting install."));
}
-
+
_system->UnLock();
int status_fd = _config->FindI("APT::Status-Fd",-1);
pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd);
return true;
}
/*}}}*/
+// DoAutomaticRemove - Remove all automatic unused packages /*{{{*/
+// ---------------------------------------------------------------------
+/* Remove unused automatic packages */
+bool DoAutomaticRemove(CacheFile &Cache)
+{
+ bool Debug = _config->FindI("Debug::pkgAutoRemove",false);
+ bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false);
+ bool hideAutoRemove = _config->FindB("APT::Get::HideAutoRemove");
+ pkgDepCache::ActionGroup group(*Cache);
+
+ if(Debug)
+ std::cout << "DoAutomaticRemove()" << std::endl;
+
+ if (_config->FindB("APT::Get::Remove",true) == false &&
+ doAutoRemove == true)
+ {
+ c1out << _("We are not supposed to delete stuff, can't start "
+ "AutoRemover") << std::endl;
+ doAutoRemove = false;
+ }
+
+ string autoremovelist, autoremoveversions;
+ // look over the cache to see what can be removed
+ for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++Pkg)
+ {
+ if (Cache[Pkg].Garbage)
+ {
+ if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install())
+ if(Debug)
+ std::cout << "We could delete %s" << Pkg.Name() << std::endl;
+
+ // only show stuff in the list that is not yet marked for removal
+ if(Cache[Pkg].Delete() == false)
+ {
+ autoremovelist += string(Pkg.Name()) + " ";
+ autoremoveversions += string(Cache[Pkg].CandVersion) + "\n";
+ }
+ if (doAutoRemove)
+ {
+ if(Pkg.CurrentVer() != 0 &&
+ Pkg->CurrentState != pkgCache::State::ConfigFiles)
+ Cache->MarkDelete(Pkg, _config->FindB("APT::Get::Purge", false));
+ else
+ Cache->MarkKeep(Pkg, false, false);
+ }
+ }
+ }
+ if (!hideAutoRemove)
+ ShowList(c1out, _("The following packages were automatically installed and are no longer required:"), autoremovelist, autoremoveversions);
+ if (!doAutoRemove && !hideAutoRemove && autoremovelist.size() > 0)
+ c1out << _("Use 'apt-get autoremove' to remove them.") << std::endl;
+
+ // Now see if we destroyed anything
+ if (Cache->BrokenCount() != 0)
+ {
+ c1out << _("Hmm, seems like the AutoRemover destroyed something which really\n"
+ "shouldn't happen. Please file a bug report against apt.") << endl;
+ c1out << endl;
+ c1out << _("The following information may help to resolve the situation:") << endl;
+ c1out << endl;
+ ShowBroken(c1out,Cache,false);
+
+ return _error->Error(_("Internal Error, AutoRemover broke stuff"));
+ }
+ return true;
+}
+
// DoUpgrade - Upgrade all packages /*{{{*/
// ---------------------------------------------------------------------
/* Upgrade all packages without installing new packages or erasing old
if (Cache->BrokenCount() != 0)
BrokenFix = true;
+ unsigned int AutoMarkChanged = 0;
unsigned int ExpectedInst = 0;
unsigned int Packages = 0;
pkgProblemResolver Fix(Cache);
bool DefRemove = false;
if (strcasecmp(CmdL.FileList[0],"remove") == 0)
DefRemove = true;
+ else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0)
+ {
+ _config->Set("APT::Get::AutomaticRemove", "true");
+ DefRemove = true;
+ }
- for (const char **I = CmdL.FileList + 1; *I != 0; I++)
+ // new scope for the ActionGroup
{
- // 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;
- while (Cache->FindPkg(S).end() == true)
+ pkgDepCache::ActionGroup group(Cache);
+ for (const char **I = CmdL.FileList + 1; *I != 0; I++)
{
- // Handle an optional end tag indicating what to do
- if (Length >= 1 && S[Length - 1] == '-')
- {
- Remove = true;
- S[--Length] = 0;
+ // Duplicate the string
+ unsigned int Length = strlen(*I);
+ char S[300];
+ if (Length >= sizeof(S))
continue;
- }
-
- if (Length >= 1 && S[Length - 1] == '+')
+ strcpy(S,*I);
+
+ // See if we are removing and special indicators..
+ bool Remove = DefRemove;
+ char *VerTag = 0;
+ bool VerIsRel = false;
+ while (Cache->FindPkg(S).end() == true)
{
- Remove = false;
- S[--Length] = 0;
- continue;
- }
+ // Handle an optional end tag indicating what to do
+ if (Length >= 1 && S[Length - 1] == '-')
+ {
+ Remove = true;
+ S[--Length] = 0;
+ continue;
+ }
- char *Slash = strchr(S,'=');
- if (Slash != 0)
- {
- VerIsRel = false;
- *Slash = 0;
- VerTag = Slash + 1;
- }
+ if (Length >= 1 && S[Length - 1] == '+')
+ {
+ Remove = false;
+ S[--Length] = 0;
+ continue;
+ }
- Slash = strchr(S,'/');
- if (Slash != 0)
- {
- VerIsRel = true;
- *Slash = 0;
- VerTag = Slash + 1;
- }
+ char *Slash = strchr(S,'=');
+ if (Slash != 0)
+ {
+ VerIsRel = false;
+ *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);
-
- // Regexs must always be confirmed
- ExpectedInst += 1000;
+ Slash = strchr(S,'/');
+ if (Slash != 0)
+ {
+ VerIsRel = true;
+ *Slash = 0;
+ VerTag = Slash + 1;
+ }
- // 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);
+ break;
}
-
- // Run over the matches
- bool Hit = false;
- for (Pkg = Cache->PkgBegin(); Pkg.end() == false; Pkg++)
+
+ // Locate the package
+ pkgCache::PkgIterator Pkg = Cache->FindPkg(S);
+ Packages++;
+ if (Pkg.end() == true)
{
- if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0)
- continue;
+ // 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);
+
+ // 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);
+ }
+
+ // Run over the matches
+ bool Hit = false;
+ for (Pkg = Cache->PkgBegin(); Pkg.end() == false; Pkg++)
+ {
+ if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0)
+ continue;
+
+ ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"),
+ Pkg.Name(),S);
- 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)
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,Remove,BrokenFix,ExpectedInst) == false)
return false;
- if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == false)
- 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 */
- if (BrokenFix == true && Cache->BrokenCount() != 0)
- {
- c1out << _("You might want to run `apt-get -f install' to correct these:") << endl;
- ShowBroken(c1out,Cache,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))
+ {
+ ioprintf(c1out,_("%s set to manual installed.\n"),
+ Pkg.Name());
+ Cache->MarkAuto(Pkg,false);
+ AutoMarkChanged++;
+ }
+ }
+ }
- return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution)."));
- }
+ /* 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 */
+ if (BrokenFix == true && Cache->BrokenCount() != 0)
+ {
+ c1out << _("You might want to run `apt-get -f install' to correct these:") << endl;
+ ShowBroken(c1out,Cache,false);
+
+ return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution)."));
+ }
- // Call the scored problem resolver
- Fix.InstallProtect();
- if (Fix.Resolve(true) == false)
- _error->Discard();
+ // Call the scored problem resolver
+ Fix.InstallProtect();
+ if (Fix.Resolve(true) == false)
+ _error->Discard();
- // Now we check the state of the packages,
- if (Cache->BrokenCount() != 0)
- {
- c1out <<
- _("Some packages could not be installed. This may mean that you have\n"
- "requested an impossible situation or if you are using the unstable\n"
- "distribution that some required packages have not yet been created\n"
- "or been moved out of Incoming.") << endl;
- if (Packages == 1)
+ // Now we check the state of the packages,
+ if (Cache->BrokenCount() != 0)
{
- c1out << endl;
c1out <<
- _("Since you only requested a single operation it is extremely likely that\n"
- "the package is simply not installable and a bug report against\n"
- "that package should be filed.") << endl;
- }
+ _("Some packages could not be installed. This may mean that you have\n"
+ "requested an impossible situation or if you are using the unstable\n"
+ "distribution that some required packages have not yet been created\n"
+ "or been moved out of Incoming.") << endl;
+ if (Packages == 1)
+ {
+ c1out << endl;
+ c1out <<
+ _("Since you only requested a single operation it is extremely likely that\n"
+ "the package is simply not installable and a bug report against\n"
+ "that package should be filed.") << endl;
+ }
+
+ c1out << _("The following information may help to resolve the situation:") << endl;
+ c1out << endl;
+ ShowBroken(c1out,Cache,false);
+ return _error->Error(_("Broken packages"));
+ }
+ }
+ if (!DoAutomaticRemove(Cache))
+ return false;
- c1out << _("The following information may help to resolve the situation:") << endl;
- c1out << endl;
- ShowBroken(c1out,Cache,false);
- return _error->Error(_("Broken packages"));
- }
-
/* Print out a list of packages that are going to be installed extra
to what the user asked */
if (Cache->InstCount() != ExpectedInst)
if (*J == 0) {
List += string(I.Name()) + " ";
- VersionsList += string(Cache[I].CandVersion) + "\n";
- }
+ VersionsList += string(Cache[I].CandVersion) + "\n";
+ }
}
ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList);
string SuggestsVersions, RecommendsVersions;
for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
{
- pkgCache::PkgIterator I(Cache,Cache.List[J]);
+ pkgCache::PkgIterator Pkg(Cache,Cache.List[J]);
/* Just look at the ones we want to install */
- if ((*Cache)[I].Install() == false)
+ if ((*Cache)[Pkg].Install() == false)
continue;
- for (pkgCache::VerIterator V = I.VersionList(); V.end() == false; V++)
- {
- for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; )
- {
- pkgCache::DepIterator Start;
- pkgCache::DepIterator End;
- D.GlobOr(Start,End); // advances D
-
- /*
- * If this is a virtual package, we need to check the list of
- * packages that provide it and see if any of those are
- * installed
- */
-
- bool providedBySomething = false;
- for (pkgCache::PrvIterator Prv = Start.TargetPkg().ProvidesList();
- Prv.end() != true;
- Prv++)
- if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
- {
- providedBySomething = true;
- break;
- }
-
- if (providedBySomething) continue;
-
- for(;;)
- {
- /* Skip if package is installed already, or is about to be */
- string target = string(Start.TargetPkg().Name()) + " ";
-
- if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install
- || Cache[Start.TargetPkg()].Install())
- break;
-
- /* Skip if we already saw it */
- if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1)
- break;
-
- if (Start->Type == pkgCache::Dep::Suggests) {
- SuggestsList += target;
- SuggestsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
- }
-
- if (Start->Type == pkgCache::Dep::Recommends) {
- RecommendsList += target;
- RecommendsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
- }
-
- if (Start >= End)
- break;
- Start++;
- }
- }
- }
+ // get the recommends/suggests for the candidate ver
+ pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
+ for (pkgCache::DepIterator D = CV.DependsList(); D.end() == false; )
+ {
+ pkgCache::DepIterator Start;
+ pkgCache::DepIterator End;
+ D.GlobOr(Start,End); // advances D
+
+ // FIXME: we really should display a or-group as a or-group to the user
+ // the problem is that ShowList is incapable of doing this
+ string RecommendsOrList,RecommendsOrVersions;
+ string SuggestsOrList,SuggestsOrVersions;
+ bool foundInstalledInOrGroup = false;
+ for(;;)
+ {
+ /* Skip if package is installed already, or is about to be */
+ string target = string(Start.TargetPkg().Name()) + " ";
+
+ if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install
+ || Cache[Start.TargetPkg()].Install())
+ {
+ foundInstalledInOrGroup=true;
+ break;
+ }
+
+ /* Skip if we already saw it */
+ if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1)
+ {
+ foundInstalledInOrGroup=true;
+ break;
+ }
+
+ // this is a dep on a virtual pkg, check if any package that provides it
+ // should be installed
+ if(Start.TargetPkg().ProvidesList() != 0)
+ {
+ pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList();
+ for (; I.end() == false; I++)
+ {
+ pkgCache::PkgIterator Pkg = I.OwnerPkg();
+ if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() &&
+ Pkg.CurrentVer() != 0)
+ foundInstalledInOrGroup=true;
+ }
+ }
+
+ if (Start->Type == pkgCache::Dep::Suggests)
+ {
+ SuggestsOrList += target;
+ SuggestsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
+ }
+
+ if (Start->Type == pkgCache::Dep::Recommends)
+ {
+ RecommendsOrList += target;
+ RecommendsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
+ }
+
+ if (Start >= End)
+ break;
+ Start++;
+ }
+
+ if(foundInstalledInOrGroup == false)
+ {
+ RecommendsList += RecommendsOrList;
+ RecommendsVersions += RecommendsOrVersions;
+ SuggestsList += SuggestsOrList;
+ SuggestsVersions += SuggestsOrVersions;
+ }
+
+ }
}
+
ShowList(c1out,_("Suggested packages:"),SuggestsList,SuggestsVersions);
ShowList(c1out,_("Recommended packages:"),RecommendsList,RecommendsVersions);
}
+ // 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 &&
+ Cache->DelCount() == 0 && Cache->InstCount() == 0 &&
+ Cache->BadCount() == 0)
+ Cache->writeStateFile(NULL);
+
// See if we need to prompt
if (Cache->InstCount() == ExpectedInst && Cache->DelCount() == 0)
return InstallPackages(Cache,false,false);
if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
return false;
+ pkgDepCache::ActionGroup group(Cache);
+
// Install everything with the install flag set
pkgCache::PkgIterator I = Cache->PkgBegin();
for (;I.end() != true; I++)
{0,"remove","APT::Get::Remove",0},
{0,"only-source","APT::Get::Only-Source",0},
{0,"arch-only","APT::Get::Arch-Only",0},
+ {0,"auto-remove","APT::Get::AutomaticRemove",0},
{0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0},
{'c',"config-file",0,CommandLine::ConfigFile},
{'o',"option",0,CommandLine::ArbItem},
{"upgrade",&DoUpgrade},
{"install",&DoInstall},
{"remove",&DoInstall},
+ {"autoremove",&DoInstall},
{"dist-upgrade",&DoDistUpgrade},
{"dselect-upgrade",&DoDSelectUpgrade},
{"build-dep",&DoBuildDep},