#include <apt-pkg/sptr.h>
#include <apt-pkg/acquire-item.h>
#include <apt-pkg/edsp.h>
+#include <apt-pkg/sourcelist.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/progress.h>
#include <sys/types.h>
#include <cstdlib>
FileNames[I] = Jnk;
}
/*}}}*/
+// Simulate::~Simulate - Destructor /*{{{*/
+pkgSimulate::~pkgSimulate()
+{
+ delete[] Flags;
+}
+ /*}}}*/
// Simulate::Describe - Describe a package /*{{{*/
// ---------------------------------------------------------------------
/* Parameter Current == true displays the current package version,
{
// Adapt the iterator
PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
+ if (Pkg.end() == true)
+ {
+ std::cerr << (Purge ? "Purg" : "Remv") << " invalid package " << iPkg.FullName() << std::endl;
+ return false;
+ }
Flags[Pkg->ID] = 3;
Sim.MarkDelete(Pkg);
Cache[I].CandidateVerIter(Cache).Downloadable() == true)
Cache.MarkInstall(I, true, 0, false);
else
- Cache.MarkDelete(I);
+ Cache.MarkDelete(I, false, 0, false);
}
break;
// This means removal failed
case pkgCache::State::HalfInstalled:
- Cache.MarkDelete(I);
+ Cache.MarkDelete(I, false, 0, false);
break;
default:
return Fix.Resolve(true);
}
/*}}}*/
-// DistUpgrade - Distribution upgrade /*{{{*/
-// ---------------------------------------------------------------------
-/* This autoinstalls every package and then force installs every
- pre-existing package. This creates the initial set of conditions which
- most likely contain problems because too many things were installed.
-
- The problem resolver is used to resolve the problems.
- */
-bool pkgDistUpgrade(pkgDepCache &Cache)
-{
- std::string const solver = _config->Find("APT::Solver", "internal");
- if (solver != "internal") {
- OpTextProgress Prog(*_config);
- return EDSP::ResolveExternal(solver.c_str(), Cache, false, true, false, &Prog);
- }
-
- pkgDepCache::ActionGroup group(Cache);
-
- /* Upgrade all installed packages first without autoinst to help the resolver
- in versioned or-groups to upgrade the old solver instead of installing
- a new one (if the old solver is not the first one [anymore]) */
- for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
- if (I->CurrentVer != 0)
- Cache.MarkInstall(I, false, 0, false);
-
- /* 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, 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, 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, 0, false);
-
- pkgProblemResolver Fix(&Cache);
-
- // Hold back held packages.
- if (_config->FindB("APT::Ignore-Hold",false) == false)
- {
- for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
- {
- if (I->SelectedState == pkgCache::State::Hold)
- {
- Fix.Protect(I);
- Cache.MarkKeep(I, false, false);
- }
- }
- }
-
- return Fix.Resolve();
-}
- /*}}}*/
-// AllUpgrade - Upgrade as many packages as possible /*{{{*/
-// ---------------------------------------------------------------------
-/* Right now the system must be consistent before this can be called.
- It also will not change packages marked for install, it only tries
- to install packages not marked for install */
-bool pkgAllUpgrade(pkgDepCache &Cache)
-{
- std::string const solver = _config->Find("APT::Solver", "internal");
- if (solver != "internal") {
- OpTextProgress Prog(*_config);
- return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
- }
-
- pkgDepCache::ActionGroup group(Cache);
-
- pkgProblemResolver Fix(&Cache);
-
- if (Cache.BrokenCount() != 0)
- return false;
-
- // Upgrade all installed packages
- for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
- {
- if (Cache[I].Install() == true)
- Fix.Protect(I);
-
- if (_config->FindB("APT::Ignore-Hold",false) == false)
- if (I->SelectedState == pkgCache::State::Hold)
- continue;
-
- if (I->CurrentVer != 0 && Cache[I].InstallVer != 0)
- Cache.MarkInstall(I, false, 0, false);
- }
-
- return Fix.ResolveByKeep();
-}
- /*}}}*/
-// MinimizeUpgrade - Minimizes the set of packages to be upgraded /*{{{*/
-// ---------------------------------------------------------------------
-/* This simply goes over the entire set of packages and tries to keep
- each package marked for upgrade. If a conflict is generated then
- the package is restored. */
-bool pkgMinimizeUpgrade(pkgDepCache &Cache)
-{
- pkgDepCache::ActionGroup group(Cache);
-
- if (Cache.BrokenCount() != 0)
- return false;
-
- // We loop for 10 tries to get the minimal set size.
- bool Change = false;
- unsigned int Count = 0;
- do
- {
- Change = false;
- for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
- {
- // Not interesting
- if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
- continue;
-
- // Keep it and see if that is OK
- Cache.MarkKeep(I, false, false);
- if (Cache.BrokenCount() != 0)
- Cache.MarkInstall(I, false, 0, false);
- else
- {
- // If keep didnt actually do anything then there was no change..
- if (Cache[I].Upgrade() == false)
- Change = true;
- }
- }
- ++Count;
- }
- while (Change == true && Count < 10);
-
- if (Cache.BrokenCount() != 0)
- return _error->Error("Internal Error in pkgMinimizeUpgrade");
-
- return true;
-}
- /*}}}*/
// ProblemResolver::pkgProblemResolver - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
-pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : Cache(*pCache)
+pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : d(NULL), Cache(*pCache)
{
// Allocate memory
unsigned long Size = Cache.Head().PackageCount;
- Scores = new signed short[Size];
+ Scores = new int[Size];
Flags = new unsigned char[Size];
memset(Flags,0,sizeof(*Flags)*Size);
unsigned long Size = Cache.Head().PackageCount;
memset(Scores,0,sizeof(*Scores)*Size);
- // Important Required Standard Optional Extra
- signed short PrioMap[] = {
+ // maps to pkgCache::State::VerPriority:
+ // Required Important Standard Optional Extra
+ int PrioMap[] = {
0,
- (signed short) _config->FindI("pkgProblemResolver::Scores::Important",3),
- (signed short) _config->FindI("pkgProblemResolver::Scores::Required",2),
- (signed short) _config->FindI("pkgProblemResolver::Scores::Standard",1),
- (signed short) _config->FindI("pkgProblemResolver::Scores::Optional",-1),
- (signed short) _config->FindI("pkgProblemResolver::Scores::Extra",-2)
+ _config->FindI("pkgProblemResolver::Scores::Required",3),
+ _config->FindI("pkgProblemResolver::Scores::Important",2),
+ _config->FindI("pkgProblemResolver::Scores::Standard",1),
+ _config->FindI("pkgProblemResolver::Scores::Optional",-1),
+ _config->FindI("pkgProblemResolver::Scores::Extra",-2)
};
- signed short PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
- signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
- signed short PrioDepends = _config->FindI("pkgProblemResolver::Scores::Depends",1);
- signed short PrioRecommends = _config->FindI("pkgProblemResolver::Scores::Recommends",1);
- signed short AddProtected = _config->FindI("pkgProblemResolver::Scores::AddProtected",10000);
- signed short AddEssential = _config->FindI("pkgProblemResolver::Scores::AddEssential",5000);
+ int PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
+ int PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
+ int PrioDepends = _config->FindI("pkgProblemResolver::Scores::Depends",1);
+ int PrioRecommends = _config->FindI("pkgProblemResolver::Scores::Recommends",1);
+ int AddProtected = _config->FindI("pkgProblemResolver::Scores::AddProtected",10000);
+ int AddEssential = _config->FindI("pkgProblemResolver::Scores::AddEssential",5000);
if (_config->FindB("Debug::pkgProblemResolver::ShowScores",false) == true)
clog << "Settings used to calculate pkgProblemResolver::Scores::" << endl
- << " Important => " << PrioMap[1] << endl
- << " Required => " << PrioMap[2] << endl
- << " Standard => " << PrioMap[3] << endl
- << " Optional => " << PrioMap[4] << endl
- << " Extra => " << PrioMap[5] << endl
+ << " Required => " << PrioMap[pkgCache::State::Required] << endl
+ << " Important => " << PrioMap[pkgCache::State::Important] << endl
+ << " Standard => " << PrioMap[pkgCache::State::Standard] << endl
+ << " Optional => " << PrioMap[pkgCache::State::Optional] << endl
+ << " Extra => " << PrioMap[pkgCache::State::Extra] << endl
<< " Essentials => " << PrioEssentials << endl
<< " InstalledAndNotObsolete => " << PrioInstalledAndNotObsolete << endl
<< " Depends => " << PrioDepends << endl
if (Cache[I].InstallVer == 0)
continue;
- signed short &Score = Scores[I->ID];
+ int &Score = Scores[I->ID];
/* This is arbitrary, it should be high enough to elevate an
essantial package above most other packages but low enough
to allow an obsolete essential packages to be removed by
a conflicts on a powerfull normal package (ie libc6) */
- if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+ if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential
+ || (I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
Score += PrioEssentials;
// We transform the priority
}
// Copy the scores to advoid additive looping
- SPtrArray<signed short> OldScores = new signed short[Size];
+ SPtrArray<int> OldScores = new int[Size];
memcpy(OldScores,Scores,sizeof(*Scores)*Size);
/* Now we cause 1 level of dependency inheritance, that is we add the
D->Type != pkgCache::Dep::Recommends))
continue;
- Scores[I->ID] += abs(OldScores[D.ParentPkg()->ID]);
+ // Do not propagate negative scores otherwise
+ // an extra (-2) package might score better than an optional (-1)
+ if (OldScores[D.ParentPkg()->ID] > 0)
+ Scores[I->ID] += OldScores[D.ParentPkg()->ID];
}
}
{
if ((Flags[I->ID] & Protected) != 0)
Scores[I->ID] += AddProtected;
- if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+ if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential ||
+ (I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
Scores[I->ID] += AddEssential;
}
}
if (WasKept == true)
Cache.MarkKeep(Pkg, false, false);
else
- Cache.MarkDelete(Pkg);
+ Cache.MarkDelete(Pkg, false, 0, false);
return false;
}
}
while (Again == true);
- if (Debug == true)
- clog << "Starting" << endl;
+ if (Debug == true) {
+ clog << "Starting pkgProblemResolver with broken count: "
+ << Cache.BrokenCount() << endl;
+ }
MakeScores();
}
}
- if (Debug == true)
- clog << "Starting 2" << endl;
+ if (Debug == true) {
+ clog << "Starting 2 pkgProblemResolver with broken count: "
+ << Cache.BrokenCount() << endl;
+ }
/* Now consider all broken packages. For each broken package we either
remove the package or fix it's problem. We do this once, it should
OldBreaks < Cache.BrokenCount())
{
if (OldVer == 0)
- Cache.MarkDelete(I);
+ Cache.MarkDelete(I, false, 0, false);
else
Cache.MarkKeep(I, false, false);
}
{
if (Debug == true)
clog << " Or group remove for " << I.FullName(false) << endl;
- Cache.MarkDelete(I);
+ Cache.MarkDelete(I, false, 0, false);
Change = true;
}
}
if (BrokenFix == false || DoUpgrade(I) == false)
{
// Consider other options
- if (InOr == false)
+ if (InOr == false || Cache[I].Garbage == true)
{
if (Debug == true)
clog << " Removing " << I.FullName(false) << " rather than change " << Start.TargetPkg().FullName(false) << endl;
- Cache.MarkDelete(I);
+ Cache.MarkDelete(I, false, 0, false);
if (Counter > 1 && Scores[Pkg->ID] > Scores[I->ID])
Scores[I->ID] = Scores[Pkg->ID];
}
LEnd->Dep = End;
LEnd++;
- if (Start->Type != pkgCache::Dep::Conflicts &&
- Start->Type != pkgCache::Dep::Obsoletes)
+ if (Start.IsNegative() == false)
break;
}
}
if (Debug == true)
clog << " Removing " << I.FullName(false) << " because I can't find " << Start.TargetPkg().FullName(false) << endl;
if (InOr == false)
- Cache.MarkDelete(I);
+ Cache.MarkDelete(I, false, 0, false);
}
Change = true;
{
if (Debug == true)
clog << " Fixing " << I.FullName(false) << " via remove of " << J->Pkg.FullName(false) << endl;
- Cache.MarkDelete(J->Pkg);
+ Cache.MarkDelete(J->Pkg, false, 0, false);
}
}
else
return true;
}
/*}}}*/
-
// ProblemResolver::BreaksInstOrPolicy - Check if the given pkg is broken/*{{{*/
// ---------------------------------------------------------------------
/* This checks if the given package is broken either by a hard dependency
*/
bool pkgProblemResolver::InstOrNewPolicyBroken(pkgCache::PkgIterator I)
{
-
// a broken install is always a problem
if (Cache[I].InstBroken() == true)
+ {
+ if (Debug == true)
+ std::clog << " Dependencies are not satisfied for " << I << std::endl;
return true;
+ }
// a newly broken policy (recommends/suggests) is a problem
if (Cache[I].NowPolicyBroken() == false &&
Cache[I].InstPolicyBroken() == true)
+ {
+ if (Debug == true)
+ std::clog << " Policy breaks with upgrade of " << I << std::endl;
return true;
-
+ }
+
return false;
}
-
+ /*}}}*/
// ProblemResolver::ResolveByKeep - Resolve problems using keep /*{{{*/
// ---------------------------------------------------------------------
/* This is the work horse of the soft upgrade routine. It is very gental
continue;
// Restart again.
- if (K == LastStop)
- return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.FullName(false).c_str());
+ if (K == LastStop) {
+ // I is an iterator based off our temporary package list,
+ // so copy the name we need before deleting the temporary list
+ std::string const LoopingPackage = I.FullName(false);
+ delete[] PList;
+ return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.", LoopingPackage.c_str());
+ }
LastStop = K;
K = PList - 1;
- }
+ }
+ delete[] PList;
return true;
}
/*}}}*/
-// ProblemResolver::InstallProtect - Install all protected packages /*{{{*/
+// ProblemResolver::InstallProtect - deprecated cpu-eating no-op /*{{{*/
// ---------------------------------------------------------------------
-/* This is used to make sure protected packages are installed */
+/* Actions issued with FromUser bit set are protected from further
+ modification (expect by other calls with FromUser set) nowadays , so we
+ don't need to reissue actions here, they are already set in stone. */
void pkgProblemResolver::InstallProtect()
{
pkgDepCache::ActionGroup group(Cache);
if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
(R.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
return -1;
+
+ if ((L.ParentPkg()->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important &&
+ (R.ParentPkg()->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important)
+ return 1;
+ if ((L.ParentPkg()->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important &&
+ (R.ParentPkg()->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important)
+ return -1;
if (L->Priority != R->Priority)
return R->Priority - L->Priority;
qsort(List,Count,sizeof(*List),PrioComp);
}
/*}}}*/
-// CacheFile::ListUpdate - update the cache files /*{{{*/
-// ---------------------------------------------------------------------
-/* This is a simple wrapper to update the cache. it will fetch stuff
- * from the network (or any other sources defined in sources.list)
- */
-bool ListUpdate(pkgAcquireStatus &Stat,
- pkgSourceList &List,
- int PulseInterval)
-{
- pkgAcquire::RunResult res;
- pkgAcquire Fetcher;
- if (Fetcher.Setup(&Stat, _config->FindDir("Dir::State::Lists")) == false)
- return false;
-
- // Populate it with the source selection
- if (List.GetIndexes(&Fetcher) == false)
- return false;
-
- // Run scripts
- RunScripts("APT::Update::Pre-Invoke");
-
- // check arguments
- if(PulseInterval>0)
- res = Fetcher.Run(PulseInterval);
- else
- res = Fetcher.Run();
-
- if (res == pkgAcquire::Failed)
- return false;
-
- bool Failed = false;
- bool TransientNetworkFailure = false;
- for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin();
- I != Fetcher.ItemsEnd(); ++I)
- {
- if ((*I)->Status == pkgAcquire::Item::StatDone)
- continue;
-
- (*I)->Finished();
-
- ::URI uri((*I)->DescURI());
- uri.User.clear();
- uri.Password.clear();
- string descUri = string(uri);
- _error->Warning(_("Failed to fetch %s %s\n"), descUri.c_str(),
- (*I)->ErrorText.c_str());
-
- if ((*I)->Status == pkgAcquire::Item::StatTransientNetworkError)
- {
- TransientNetworkFailure = true;
- continue;
- }
-
- Failed = true;
- }
-
- // Clean out any old list files
- // Keep "APT::Get::List-Cleanup" name for compatibility, but
- // this is really a global option for the APT library now
- if (!TransientNetworkFailure && !Failed &&
- (_config->FindB("APT::Get::List-Cleanup",true) == true &&
- _config->FindB("APT::List-Cleanup",true) == true))
- {
- if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
- Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
- // something went wrong with the clean
- return false;
- }
-
- if (TransientNetworkFailure == true)
- _error->Warning(_("Some index files failed to download. They have been ignored, or old ones used instead."));
- else if (Failed == true)
- return _error->Error(_("Some index files failed to download. They have been ignored, or old ones used instead."));
-
-
- // Run the success scripts if all was fine
- if(!TransientNetworkFailure && !Failed)
- RunScripts("APT::Update::Post-Invoke-Success");
-
- // Run the other scripts
- RunScripts("APT::Update::Post-Invoke");
- return true;
-}
- /*}}}*/