##################################################################### */
/*}}}*/
// Include Files /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/algorithms.h"
-#endif
#include <apt-pkg/algorithms.h>
#include <apt-pkg/error.h>
#include <apt-pkg/configuration.h>
-#include <apt-pkg/pkgsystem.h>
#include <apt-pkg/version.h>
#include <apt-pkg/sptr.h>
#include <apti18n.h>
#include <sys/types.h>
-#include <regex.h>
+#include <cstdlib>
+#include <algorithm>
#include <iostream>
/*}}}*/
using namespace std;
DepIterator End;
D.GlobOr(Start,End);
if (Start->Type == pkgCache::Dep::Conflicts ||
+ Start->Type == pkgCache::Dep::DpkgBreaks ||
Start->Type == pkgCache::Dep::Obsoletes ||
End->Type == pkgCache::Dep::PreDepends)
{
cout << " Obsoletes:" << D.TargetPkg().Name();
else if (D->Type == pkgCache::Dep::Conflicts)
cout << " Conflicts:" << D.TargetPkg().Name();
+ else if (D->Type == pkgCache::Dep::DpkgBreaks)
+ cout << " Breaks:" << D.TargetPkg().Name();
else
cout << " Depends:" << D.TargetPkg().Name();
}
the necessary calculations to deal with the problems. */
bool pkgApplyStatus(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
if (I->VersionList == 0)
I->InstState == pkgCache::State::HoldReInstReq)
{
if (I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true)
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
else
{
// Is this right? Will dpkg choke on an upgrade?
if (Cache[I].CandidateVer != 0 &&
Cache[I].CandidateVerIter(Cache).Downloadable() == true)
- Cache.MarkInstall(I);
+ Cache.MarkInstall(I, false, 0, false);
else
return _error->Error(_("The package %s needs to be reinstalled, "
"but I can't find an archive for it."),I.Name());
re-unpacked (probably) */
case pkgCache::State::UnPacked:
case pkgCache::State::HalfConfigured:
+ case pkgCache::State::TriggersAwaited:
+ case pkgCache::State::TriggersPending:
if ((I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true) ||
I.State() != pkgCache::PkgIterator::NeedsUnpack)
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
else
{
if (Cache[I].CandidateVer != 0 &&
Cache[I].CandidateVerIter(Cache).Downloadable() == true)
- Cache.MarkInstall(I);
+ Cache.MarkInstall(I, true, 0, false);
else
Cache.MarkDelete(I);
}
on the result. */
bool pkgFixBroken(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
// Auto upgrade all broken packages
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if (Cache[I].NowBroken() == true)
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
/* Fix packages that are in a NeedArchive state but don't have a
downloadable install version */
if (Cache[I].InstVerIter(Cache).Downloadable() == false)
continue;
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
}
pkgProblemResolver Fix(&Cache);
*/
bool pkgDistUpgrade(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
/* Auto upgrade all installed packages, this provides the basis
for the installation */
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if (I->CurrentVer != 0)
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
/* Now, auto upgrade all essential packages - this ensures that
the essential packages are present and working */
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
- Cache.MarkInstall(I,true);
+ Cache.MarkInstall(I, true, 0, false);
/* We do it again over all previously installed packages to force
conflict resolution on them all. */
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
if (I->CurrentVer != 0)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
pkgProblemResolver Fix(&Cache);
if (I->SelectedState == pkgCache::State::Hold)
{
Fix.Protect(I);
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
}
}
}
to install packages not marked for install */
bool pkgAllUpgrade(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
pkgProblemResolver Fix(&Cache);
if (Cache.BrokenCount() != 0)
continue;
if (I->CurrentVer != 0 && Cache[I].InstallVer != 0)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
}
return Fix.ResolveByKeep();
the package is restored. */
bool pkgMinimizeUpgrade(pkgDepCache &Cache)
{
+ pkgDepCache::ActionGroup group(Cache);
+
if (Cache.BrokenCount() != 0)
return false;
continue;
// Keep it and see if that is OK
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
if (Cache.BrokenCount() != 0)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
else
{
// If keep didnt actually do anything then there was no change..
Score += PrioMap[Cache[I].InstVerIter(Cache)->Priority];
/* This helps to fix oddball problems with conflicting packages
- on the same level. We enhance the score of installed packages */
- if (I->CurrentVer != 0)
+ on the same level. We enhance the score of installed packages
+ if those are not obsolete
+ */
+ if (I->CurrentVer != 0 && Cache[I].CandidateVer != 0 && Cache[I].CandidateVerIter(Cache).Downloadable())
Score += 1;
}
installable */
bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
{
+ pkgDepCache::ActionGroup group(Cache);
+
if ((Flags[Pkg->ID] & Upgradable) == 0 || Cache[Pkg].Upgradable() == false)
return false;
if ((Flags[Pkg->ID] & Protected) == Protected)
Flags[Pkg->ID] &= ~Upgradable;
bool WasKept = Cache[Pkg].Keep();
- Cache.MarkInstall(Pkg,false);
+ Cache.MarkInstall(Pkg, false, 0, false);
// This must be a virtual package or something like that.
if (Cache[Pkg].InstVerIter(Cache).end() == true)
/* We let the algorithm deal with conflicts on its next iteration,
it is much smarter than us */
if (Start->Type == pkgCache::Dep::Conflicts ||
+ Start->Type == pkgCache::Dep::DpkgBreaks ||
Start->Type == pkgCache::Dep::Obsoletes)
break;
if (Fail == true)
{
if (WasKept == true)
- Cache.MarkKeep(Pkg);
+ Cache.MarkKeep(Pkg, false, false);
else
Cache.MarkDelete(Pkg);
return false;
upgrade packages to advoid problems. */
bool pkgProblemResolver::Resolve(bool BrokenFix)
{
+ pkgDepCache::ActionGroup group(Cache);
+
unsigned long Size = Cache.Head().PackageCount;
// Record which packages are marked for install
{
if (Cache[I].InstBroken() == true && BrokenFix == true)
{
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Cache[I].Install() == true)
Again = true;
}
pkgCache::Version *OldVer = Cache[I].InstallVer;
Flags[I->ID] &= ReInstateTried;
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Cache[I].InstBroken() == true ||
OldBreaks < Cache.BrokenCount())
{
if (OldVer == 0)
Cache.MarkDelete(I);
else
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
}
else
if (Debug == true)
continue;
if (Debug == true)
- cout << "Investigating " << I.Name() << endl;
+ clog << "Investigating " << I.Name() << endl;
// Isolate the problem dependency
PackageKill KillList[100];
{
if (Debug == true)
clog << " Or group keep for " << I.Name() << endl;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
Change = true;
}
}
OldEnd = LEnd;
}
else
+ {
Start++;
+ // We only worry about critical deps.
+ if (Start.IsCritical() != true)
+ continue;
+ }
// Dep is ok
if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
if (*VList == 0 && (Flags[I->ID] & Protected) != Protected &&
Start->Type != pkgCache::Dep::Conflicts &&
+ Start->Type != pkgCache::Dep::DpkgBreaks &&
Start->Type != pkgCache::Dep::Obsoletes &&
Cache[I].NowBroken() == false)
{
}
Change = true;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
break;
}
if (Scores[I->ID] <= Scores[Pkg->ID] ||
((Cache[Start] & pkgDepCache::DepNow) == 0 &&
End->Type != pkgCache::Dep::Conflicts &&
+ End->Type != pkgCache::Dep::DpkgBreaks &&
End->Type != pkgCache::Dep::Obsoletes))
{
// Try a little harder to fix protected packages..
/* See if a keep will do, unless the package is protected,
then installing it will be necessary */
bool Installed = Cache[I].Install();
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
if (Cache[I].InstBroken() == false)
{
// Unwind operation will be keep now
// Restore
if (InOr == true && Installed == true)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Debug == true)
clog << " Holding Back " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
(Start->Type == pkgCache::Dep::Conflicts ||
Start->Type == pkgCache::Dep::Obsoletes))
continue;
-
+
+ if (Start->Type == pkgCache::Dep::DpkgBreaks)
+ {
+ /* Would it help if we upgraded? */
+ if (Cache[End] & pkgDepCache::DepGCVer) {
+ if (Debug)
+ clog << " Upgrading " << Pkg.Name() << " due to Breaks field in " << I.Name() << endl;
+ Cache.MarkInstall(Pkg, false, 0, false);
+ continue;
+ }
+ if (Debug)
+ clog << " Will not break " << Pkg.Name() << " as stated in Breaks field in " << I.Name() <<endl;
+ Cache.MarkKeep(I, false, false);
+ continue;
+ }
+
// Skip adding to the kill list if it is protected
if ((Flags[Pkg->ID] & Protected) != 0)
continue;
// Hm, nothing can possibly satisify this dep. Nuke it.
if (VList[0] == 0 &&
Start->Type != pkgCache::Dep::Conflicts &&
+ Start->Type != pkgCache::Dep::DpkgBreaks &&
Start->Type != pkgCache::Dep::Obsoletes &&
(Flags[I->ID] & Protected) != Protected)
{
// Restore
if (InOr == true && Installed == true)
- Cache.MarkInstall(I,false);
+ Cache.MarkInstall(I, false, 0, false);
if (Debug == true)
clog << " Holding Back " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
{
if (Debug == true)
clog << " Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
- Cache.MarkKeep(J->Pkg);
+ Cache.MarkKeep(J->Pkg, false, false);
}
if (Counter > 1)
system was non-broken previously. */
bool pkgProblemResolver::ResolveByKeep()
{
+ pkgDepCache::ActionGroup group(Cache);
+
unsigned long Size = Cache.Head().PackageCount;
if (Debug == true)
{
if (Debug == true)
clog << "Keeping package " << I.Name() << endl;
- Cache.MarkKeep(I);
+ Cache.MarkKeep(I, false, false);
if (Cache[I].InstBroken() == false)
{
K = PList - 1;
{
if (Debug == true)
clog << " Keeping Package " << Pkg.Name() << " due to dep" << endl;
- Cache.MarkKeep(Pkg);
+ Cache.MarkKeep(Pkg, false, false);
}
if (Cache[I].InstBroken() == false)
/* This is used to make sure protected packages are installed */
void pkgProblemResolver::InstallProtect()
{
+ pkgDepCache::ActionGroup group(Cache);
+
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
if ((Flags[I->ID] & Protected) == Protected)
{
if ((Flags[I->ID] & ToRemove) == ToRemove)
Cache.MarkDelete(I);
- else
- Cache.MarkInstall(I,false);
+ else
+ {
+ // preserver the information if the package was auto
+ // or manual installed
+ bool autoInst = (Cache[I].Flags & pkgCache::Flag::Auto);
+ Cache.MarkInstall(I, false, 0, !autoInst);
+ }
}
}
}
}
/*}}}*/
-
-// mark a single package in Mark-and-Sweep
-void pkgMarkPackage(pkgDepCache &Cache,
- const pkgCache::PkgIterator &pkg,
- const pkgCache::VerIterator &ver,
- bool follow_recommends,
- bool follow_suggests)
-{
- pkgDepCache::StateCache &state=Cache[pkg];
- pkgCache::VerIterator candver=state.CandidateVerIter(Cache);
- pkgCache::VerIterator instver=state.InstVerIter(Cache);
-
-#if 0
- // If a package was garbage-collected but is now being marked, we
- // should re-select it
- // For cases when a pkg is set to upgrade and this trigger the
- // removal of a no-longer used dependency. if the pkg is set to
- // keep again later it will result in broken deps
- if(state.Delete() && state.RemoveReason=pkgDepCache::Unused)
- {
- if(ver==candver)
- mark_install(pkg, false, false, NULL);
- else if(ver==pkg.CurrentVer())
- MarkKeep(pkg);
-
- instver=state.InstVerIter(*this);
- }
-#endif
-
- // Ignore versions other than the InstVer, and ignore packages
- // that are already going to be removed or just left uninstalled.
- if(!(ver==instver && !instver.end()))
- return;
-
- // if we are marked already we are done
- if(state.Marked)
- return;
-
- //std::cout << "Setting Marked for: " << pkg.Name() << std::endl;
- state.Marked=true;
-
- if(!ver.end())
- {
- for(pkgCache::DepIterator d=ver.DependsList(); !d.end(); ++d)
- {
- if(d->Type==pkgCache::Dep::Depends ||
- d->Type==pkgCache::Dep::PreDepends ||
- (follow_recommends &&
- d->Type==pkgCache::Dep::Recommends) ||
- (follow_suggests &&
- d->Type==pkgCache::Dep::Suggests))
- {
- // Try all versions of this package.
- for(pkgCache::VerIterator V=d.TargetPkg().VersionList();
- !V.end(); ++V)
- {
- if(_system->VS->CheckDep(V.VerStr(),d->CompareOp, d.TargetVer()))
- {
- pkgMarkPackage(Cache, V.ParentPkg(), V,
- follow_recommends, follow_suggests);
- }
- }
- // Now try virtual packages
- for(pkgCache::PrvIterator prv=d.TargetPkg().ProvidesList();
- !prv.end(); ++prv)
- {
- if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp,
- d.TargetVer()))
- {
- pkgMarkPackage(Cache, prv.OwnerPkg(), prv.OwnerVer(),
- follow_recommends, follow_suggests);
- }
- }
- }
- }
- }
-}
-
-
-// Helper for APT::NeverAutoRemove, always include the packages matching
-// this regexp into the root-set
-inline bool
-pkgMarkAlwaysInclude(pkgCache::PkgIterator p, vector<regex_t*> alwaysMark)
-{
- for(unsigned int i=0;i<alwaysMark.size();i++)
- if (regexec(alwaysMark[i],p.Name(),0,0,0) == 0)
- return true;
-
- return false;
-}
-
-// the main mark algorithm
-bool pkgMarkUsed(pkgDepCache &Cache, InRootSetFunc func)
-{
- bool follow_recommends;
- bool follow_suggests;
-
- // init the states
- for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
- {
- Cache[p].Marked=false;
- Cache[p].Garbage=false;
- }
-
- // init vars
- follow_recommends=_config->FindB("APT::AutoRemove::RecommendsImportant",false);
- follow_suggests=_config->FindB("APT::AutoRemove::SuggestsImportant", false);
-
-
- // init the "NeverAutoRemove" variable
- vector<regex_t *> neverAutoRemoveRegexp;
- Configuration::Item const *Opts;
- Opts = _config->Tree("APT::NeverAutoRemove");
- if (Opts != 0 && Opts->Child != 0)
- {
- Opts = Opts->Child;
- for (; Opts != 0; Opts = Opts->Next)
- {
- if (Opts->Value.empty() == true)
- continue;
-
- regex_t *p = new regex_t;
- if(regcomp(p,Opts->Value.c_str(),
- REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
- {
- regfree(p);
- for(unsigned int i=0;i<neverAutoRemoveRegexp.size();i++)
- regfree(neverAutoRemoveRegexp[i]);
- return _error->Error("Regex compilation error for APT::NeverAutoRemove");
- }
- neverAutoRemoveRegexp.push_back(p);
- }
- }
-
-
- // do the mark part
- for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
- {
- if( (func != NULL ? (*func)(p) : false) ||
- pkgMarkAlwaysInclude(p, neverAutoRemoveRegexp) ||
- !(Cache[p].Flags & pkgCache::Flag::Auto) ||
- (p->Flags & pkgCache::Flag::Essential))
-
- {
- if(Cache[p].Keep() && !p.CurrentVer().end())
- pkgMarkPackage(Cache, p, p.CurrentVer(),
- follow_recommends, follow_suggests);
- else if(Cache[p].Install())
- pkgMarkPackage(Cache, p, Cache[p].InstVerIter(Cache),
- follow_recommends, follow_suggests);
- }
- }
-
-
- // do the sweep
- for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
- {
- pkgDepCache::StateCache &state=Cache[p];
-
- if(!state.Marked)
- {
- // mark installed but not yet marked stuff as garbage
- if(p->CurrentVer != 0) {
- state.Garbage=true;
- std::cout << "Garbage: " << p.Name() << std::endl;
- }
-
-#if 0 // mvo: the below bits still needs to be ported
-
- // Be sure not to re-delete already deleted packages.
- if(delete_unused && (!p.CurrentVer().end() || state.Install()) &&
- !state.Delete())
- {
- bool do_delete=true;
-
- // If the package is being upgraded, check if we're
- // losing a versioned dep. If the dependency matches
- // the previous version and not the new version, keep
- // the package back instead of removing it.
- if(!p.CurrentVer().end() && state.Install())
- {
- const char *vs=p.CurrentVer().VerStr();
-
- // Check direct revdeps only. THIS ASSUMES NO
- // VERSIONED PROVIDES, but Debian probably won't
- // have them for ages if ever.
- for(pkgCache::DepIterator revdep=p.RevDependsList();
- !revdep.end(); ++revdep)
- {
- pkgCache::PkgIterator depender=revdep.ParentPkg();
- // Find which version of the depending package
- // will be installed.
- pkgCache::VerIterator instver=(*this)[depender].InstVerIter(*this);
-
- // Only pay attention to strong positive
- // dependencies whose parents will be installed.
- if(revdep.ParentVer()==instver &&
- (revdep->Type==pkgCache::Dep::Depends ||
- revdep->Type==pkgCache::Dep::PreDepends ||
- (revdep->Type==pkgCache::Dep::Recommends &&
- follow_recommends)))
- {
- // If the previous version matched, cancel the
- // deletion. (note that I assume that the new
- // version does NOT match; otherwise it would
- // not be unused!)
- if(_system->VS->CheckDep(vs,
- revdep->CompareOp,
- revdep.TargetVer()))
- {
- mark_keep(p, false, false, undo);
- do_delete=false;
- break;
- }
- }
- }
- }
-
- if(do_delete)
- mark_delete(p, false, true, undo);
- }
-#endif
- }
- }
-
- // cleanup
- for(unsigned int i=0;i<neverAutoRemoveRegexp.size();i++)
- regfree(neverAutoRemoveRegexp[i]);
-
-
- return true;
-}