#include <apt-pkg/version.h>
#include <apt-pkg/sptr.h>
#include <apt-pkg/acquire-item.h>
-
+#include <apt-pkg/edsp.h>
+
#include <apti18n.h>
#include <sys/types.h>
#include <cstdlib>
#include <algorithm>
#include <iostream>
+
+#include <stdio.h>
/*}}}*/
using namespace std;
{
VerIterator Ver(Sim);
- out << Pkg.Name();
+ out << Pkg.FullName(true);
if (Current == true)
{
Describe(Pkg,cout,true,true);
Sim.MarkInstall(Pkg,false);
- if (strcmp(Pkg.Arch(),"all") == 0)
- {
- pkgCache::GrpIterator G = Pkg.Group();
- pkgCache::GrpIterator iG = iPkg.Group();
- for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
- {
- if (strcmp(P.Arch(), "all") == 0)
- continue;
- if (iG.FindPkg(P.Arch())->CurrentVer == 0)
- continue;
- Flags[P->ID] = 1;
- Sim.MarkInstall(P, false);
- }
- }
-
// Look for broken conflicts+predepends.
for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
{
{
if ((Sim[End] & pkgDepCache::DepGInstall) == 0)
{
- cout << " [" << I.Name() << " on " << Start.TargetPkg().Name() << ']';
+ cout << " [" << I.FullName(false) << " on " << Start.TargetPkg().FullName(false) << ']';
if (Start->Type == pkgCache::Dep::Conflicts)
- _error->Error("Fatal, conflicts violated %s",I.Name());
+ _error->Error("Fatal, conflicts violated %s",I.FullName(false).c_str());
}
}
}
Flags[Pkg->ID] = 2;
- if (strcmp(Pkg.Arch(),"all") == 0)
- {
- pkgCache::GrpIterator G = Pkg.Group();
- for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
- {
- if (strcmp(P.Arch(), "all") == 0)
- continue;
- if (Flags[P->ID] == 1)
- Flags[P->ID] = 2;
- }
- }
-
-// Sim.MarkInstall(Pkg,false);
if (Sim[Pkg].InstBroken() == true)
{
- cout << "Conf " << Pkg.Name() << " broken" << endl;
+ cout << "Conf " << Pkg.FullName(false) << " broken" << endl;
Sim.Update();
continue;
if (D->Type == pkgCache::Dep::Obsoletes)
- cout << " Obsoletes:" << D.TargetPkg().Name();
+ cout << " Obsoletes:" << D.TargetPkg().FullName(false);
else if (D->Type == pkgCache::Dep::Conflicts)
- cout << " Conflicts:" << D.TargetPkg().Name();
+ cout << " Conflicts:" << D.TargetPkg().FullName(false);
else if (D->Type == pkgCache::Dep::DpkgBreaks)
- cout << " Breaks:" << D.TargetPkg().Name();
+ cout << " Breaks:" << D.TargetPkg().FullName(false);
else
- cout << " Depends:" << D.TargetPkg().Name();
+ cout << " Depends:" << D.TargetPkg().FullName(false);
}
cout << endl;
- _error->Error("Conf Broken %s",Pkg.Name());
+ _error->Error("Conf Broken %s",Pkg.FullName(false).c_str());
}
else
{
Flags[Pkg->ID] = 3;
Sim.MarkDelete(Pkg);
- if (strcmp(Pkg.Arch(),"all") == 0)
- {
- pkgCache::GrpIterator G = Pkg.Group();
- pkgCache::GrpIterator iG = iPkg.Group();
- for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
- {
- if (strcmp(P.Arch(), "all") == 0)
- continue;
- if (iG.FindPkg(P.Arch())->CurrentVer == 0)
- continue;
- Flags[P->ID] = 3;
- Sim.MarkDelete(P);
- }
- }
-
if (Purge == true)
cout << "Purg ";
else
if (Sim[I].InstBroken() == true)
{
if (Flags[I->ID] == 0)
- cout << I.Name() << ' ';
+ cout << I.FullName(false) << ' ';
/* else
cout << I.Name() << "! ";*/
}
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());
+ "but I can't find an archive for it."),I.FullName(true).c_str());
}
continue;
default:
if (I->InstState != pkgCache::State::Ok)
return _error->Error("The package %s is not ok and I "
- "don't know how to fix it!",I.Name());
+ "don't know how to fix it!",I.FullName(false).c_str());
}
}
return true;
{
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 ((Flags[P->ID] & Protected) == Protected)
{
if (Debug == true)
- clog << " Reinst Failed because of protected " << P.Name() << endl;
+ clog << " Reinst Failed because of protected " << P.FullName(false) << endl;
Fail = true;
}
else
if (DoUpgrade(P) == false)
{
if (Debug == true)
- clog << " Reinst Failed because of " << P.Name() << endl;
+ clog << " Reinst Failed because of " << P.FullName(false) << endl;
Fail = true;
}
else
break;
if (Debug == true)
- clog << " Reinst Failed early because of " << Start.TargetPkg().Name() << endl;
+ clog << " Reinst Failed early because of " << Start.TargetPkg().FullName(false) << endl;
Fail = true;
}
}
}
if (Debug == true)
- clog << " Re-Instated " << Pkg.Name() << endl;
+ clog << " Re-Instated " << Pkg.FullName(false) << endl;
return true;
}
/*}}}*/
-// ProblemResolver::Resolve - Run the resolution pass /*{{{*/
+// ProblemResolver::Resolve - calls a resolver to fix the situation /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgProblemResolver::Resolve(bool BrokenFix)
+{
+ std::string const solver = _config->Find("APT::Solver::Name", "internal");
+
+ if (solver != "internal")
+ {
+ int solver_in, solver_out;
+ if (EDSP::ExecuteSolver(solver.c_str(), &solver_in, &solver_out) == false)
+ return false;
+
+ FILE* output = fdopen(solver_in, "w");
+ if (output == NULL)
+ return _error->Errno("Resolve", "fdopen on solver stdin failed");
+ EDSP::WriteRequest(Cache, output);
+ EDSP::WriteScenario(Cache, output);
+ fclose(output);
+
+ if (EDSP::ReadResponse(solver_out, Cache) == false)
+ return _error->Error("Reading solver response failed");
+
+ return true;
+ }
+ return ResolveInternal(BrokenFix);
+}
+ /*}}}*/
+// ProblemResolver::ResolveInternal - Run the resolution pass /*{{{*/
// ---------------------------------------------------------------------
/* This routines works by calculating a score for each package. The score
is derived by considering the package's priority and all reverse
The BrokenFix flag enables a mode where the algorithm tries to
upgrade packages to advoid problems. */
-bool pkgProblemResolver::Resolve(bool BrokenFix)
+bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
{
pkgDepCache::ActionGroup group(Cache);
- unsigned long Size = Cache.Head().PackageCount;
-
// Record which packages are marked for install
bool Again = false;
do
clog << "Starting" << endl;
MakeScores();
-
+
+ unsigned long const Size = Cache.Head().PackageCount;
+
/* We have to order the packages so that the broken fixing pass
operates from highest score to lowest. This prevents problems when
high score packages cause the removal of lower score packages that
not be possible for a loop to form (that is a < b < c and fixing b by
changing a breaks c) */
bool Change = true;
+ bool const TryFixByInstall = _config->FindB("pkgProblemResolver::FixByInstall", true);
for (int Counter = 0; Counter != 10 && Change == true; Counter++)
{
Change = false;
(Flags[I->ID] & ReInstateTried) == 0)
{
if (Debug == true)
- clog << " Try to Re-Instate " << I.Name() << endl;
+ clog << " Try to Re-Instate (" << Counter << ") " << I.FullName(false) << endl;
unsigned long OldBreaks = Cache.BrokenCount();
pkgCache::Version *OldVer = Cache[I].InstallVer;
Flags[I->ID] &= ReInstateTried;
}
else
if (Debug == true)
- clog << "Re-Instated " << I.Name() << " (" << OldBreaks << " vs " << Cache.BrokenCount() << ')' << endl;
+ clog << "Re-Instated " << I.FullName(false) << " (" << OldBreaks << " vs " << Cache.BrokenCount() << ')' << endl;
}
if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
continue;
if (Debug == true)
- clog << "Investigating " << I.Name() << endl;
+ clog << "Investigating (" << Counter << ") " << I << endl;
// Isolate the problem dependency
PackageKill KillList[100];
if (Start == End)
{
// Decide what to do
- if (InOr == true)
+ if (InOr == true && OldEnd == LEnd)
{
- if (OldEnd == LEnd && OrOp == OrRemove)
+ if (OrOp == OrRemove)
{
if ((Flags[I->ID] & Protected) != Protected)
{
if (Debug == true)
- clog << " Or group remove for " << I.Name() << endl;
+ clog << " Or group remove for " << I.FullName(false) << endl;
Cache.MarkDelete(I);
Change = true;
- }
- }
- if (OldEnd == LEnd && OrOp == OrKeep)
+ }
+ }
+ else if (OrOp == OrKeep)
{
if (Debug == true)
- clog << " Or group keep for " << I.Name() << endl;
+ clog << " Or group keep for " << I.FullName(false) << endl;
Cache.MarkKeep(I, false, false);
Change = true;
}
}
if (Debug == true)
- clog << "Package " << I.Name() << " has broken " << Start.DepType() << " on " << Start.TargetPkg().Name() << endl;
+ clog << "Broken " << Start << endl;
/* Look across the version list. If there are no possible
targets then we keep the package and bail. This is necessary
pkgCache::VerIterator Ver(Cache,*V);
pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+ /* This is a conflicts, and the version we are looking
+ at is not the currently selected version of the
+ package, which means it is not necessary to
+ remove/keep */
+ if (Cache[Pkg].InstallVer != Ver &&
+ (Start->Type == pkgCache::Dep::Conflicts ||
+ Start->Type == pkgCache::Dep::DpkgBreaks ||
+ Start->Type == pkgCache::Dep::Obsoletes))
+ {
+ if (Debug)
+ clog << " Conflicts//Breaks against version "
+ << Ver.VerStr() << " for " << Pkg.Name()
+ << " but that is not InstVer, ignoring"
+ << endl;
+ continue;
+ }
+
if (Debug == true)
- clog << " Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] <<
- " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl;
+ clog << " Considering " << Pkg.FullName(false) << ' ' << (int)Scores[Pkg->ID] <<
+ " as a solution to " << I.FullName(false) << ' ' << (int)Scores[I->ID] << endl;
/* Try to fix the package under consideration rather than
fiddle with the VList package */
Cache.MarkInstall(I, false, 0, false);
if (Debug == true)
- clog << " Holding Back " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
+ clog << " Holding Back " << I.FullName(false) << " rather than change " << Start.TargetPkg().FullName(false) << endl;
}
else
{
if (InOr == false)
{
if (Debug == true)
- clog << " Removing " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
+ clog << " Removing " << I.FullName(false) << " rather than change " << Start.TargetPkg().FullName(false) << endl;
Cache.MarkDelete(I);
if (Counter > 1 && Scores[Pkg->ID] > Scores[I->ID])
Scores[I->ID] = Scores[Pkg->ID];
}
+ else if (TryFixByInstall == true &&
+ Start.TargetPkg()->CurrentVer == 0 &&
+ Cache[Start.TargetPkg()].Delete() == false &&
+ (Flags[Start.TargetPkg()->ID] & ToRemove) != ToRemove &&
+ Cache.GetCandidateVer(Start.TargetPkg()).end() == false)
+ {
+ /* Before removing or keeping the package with the broken dependency
+ try instead to install the first not previously installed package
+ solving this dependency. This helps every time a previous solver
+ is removed by the resolver because of a conflict or alike but it is
+ dangerous as it could trigger new breaks/conflicts… */
+ if (Debug == true)
+ clog << " Try Installing " << Start.TargetPkg() << " before changing " << I.FullName(false) << std::endl;
+ unsigned long const OldBroken = Cache.BrokenCount();
+ Cache.MarkInstall(Start.TargetPkg(), true, 1, false);
+ // FIXME: we should undo the complete MarkInstall process here
+ if (Cache[Start.TargetPkg()].InstBroken() == true || Cache.BrokenCount() > OldBroken)
+ Cache.MarkDelete(Start.TargetPkg(), false, 1, false);
+ }
}
}
}
else
{
- /* This is a conflicts, and the version we are looking
- at is not the currently selected version of the
- package, which means it is not necessary to
- remove/keep */
- if (Cache[Pkg].InstallVer != Ver &&
- (Start->Type == pkgCache::Dep::Conflicts ||
- Start->Type == pkgCache::Dep::Obsoletes))
- continue;
-
if (Start->Type == pkgCache::Dep::DpkgBreaks)
{
// first, try upgradring the package, if that
// does not help, the breaks goes onto the
// kill list
+ //
// FIXME: use DoUpgrade(Pkg) instead?
- if (Cache[End] & pkgDepCache::DepGCVer)
+ if (Cache[End] & pkgDepCache::DepGCVer)
{
if (Debug)
- clog << " Upgrading " << Pkg.Name() << " due to Breaks field in " << I.Name() << endl;
+ clog << " Upgrading " << Pkg.FullName(false) << " due to Breaks field in " << I.FullName(false) << endl;
Cache.MarkInstall(Pkg, false, 0, false);
continue;
}
continue;
if (Debug == true)
- clog << " Added " << Pkg.Name() << " to the remove list" << endl;
+ clog << " Added " << Pkg.FullName(false) << " to the remove list" << endl;
LEnd->Pkg = Pkg;
LEnd->Dep = End;
Cache.MarkInstall(I, false, 0, false);
if (Debug == true)
- clog << " Holding Back " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
+ clog << " Holding Back " << I.FullName(false) << " because I can't find " << Start.TargetPkg().FullName(false) << endl;
}
else
{
if (Debug == true)
- clog << " Removing " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
+ clog << " Removing " << I.FullName(false) << " because I can't find " << Start.TargetPkg().FullName(false) << endl;
if (InOr == false)
Cache.MarkDelete(I);
}
J->Dep->Type == pkgCache::Dep::Obsoletes)
{
if (Debug == true)
- clog << " Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl;
+ clog << " Fixing " << I.FullName(false) << " via remove of " << J->Pkg.FullName(false) << endl;
Cache.MarkDelete(J->Pkg);
}
}
else
{
if (Debug == true)
- clog << " Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
+ clog << " Fixing " << I.FullName(false) << " via keep of " << J->Pkg.FullName(false) << endl;
Cache.MarkKeep(J->Pkg, false, false);
}
return _error->Error(_("Unable to correct problems, you have held broken packages."));
}
- // set the auto-flags (mvo: I'm not sure if we _really_ need this, but
- // I didn't managed
+ // set the auto-flags (mvo: I'm not sure if we _really_ need this)
pkgCache::PkgIterator I = Cache.PkgBegin();
for (;I.end() != true; I++) {
if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) {
if(_config->FindI("Debug::pkgAutoRemove",false)) {
- std::clog << "Resolve installed new pkg: " << I.Name()
+ std::clog << "Resolve installed new pkg: " << I.FullName(false)
<< " (now marking it as auto)" << std::endl;
}
Cache[I].Flags |= pkgCache::Flag::Auto;
if ((Flags[I->ID] & Protected) == 0)
{
if (Debug == true)
- clog << "Keeping package " << I.Name() << endl;
+ clog << "Keeping package " << I.FullName(false) << endl;
Cache.MarkKeep(I, false, false);
if (Cache[I].InstBroken() == false)
{
while (true)
{
if (Debug == true)
- clog << "Package " << I.Name() << " has broken " << Start.DepType() << " on " << Start.TargetPkg().Name() << endl;
+ clog << "Package " << I.FullName(false) << " " << Start << endl;
// Look at all the possible provides on this package
SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
if ((Flags[I->ID] & Protected) == 0)
{
if (Debug == true)
- clog << " Keeping Package " << Pkg.Name() << " due to " << Start.DepType() << endl;
+ clog << " Keeping Package " << Pkg.FullName(false) << " due to " << Start.DepType() << endl;
Cache.MarkKeep(Pkg, false, false);
}
// Restart again.
if (K == LastStop)
- return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.Name());
+ return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.FullName(false).c_str());
LastStop = K;
K = PList - 1;
}
}
if (TransientNetworkFailure == true)
- _error->Warning(_("Some index files failed to download, they have been ignored, or old ones used instead."));
+ _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."));
+ 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