X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/1f530ccb32c17b70b05dd5feee706dc1098a7251..4e1c86a6c0cf9a6e51ec4f9b9ad9271547fa036d:/apt-pkg/depcache.cc diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index ffa4fe71c..2656e9b42 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -8,27 +8,35 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ +#include + #include #include +#include #include #include #include - #include #include #include #include #include #include +#include +#include +#include #include -#include +#include #include #include -#include +#include /*}}}*/ + +using std::string; + // helper for Install-Recommends-Sections and Never-MarkAuto-Sections /*{{{*/ static bool ConfigValueInSubTree(const char* SubTree, const char *needle) @@ -69,7 +77,7 @@ void pkgDepCache::ActionGroup::release() cache.MarkAndSweep(); } - released = false; + released = true; } } @@ -128,7 +136,7 @@ bool pkgDepCache::Init(OpProgress *Prog) /* Set the current state of everything. In this state all of the packages are kept exactly as is. See AllUpgrade */ int Done = 0; - for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++) + for (PkgIterator I = PkgBegin(); I.end() != true; ++I, ++Done) { if (Prog != 0 && Done%20 == 0) Prog->Progress(Done); @@ -165,17 +173,17 @@ bool pkgDepCache::Init(OpProgress *Prog) bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/ { FileFd state_file; - string const state = _config->FindDir("Dir::State") + "extended_states"; - if(FileExists(state)) { + string const state = _config->FindFile("Dir::State::extended_states"); + if(RealFileExists(state)) { state_file.Open(state, FileFd::ReadOnly); - int const file_size = state_file.Size(); + off_t const file_size = state_file.Size(); if(Prog != NULL) Prog->OverallProgress(0, file_size, 1, _("Reading state information")); pkgTagFile tagfile(&state_file); pkgTagSection section; - int amt = 0; + off_t amt = 0; bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false); while(tagfile.Step(section)) { string const pkgname = section.FindS("Package"); @@ -192,7 +200,7 @@ bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/ { PkgState[pkg->ID].Flags |= Flag::Auto; if (unlikely(debug_autoremove)) - std::cout << "Auto-Installed : " << pkg.FullName() << std::endl; + std::clog << "Auto-Installed : " << pkg.FullName() << std::endl; if (pkgarch == "any") { pkgCache::GrpIterator G = pkg.Group(); @@ -222,12 +230,12 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/ std::clog << "pkgDepCache::writeStateFile()" << std::endl; FileFd StateFile; - string const state = _config->FindDir("Dir::State") + "extended_states"; + string const state = _config->FindFile("Dir::State::extended_states"); // if it does not exist, create a empty one - if(!FileExists(state)) + if(!RealFileExists(state)) { - StateFile.Open(state, FileFd::WriteEmpty); + StateFile.Open(state, FileFd::WriteAtomic); StateFile.Close(); } @@ -257,7 +265,22 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/ pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch); if(pkg.end() || pkg.VersionList().end()) continue; - bool const newAuto = (PkgState[pkg->ID].Flags & Flag::Auto); + StateCache const &P = PkgState[pkg->ID]; + bool newAuto = (P.Flags & Flag::Auto); + // skip not installed or now-removed ones if requested + if (InstalledOnly && ( + (pkg->CurrentVer == 0 && P.Mode != ModeInstall) || + (pkg->CurrentVer != 0 && P.Mode == ModeDelete))) + { + // The section is obsolete if it contains no other tag + unsigned int const count = section.Count(); + if (count < 2 || + (count == 2 && section.Exists("Auto-Installed")) || + (count == 3 && section.Exists("Auto-Installed") && section.Exists("Architecture"))) + continue; + else + newAuto = false; + } if(_config->FindB("Debug::pkgAutoRemove",false)) std::clog << "Update existing AutoInstall info: " << pkg.FullName() << std::endl; @@ -276,15 +299,18 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/ // then write the ones we have not seen yet std::ostringstream ostr; - for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) { - if(PkgState[pkg->ID].Flags & Flag::Auto) { + for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); ++pkg) { + StateCache const &P = PkgState[pkg->ID]; + if(P.Flags & Flag::Auto) { if (pkgs_seen.find(pkg.FullName()) != pkgs_seen.end()) { if(debug_autoremove) std::clog << "Skipping already written " << pkg.FullName() << std::endl; continue; } // skip not installed ones if requested - if(InstalledOnly && pkg->CurrentVer == 0) + if (InstalledOnly && ( + (pkg->CurrentVer == 0 && P.Mode != ModeInstall) || + (pkg->CurrentVer != 0 && P.Mode == ModeDelete))) continue; const char* const pkgarch = pkg.Arch(); if (strcmp(pkgarch, "all") == 0) @@ -320,8 +346,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) /* Check simple depends. A depends -should- never self match but we allow it anyhow because dpkg does. Technically it is a packaging bug. Conflicts may never self match */ - if (Dep.TargetPkg() != Dep.ParentPkg() || - (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes)) + if (Dep.TargetPkg() != Dep.ParentPkg() || Dep.IsNegative() == false) { PkgIterator Pkg = Dep.TargetPkg(); // Check the base package @@ -346,15 +371,11 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) // Check the providing packages PrvIterator P = Dep.TargetPkg().ProvidesList(); - PkgIterator Pkg = Dep.ParentPkg(); - for (; P.end() != true; P++) + for (; P.end() != true; ++P) { - /* Provides may never be applied against the same package if it is - a conflicts. See the comment above. */ - if (P.OwnerPkg() == Pkg && - (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks)) + if (Dep.IsIgnorable(P) == true) continue; - + // Check if the provides is a hit if (Type == NowVersion) { @@ -389,8 +410,8 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) /*}}}*/ // DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/ // --------------------------------------------------------------------- -/* Call with Mult = -1 to preform the inverse opration */ -void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) +/* Call with Inverse = true to preform the inverse opration */ +void pkgDepCache::AddSizes(const PkgIterator &Pkg, bool const Inverse) { StateCache &P = PkgState[Pkg->ID]; @@ -404,8 +425,13 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) // Compute the size data if (P.NewInstall() == true) { - iUsrSize += (signed)(Mult*P.InstVerIter(*this)->InstalledSize); - iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size); + if (Inverse == false) { + iUsrSize += P.InstVerIter(*this)->InstalledSize; + iDownloadSize += P.InstVerIter(*this)->Size; + } else { + iUsrSize -= P.InstVerIter(*this)->InstalledSize; + iDownloadSize -= P.InstVerIter(*this)->Size; + } return; } @@ -414,9 +440,15 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) (P.InstallVer != (Version *)Pkg.CurrentVer() || (P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0) { - iUsrSize += (signed)(Mult*((signed)P.InstVerIter(*this)->InstalledSize - - (signed)Pkg.CurrentVer()->InstalledSize)); - iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size); + if (Inverse == false) { + iUsrSize -= Pkg.CurrentVer()->InstalledSize; + iUsrSize += P.InstVerIter(*this)->InstalledSize; + iDownloadSize += P.InstVerIter(*this)->Size; + } else { + iUsrSize -= P.InstVerIter(*this)->InstalledSize; + iUsrSize += Pkg.CurrentVer()->InstalledSize; + iDownloadSize -= P.InstVerIter(*this)->Size; + } return; } @@ -424,14 +456,20 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack && P.Delete() == false) { - iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size); + if (Inverse == false) + iDownloadSize += P.InstVerIter(*this)->Size; + else + iDownloadSize -= P.InstVerIter(*this)->Size; return; } // Removing if (Pkg->CurrentVer != 0 && P.InstallVer == 0) { - iUsrSize -= (signed)(Mult*Pkg.CurrentVer()->InstalledSize); + if (Inverse == false) + iUsrSize -= Pkg.CurrentVer()->InstalledSize; + else + iUsrSize += Pkg.CurrentVer()->InstalledSize; return; } } @@ -444,8 +482,9 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) calld Remove/Add itself. Remember, dependencies can be circular so while processing a dep for Pkg it is possible that Add/Remove will be called on Pkg */ -void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add) +void pkgDepCache::AddStates(const PkgIterator &Pkg, bool const Invert) { + signed char const Add = (Invert == false) ? 1 : -1; StateCache &State = PkgState[Pkg->ID]; // The Package is broken (either minimal dep or policy dep) @@ -461,8 +500,8 @@ void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add) // Not installed if (Pkg->CurrentVer == 0) { - if (State.Mode == ModeDelete && - (State.iFlags | Purge) == Purge && Pkg.Purge() == false) + if (State.Mode == ModeDelete && + (State.iFlags & Purge) == Purge && Pkg.Purge() == false) iDelCount += Add; if (State.Mode == ModeInstall) @@ -499,16 +538,14 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V) { unsigned char Group = 0; - for (DepIterator D = V.DependsList(); D.end() != true; D++) + for (DepIterator D = V.DependsList(); D.end() != true; ++D) { // Build the dependency state. unsigned char &State = DepState[D->ID]; /* Invert for Conflicts. We have to do this twice to get the right sense for a conflicts group */ - if (D->Type == Dep::Conflicts || - D->Type == Dep::DpkgBreaks || - D->Type == Dep::Obsoletes) + if (D.IsNegative() == true) State = ~State; // Add to the group if we are within an or.. @@ -519,9 +556,7 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V) Group = 0; // Invert for Conflicts - if (D->Type == Dep::Conflicts || - D->Type == Dep::DpkgBreaks || - D->Type == Dep::Obsoletes) + if (D.IsNegative() == true) State = ~State; } } @@ -543,7 +578,7 @@ unsigned char pkgDepCache::VersionState(DepIterator D,unsigned char Check, // Compute a single dependency element (glob or) DepIterator Start = D; unsigned char State = 0; - for (bool LastOR = true; D.end() == false && LastOR == true; D++) + for (bool LastOR = true; D.end() == false && LastOR == true; ++D) { State |= DepState[D->ID]; LastOR = (D->CompareOp & Dep::Or) == Dep::Or; @@ -617,107 +652,6 @@ void pkgDepCache::UpdateVerState(PkgIterator Pkg) } } /*}}}*/ -// DepCache::RemovePseudoInstalledPkg - MultiArch helper for Update() /*{{{*/ -// --------------------------------------------------------------------- -/* We "install" arch all packages for all archs if it is installed. Many - of these will be broken. This method will look at these broken Pkg and - "remove" it. */ -bool pkgDepCache::RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set &recheck) { - if (unlikely(Pkg->CurrentVer == 0)) - return false; - - VerIterator V = Pkg.CurrentVer(); - if (V->MultiArch != Version::All) - return false; - - // Never ever kill an "all" package - they have no dependency so they can't be broken - if (strcmp(Pkg.Arch(),"all") == 0) - return false; - - unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy); - if ((CurDepState & DepInstMin) == DepInstMin) { - // okay, the package isn't broken, but is the package also required? - // If it has no real dependencies, no installed rdepends and doesn't - // provide something of value, we will kill it as not required. - // These pseudopackages have otherwise interesting effects if they get - // a new dependency in a newer version… - for (pkgCache::DepIterator D = V.DependsList(); - D.end() != true; ++D) - if (D.IsCritical() == true && D.ParentPkg()->Group != Pkg->Group) - return false; - for (DepIterator D = Pkg.RevDependsList(); D.end() != true; ++D) - { - if (D.IsCritical() == false) - continue; - PkgIterator const P = D.ParentPkg(); - if (P->Group == Pkg->Group) - continue; - if (P->CurrentVer != 0) - return false; - } - for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++) - for (DepIterator d = Prv.ParentPkg().RevDependsList(); - d.end() != true; ++d) - { - PkgIterator const P = d.ParentPkg(); - if (P->CurrentVer != 0 && - P->Group != Pkg->Group) - return false; - } - } - - // Dependencies for this arch all package are not statisfied - // so we installed it only for our convenience: get right of it now. - RemoveSizes(Pkg); - RemoveStates(Pkg); - - Pkg->CurrentVer = 0; - PkgState[Pkg->ID].InstallVer = 0; - - AddStates(Pkg); - Update(Pkg); - AddSizes(Pkg); - - // After the remove previously satisfied pseudo pkg could be now - // no longer satisfied, so we need to recheck the reverse dependencies - for (DepIterator d = Pkg.RevDependsList(); d.end() != true; ++d) - { - PkgIterator const P = d.ParentPkg(); - if (P->CurrentVer != 0) - recheck.insert(P.Index()); - } - - for (DepIterator d = V.DependsList(); d.end() != true; ++d) - { - PkgIterator const P = d.TargetPkg(); - for (PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv) - { - PkgIterator const O = Prv.OwnerPkg(); - if (O->CurrentVer != 0) - recheck.insert(O.Index()); - } - - if (P->CurrentVer != 0) - recheck.insert(P.Index()); - } - - for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++) - { - for (DepIterator d = Prv.ParentPkg().RevDependsList(); - d.end() != true; ++d) - { - PkgIterator const P = d.ParentPkg(); - if (P->CurrentVer == 0) - continue; - - recheck.insert(P.Index()); - } - } - - - return true; -} - /*}}}*/ // DepCache::Update - Figure out all the state information /*{{{*/ // --------------------------------------------------------------------- /* This will figure out the state of all the packages and all the @@ -732,21 +666,17 @@ void pkgDepCache::Update(OpProgress *Prog) iBrokenCount = 0; iBadCount = 0; - std::set recheck; - // Perform the depends pass int Done = 0; - bool const checkMultiArch = APT::Configuration::getArchitectures().size() > 1; - unsigned long killed = 0; - for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++) + for (PkgIterator I = PkgBegin(); I.end() != true; ++I, ++Done) { if (Prog != 0 && Done%20 == 0) Prog->Progress(Done); - for (VerIterator V = I.VersionList(); V.end() != true; V++) + for (VerIterator V = I.VersionList(); V.end() != true; ++V) { unsigned char Group = 0; - for (DepIterator D = V.DependsList(); D.end() != true; D++) + for (DepIterator D = V.DependsList(); D.end() != true; ++D) { // Build the dependency state. unsigned char &State = DepState[D->ID]; @@ -759,9 +689,7 @@ void pkgDepCache::Update(OpProgress *Prog) Group = 0; // Invert for Conflicts - if (D->Type == Dep::Conflicts || - D->Type == Dep::DpkgBreaks || - D->Type == Dep::Obsoletes) + if (D.IsNegative() == true) State = ~State; } } @@ -770,95 +698,6 @@ void pkgDepCache::Update(OpProgress *Prog) AddSizes(I); UpdateVerState(I); AddStates(I); - - if (checkMultiArch != true || I->CurrentVer == 0) - continue; - - VerIterator const V = I.CurrentVer(); - if (V->MultiArch != Version::All) - continue; - - recheck.insert(I.Index()); - --Done; // no progress if we need to recheck the package - } - - if (checkMultiArch == true) { - /* FIXME: recheck breaks proper progress reporting as we don't know - how many packages we need to recheck. To lower the effect - a bit we increase with a kill, but we should do something more clever… */ - for(std::set::const_iterator p = recheck.begin(); - p != recheck.end(); ++p) { - if (Prog != 0 && Done%20 == 0) - Prog->Progress(Done); - PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p); - if (RemovePseudoInstalledPkg(P, recheck) == true) { - ++killed; - ++Done; - } - recheck.erase(p); - } - - /* Okay, we have killed a great amount of pseudopackages - - we have killed so many that we have now arch "all" packages - without an installed pseudo package, but we NEED an installed - pseudo package, so we will search now for a pseudo package - we can install without breaking everything. */ - for (GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G) - { - PkgIterator P = G.FindPkg("all"); - if (P.end() == true) - continue; - if (P->CurrentVer == 0) - continue; - bool installed = false; - for (P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P)) - { - if (strcmp(P.Arch(), "all") == 0) - continue; - if (P->CurrentVer == 0) - continue; - installed = true; - break; - } - if (installed == false) - recheck.insert(G.Index()); - } - std::vector Archs = APT::Configuration::getArchitectures(); - bool checkChanged = false; - do { - for(std::set::const_iterator g = recheck.begin(); - g != recheck.end(); ++g) { - GrpIterator G = GrpIterator(*Cache, Cache->GrpP + *g); - VerIterator allV = G.FindPkg("all").CurrentVer(); - for (std::vector::const_iterator a = Archs.begin(); - a != Archs.end(); ++a) - { - PkgIterator P = G.FindPkg(*a); - if (P.end() == true) continue; - for (VerIterator V = P.VersionList(); V.end() != true; ++V) - { - // FIXME: String comparison isn't a save indicator! - if (strcmp(allV.VerStr(),V.VerStr()) != 0) - continue; - unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy); - if ((CurDepState & DepInstMin) != DepInstMin) - break; // we found the correct version, but it is broken. Better try another arch or later again - P->CurrentVer = V.Index(); - AddStates(P); - Update(P); - AddSizes(P); - checkChanged = true; - break; - } - } - recheck.erase(g); - } - } while (checkChanged == true && recheck.empty() == false); - - if (_config->FindB("Debug::MultiArchKiller", false) == true) - for(std::set::const_iterator g = recheck.begin(); - g != recheck.end(); ++g) - std::cout << "No pseudo package for »" << GrpIterator(*Cache, Cache->GrpP + *g).Name() << "« installed" << std::endl; } if (Prog != 0) @@ -874,15 +713,13 @@ void pkgDepCache::Update(OpProgress *Prog) void pkgDepCache::Update(DepIterator D) { // Update the reverse deps - for (;D.end() != true; D++) + for (;D.end() != true; ++D) { unsigned char &State = DepState[D->ID]; State = DependencyState(D); // Invert for Conflicts - if (D->Type == Dep::Conflicts || - D->Type == Dep::DpkgBreaks || - D->Type == Dep::Obsoletes) + if (D.IsNegative() == true) State = ~State; RemoveStates(D.ParentPkg()); @@ -909,50 +746,46 @@ void pkgDepCache::Update(PkgIterator const &Pkg) // Update the provides map for the current ver if (Pkg->CurrentVer != 0) for (PrvIterator P = Pkg.CurrentVer().ProvidesList(); - P.end() != true; P++) + P.end() != true; ++P) Update(P.ParentPkg().RevDependsList()); // Update the provides map for the candidate ver if (PkgState[Pkg->ID].CandidateVer != 0) for (PrvIterator P = PkgState[Pkg->ID].CandidateVerIter(*this).ProvidesList(); - P.end() != true; P++) + P.end() != true; ++P) Update(P.ParentPkg().RevDependsList()); } /*}}}*/ // DepCache::MarkKeep - Put the package in the keep state /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser, +bool pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser, unsigned long Depth) { - // Simplifies other routines. - if (Pkg.end() == true) - return; + if (IsModeChangeOk(ModeKeep, Pkg, Depth, FromUser) == false) + return false; /* Reject an attempt to keep a non-source broken installed package, those must be upgraded */ if (Pkg.State() == PkgIterator::NeedsUnpack && Pkg.CurrentVer().Downloadable() == false) - return; - - /** \todo Can this be moved later in the method? */ - ActionGroup group(*this); + return false; /* We changed the soft state all the time so the UI is a bit nicer to use */ StateCache &P = PkgState[Pkg->ID]; + + // Check that it is not already kept + if (P.Mode == ModeKeep) + return true; + if (Soft == true) P.iFlags |= AutoKept; else P.iFlags &= ~AutoKept; - - // Check that it is not already kept - if (P.Mode == ModeKeep) - return; - // We dont even try to keep virtual packages.. - if (Pkg->VersionList == 0) - return; + ActionGroup group(*this); + #if 0 // reseting the autoflag here means we lose the // auto-mark information if a user selects a package for removal // but changes his mind then and sets it for keep again @@ -977,44 +810,40 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser, P.InstallVer = Pkg.CurrentVer(); AddStates(Pkg); - Update(Pkg); - AddSizes(Pkg); + + return true; } /*}}}*/ // DepCache::MarkDelete - Put the package in the delete state /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, +bool pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, unsigned long Depth, bool FromUser) { - // Simplifies other routines. - if (Pkg.end() == true) - return; + if (IsModeChangeOk(ModeDelete, Pkg, Depth, FromUser) == false) + return false; - ActionGroup group(*this); + StateCache &P = PkgState[Pkg->ID]; // Check that it is not already marked for delete - StateCache &P = PkgState[Pkg->ID]; - P.iFlags &= ~(AutoKept | Purge); - if (rPurge == true) - P.iFlags |= Purge; - if ((P.Mode == ModeDelete || P.InstallVer == 0) && (Pkg.Purge() == true || rPurge == false)) - return; - - // We dont even try to delete virtual packages.. - if (Pkg->VersionList == 0) - return; + return true; - // check if we are allowed to install the package + // check if we are allowed to remove the package if (IsDeleteOk(Pkg,rPurge,Depth,FromUser) == false) - return; + return false; + + P.iFlags &= ~(AutoKept | Purge); + if (rPurge == true) + P.iFlags |= Purge; + + ActionGroup group(*this); if (DebugMarker == true) - std::clog << OutputInDepth(Depth) << "MarkDelete " << Pkg << " FU=" << FromUser << std::endl; + std::clog << OutputInDepth(Depth) << (rPurge ? "MarkPurge " : "MarkDelete ") << Pkg << " FU=" << FromUser << std::endl; RemoveSizes(Pkg); RemoveStates(Pkg); @@ -1029,67 +858,169 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, Update(Pkg); AddSizes(Pkg); - // if we remove the pseudo package, we also need to remove the "real" - if (Pkg->CurrentVer != 0 && Pkg.CurrentVer().Pseudo() == true) - MarkDelete(Pkg.Group().FindPkg("all"), rPurge, Depth+1, FromUser); + return true; } /*}}}*/ // DepCache::IsDeleteOk - check if it is ok to remove this package /*{{{*/ // --------------------------------------------------------------------- -/* The default implementation just honors dpkg hold - But an application using this library can override this method - to control the MarkDelete behaviour */ +/* The default implementation tries to prevent deletion of install requests. + dpkg holds are enforced by the private IsModeChangeOk */ bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge, unsigned long Depth, bool FromUser) { - if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false) + if (FromUser == false && Pkg->CurrentVer == 0) { - if (DebugMarker == true) - std::clog << OutputInDepth(Depth) << "Hold prevents MarkDelete of " << Pkg << " FU=" << FromUser << std::endl; + StateCache &P = PkgState[Pkg->ID]; + if (P.InstallVer != 0 && P.Status == 2 && (P.Flags & Flag::Auto) != Flag::Auto) + { + if (DebugMarker == true) + std::clog << OutputInDepth(Depth) << "Manual install request prevents MarkDelete of " << Pkg << std::endl; + return false; + } + } + return true; +} + /*}}}*/ +// DepCache::IsModeChangeOk - check if it is ok to change the mode /*{{{*/ +// --------------------------------------------------------------------- +/* this is used by all Mark methods on the very first line to check sanity + and prevents mode changes for packages on hold for example. + If you want to check Mode specific stuff you can use the virtual public + IsOk methods instead */ +char const* PrintMode(char const mode) +{ + switch (mode) + { + case pkgDepCache::ModeInstall: return "Install"; + case pkgDepCache::ModeKeep: return "Keep"; + case pkgDepCache::ModeDelete: return "Delete"; + default: return "UNKNOWN"; + } +} +bool pkgDepCache::IsModeChangeOk(ModeList const mode, PkgIterator const &Pkg, + unsigned long const Depth, bool const FromUser) +{ + // we are not trying to hard… + if (unlikely(Depth > 100)) + return false; + + // general sanity + if (unlikely(Pkg.end() == true || Pkg->VersionList == 0)) + return false; + + // the user is always right + if (FromUser == true) + return true; + + StateCache &P = PkgState[Pkg->ID]; + + // if previous state was set by user only user can reset it + if ((P.iFlags & Protected) == Protected) + { + if (unlikely(DebugMarker == true) && P.Mode != mode) + std::clog << OutputInDepth(Depth) << "Ignore Mark" << PrintMode(mode) + << " of " << Pkg << " as its mode (" << PrintMode(P.Mode) + << ") is protected" << std::endl; + return false; + } + // enforce dpkg holds + else if (mode != ModeKeep && Pkg->SelectedState == pkgCache::State::Hold && + _config->FindB("APT::Ignore-Hold",false) == false) + { + if (unlikely(DebugMarker == true) && P.Mode != mode) + std::clog << OutputInDepth(Depth) << "Hold prevents Mark" << PrintMode(mode) + << " of " << Pkg << std::endl; return false; } + return true; } /*}}}*/ // DepCache::MarkInstall - Put the package in the install state /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, +struct CompareProviders { + pkgCache::PkgIterator const Pkg; + CompareProviders(pkgCache::DepIterator const &Dep) : Pkg(Dep.TargetPkg()) {}; + //bool operator() (APT::VersionList::iterator const &AV, APT::VersionList::iterator const &BV) + bool operator() (pkgCache::VerIterator const &AV, pkgCache::VerIterator const &BV) + { + pkgCache::PkgIterator const A = AV.ParentPkg(); + pkgCache::PkgIterator const B = BV.ParentPkg(); + // Prefer packages in the same group as the target; e.g. foo:i386, foo:amd64 + if (A->Group != B->Group) + { + if (A->Group == Pkg->Group && B->Group != Pkg->Group) + return false; + else if (B->Group == Pkg->Group && A->Group != Pkg->Group) + return true; + } + // we like essentials + if ((A->Flags & pkgCache::Flag::Essential) != (B->Flags & pkgCache::Flag::Essential)) + { + if ((A->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) + return false; + else if ((B->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) + return true; + } + if ((A->Flags & pkgCache::Flag::Important) != (B->Flags & pkgCache::Flag::Important)) + { + if ((A->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important) + return false; + else if ((B->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important) + return true; + } + // higher priority seems like a good idea + if (AV->Priority != BV->Priority) + return AV->Priority < BV->Priority; + // prefer native architecture + if (strcmp(A.Arch(), B.Arch()) != 0) + { + if (strcmp(A.Arch(), A.Cache()->NativeArch()) == 0) + return false; + else if (strcmp(B.Arch(), B.Cache()->NativeArch()) == 0) + return true; + std::vector archs = APT::Configuration::getArchitectures(); + for (std::vector::const_iterator a = archs.begin(); a != archs.end(); ++a) + if (*a == A.Arch()) + return false; + else if (*a == B.Arch()) + return true; + } + // unable to decide… + return A->ID < B->ID; + } +}; +bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, unsigned long Depth, bool FromUser, bool ForceImportantDeps) { - if (Depth > 100) - return; - - // Simplifies other routines. - if (Pkg.end() == true) - return; - - ActionGroup group(*this); + if (IsModeChangeOk(ModeInstall, Pkg, Depth, FromUser) == false) + return false; + + StateCache &P = PkgState[Pkg->ID]; + + // See if there is even any possible instalation candidate + if (P.CandidateVer == 0) + return false; /* Check that it is not already marked for install and that it can be installed */ - StateCache &P = PkgState[Pkg->ID]; - P.iFlags &= ~AutoKept; if ((P.InstPolicyBroken() == false && P.InstBroken() == false) && (P.Mode == ModeInstall || P.CandidateVer == (Version *)Pkg.CurrentVer())) { if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0) - MarkKeep(Pkg, false, FromUser, Depth+1); - return; + return MarkKeep(Pkg, false, FromUser, Depth+1); + return true; } - // See if there is even any possible instalation candidate - if (P.CandidateVer == 0) - return; - // We dont even try to install virtual packages.. - if (Pkg->VersionList == 0) - return; - // check if we are allowed to install the package if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false) - return; + return false; + + ActionGroup group(*this); + P.iFlags &= ~AutoKept; /* Target the candidate version and remove the autoflag. We reset the autoflag below if this was called recursively. Otherwise the user @@ -1102,9 +1033,10 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, if(FromUser) { - // Set it to manual if it's a new install or cancelling the - // removal of a garbage package. - if(P.Status == 2 || (!Pkg.CurrentVer().end() && !P.Marked)) + // Set it to manual if it's a new install or already installed, + // but only if its not marked by the autoremover (aptitude depend on this behavior) + // or if we do automatic installation (aptitude never does it) + if(P.Status == 2 || (Pkg->CurrentVer != 0 && (AutoInst == true || P.Marked == false))) P.Flags &= ~Flag::Auto; } else @@ -1120,8 +1052,8 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, Update(Pkg); AddSizes(Pkg); - if (AutoInst == false) - return; + if (AutoInst == false || _config->Find("APT::Solver", "internal") != "internal") + return true; if (DebugMarker == true) std::clog << OutputInDepth(Depth) << "MarkInstall " << Pkg << " FU=" << FromUser << std::endl; @@ -1133,7 +1065,7 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, DepIterator Start = Dep; bool Result = true; unsigned Ors = 0; - for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++,Ors++) + for (bool LastOR = true; Dep.end() == false && LastOR == true; ++Dep, ++Ors) { LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or; @@ -1152,7 +1084,22 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, */ if (IsImportantDep(Start) == false) continue; - + + /* If we are in an or group locate the first or that can + succeed. We have already cached this.. */ + for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; --Ors) + ++Start; + if (Ors == 1 && (DepState[Start->ID] &DepCVer) != DepCVer && Start.IsNegative() == false) + { + if(DebugAutoInstall == true) + std::clog << OutputInDepth(Depth) << Start << " can't be satisfied!" << std::endl; + if (Start.IsCritical() == false) + continue; + // if the dependency was critical, we can't install it, so remove it again + MarkDelete(Pkg,false,Depth + 1, false); + return false; + } + /* Check if any ImportantDep() (but not Critical) were added * since we installed the package. Also check for deps that * were satisfied in the past: for instance, if a version @@ -1160,97 +1107,73 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, * package should follow that Recommends rather than causing the * dependency to be removed. (bug #470115) */ - bool isNewImportantDep = false; - bool isPreviouslySatisfiedImportantDep = false; - if(!ForceImportantDeps && !Start.IsCritical()) + if (Pkg->CurrentVer != 0 && ForceImportantDeps == false && Start.IsCritical() == false) { - bool found=false; - VerIterator instVer = Pkg.CurrentVer(); - if(!instVer.end()) + bool isNewImportantDep = true; + bool isPreviouslySatisfiedImportantDep = false; + for (DepIterator D = Pkg.CurrentVer().DependsList(); D.end() != true; ++D) { - for (DepIterator D = instVer.DependsList(); D.end() != true; D++) - { - //FIXME: deal better with or-groups(?) - DepIterator LocalStart = D; - - if(IsImportantDep(D) && !D.IsCritical() && - Start.TargetPkg() == D.TargetPkg()) - { - if(!isPreviouslySatisfiedImportantDep) - { - DepIterator D2 = D; - while((D2->CompareOp & Dep::Or) != 0) - ++D2; - - isPreviouslySatisfiedImportantDep = - (((*this)[D2] & DepGNow) != 0); - } - - found=true; - } - } - // this is a new dep if it was not found to be already - // a important dep of the installed pacakge - isNewImportantDep = !found; + //FIXME: Should we handle or-group better here? + // We do not check if the package we look for is part of the same or-group + // we might find while searching, but could that really be a problem? + if (D.IsCritical() == true || IsImportantDep(D) == false || + Start.TargetPkg() != D.TargetPkg()) + continue; + + isNewImportantDep = false; + + while ((D->CompareOp & Dep::Or) != 0) + ++D; + + isPreviouslySatisfiedImportantDep = (((*this)[D] & DepGNow) != 0); + if (isPreviouslySatisfiedImportantDep == true) + break; + } + + if(isNewImportantDep == true) + { + if (DebugAutoInstall == true) + std::clog << OutputInDepth(Depth) << "new important dependency: " + << Start.TargetPkg().FullName() << std::endl; + } + else if(isPreviouslySatisfiedImportantDep == true) + { + if (DebugAutoInstall == true) + std::clog << OutputInDepth(Depth) << "previously satisfied important dependency on " + << Start.TargetPkg().FullName() << std::endl; + } + else + { + if (DebugAutoInstall == true) + std::clog << OutputInDepth(Depth) << "ignore old unsatisfied important dependency on " + << Start.TargetPkg().FullName() << std::endl; + continue; } } - if(isNewImportantDep) - if(DebugAutoInstall == true) - std::clog << OutputInDepth(Depth) << "new important dependency: " - << Start.TargetPkg().Name() << std::endl; - if(isPreviouslySatisfiedImportantDep) - if(DebugAutoInstall == true) - std::clog << OutputInDepth(Depth) << "previously satisfied important dependency on " - << Start.TargetPkg().Name() << std::endl; - - // skip important deps if the package is already installed - if (Pkg->CurrentVer != 0 && Start.IsCritical() == false - && !isNewImportantDep && !isPreviouslySatisfiedImportantDep - && !ForceImportantDeps) - continue; - - /* If we are in an or group locate the first or that can - succeed. We have already cached this.. */ - for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; Ors--) - Start++; /* This bit is for processing the possibilty of an install/upgrade - fixing the problem */ - SPtrArray List = Start.AllTargets(); - if (Start->Type != Dep::DpkgBreaks && - (DepState[Start->ID] & DepCVer) == DepCVer) + fixing the problem for "positive" dependencies */ + if (Start.IsNegative() == false && (DepState[Start->ID] & DepCVer) == DepCVer) { - // Right, find the best version to install.. - Version **Cur = List; - PkgIterator P = Start.TargetPkg(); - PkgIterator InstPkg(*Cache,0); - - // See if there are direct matches (at the start of the list) - for (; *Cur != 0 && (*Cur)->ParentPkg == P.Index(); Cur++) + APT::VersionList verlist; + pkgCache::VerIterator Cand = PkgState[Start.TargetPkg()->ID].CandidateVerIter(*this); + if (Cand.end() == false && VS().CheckDep(Cand.VerStr(), Start->CompareOp, Start.TargetVer()) == true) + verlist.insert(Cand); + for (PrvIterator Prv = Start.TargetPkg().ProvidesList(); Prv.end() != true; ++Prv) { - PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg); - if (PkgState[Pkg->ID].CandidateVer != *Cur) + pkgCache::VerIterator V = Prv.OwnerVer(); + pkgCache::VerIterator Cand = PkgState[Prv.OwnerPkg()->ID].CandidateVerIter(*this); + if (Cand.end() == true || V != Cand || + VS().CheckDep(Prv.ProvideVersion(), Start->CompareOp, Start.TargetVer()) == false) continue; - InstPkg = Pkg; - break; + verlist.insert(Cand); } + CompareProviders comp(Start); + APT::VersionList::iterator InstVer = std::max_element(verlist.begin(), verlist.end(), comp); - // Select the highest priority providing package - if (InstPkg.end() == true) - { - pkgPrioSortList(*Cache,Cur); - for (; *Cur != 0; Cur++) - { - PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg); - if (PkgState[Pkg->ID].CandidateVer != *Cur) - continue; - InstPkg = Pkg; - break; - } - } - - if (InstPkg.end() == false) + if (InstVer != verlist.end()) { + pkgCache::PkgIterator InstPkg = InstVer.ParentPkg(); if(DebugAutoInstall == true) std::clog << OutputInDepth(Depth) << "Installing " << InstPkg.Name() << " as " << Start.DepType() << " of " << Pkg.Name() @@ -1268,48 +1191,52 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, // mark automatic dependency MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps); // Set the autoflag, after MarkInstall because MarkInstall unsets it - if (P->CurrentVer == 0) + if (InstPkg->CurrentVer == 0) PkgState[InstPkg->ID].Flags |= Flag::Auto; } } continue; } - - /* For conflicts we just de-install the package and mark as auto, - Conflicts may not have or groups. For dpkg's Breaks we try to - upgrade the package. */ - if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes || - Start->Type == Dep::DpkgBreaks) + /* Negative dependencies have no or-group + If the dependency isn't versioned, we try if an upgrade might solve the problem. + Otherwise we remove the offender if needed */ + else if (Start.IsNegative() == true && Start->Type != pkgCache::Dep::Obsoletes) { + SPtrArray List = Start.AllTargets(); + pkgCache::PkgIterator TrgPkg = Start.TargetPkg(); for (Version **I = List; *I != 0; I++) { VerIterator Ver(*this,*I); PkgIterator Pkg = Ver.ParentPkg(); - if (Start->Type != Dep::DpkgBreaks) - MarkDelete(Pkg,false,Depth + 1, false); - else if (PkgState[Pkg->ID].CandidateVer != *I) - MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps); + /* The List includes all packages providing this dependency, + even providers which are not installed, so skip them. */ + if (PkgState[Pkg->ID].InstallVer == 0) + continue; + + if ((Start->Version != 0 || TrgPkg != Pkg) && + PkgState[Pkg->ID].CandidateVer != PkgState[Pkg->ID].InstallVer && + PkgState[Pkg->ID].CandidateVer != *I && + MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps) == true) + continue; + else if ((Start->Type == pkgCache::Dep::Conflicts || Start->Type == pkgCache::Dep::DpkgBreaks) && + MarkDelete(Pkg,false,Depth + 1, false) == false) + break; } continue; - } + } } + + return Dep.end() == true; } /*}}}*/ // DepCache::IsInstallOk - check if it is ok to install this package /*{{{*/ // --------------------------------------------------------------------- -/* The default implementation just honors dpkg hold - But an application using this library can override this method - to control the MarkInstall behaviour */ +/* The default implementation does nothing. + dpkg holds are enforced by the private IsModeChangeOk */ bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst, unsigned long Depth, bool FromUser) { - if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false) - { - if (DebugMarker == true) - std::clog << OutputInDepth(Depth) << "Hold prevents MarkInstall of " << Pkg << " FU=" << FromUser << std::endl; - return false; - } return true; } /*}}}*/ @@ -1318,19 +1245,39 @@ bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst, /* */ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To) { - ActionGroup group(*this); + if (unlikely(Pkg.end() == true)) + return; - RemoveSizes(Pkg); - RemoveStates(Pkg); - - StateCache &P = PkgState[Pkg->ID]; - if (To == true) - P.iFlags |= ReInstall; + APT::PackageList pkglist; + if (Pkg->CurrentVer != 0 && + (Pkg.CurrentVer()-> MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same) + { + pkgCache::GrpIterator Grp = Pkg.Group(); + for (pkgCache::PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P)) + { + if (P->CurrentVer != 0) + pkglist.insert(P); + } + } else - P.iFlags &= ~ReInstall; - - AddStates(Pkg); - AddSizes(Pkg); + pkglist.insert(Pkg); + + ActionGroup group(*this); + + for (APT::PackageList::const_iterator Pkg = pkglist.begin(); Pkg != pkglist.end(); ++Pkg) + { + RemoveSizes(Pkg); + RemoveStates(Pkg); + + StateCache &P = PkgState[Pkg->ID]; + if (To == true) + P.iFlags |= ReInstall; + else + P.iFlags &= ~ReInstall; + + AddStates(Pkg); + AddSizes(Pkg); + } } /*}}}*/ // DepCache::SetCandidateVersion - Change the candidate version /*{{{*/ @@ -1338,15 +1285,18 @@ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To) /* */ void pkgDepCache::SetCandidateVersion(VerIterator TargetVer) { - ActionGroup group(*this); - pkgCache::PkgIterator Pkg = TargetVer.ParentPkg(); StateCache &P = PkgState[Pkg->ID]; + if (P.CandidateVer == TargetVer) + return; + + ActionGroup group(*this); + RemoveSizes(Pkg); RemoveStates(Pkg); - if (P.CandidateVer == P.InstallVer) + if (P.CandidateVer == P.InstallVer && P.Install() == true) P.InstallVer = (Version *)TargetVer; P.CandidateVer = (Version *)TargetVer; P.Update(Pkg,*this); @@ -1354,8 +1304,173 @@ void pkgDepCache::SetCandidateVersion(VerIterator TargetVer) AddStates(Pkg); Update(Pkg); AddSizes(Pkg); + } + /*}}}*/ +// DepCache::SetCandidateRelease - Change the candidate version /*{{{*/ +// --------------------------------------------------------------------- +/* changes the candidate of a package and walks over all its dependencies + to check if it needs to change the candidate of the dependency, too, + to reach a installable versionstate */ +bool pkgDepCache::SetCandidateRelease(pkgCache::VerIterator TargetVer, + std::string const &TargetRel) +{ + std::list > Changed; + return SetCandidateRelease(TargetVer, TargetRel, Changed); +} +bool pkgDepCache::SetCandidateRelease(pkgCache::VerIterator TargetVer, + std::string const &TargetRel, + std::list > &Changed) +{ + ActionGroup group(*this); + SetCandidateVersion(TargetVer); + + if (TargetRel == "installed" || TargetRel == "candidate") // both doesn't make sense in this context + return true; + + pkgVersionMatch Match(TargetRel, pkgVersionMatch::Release); + // save the position of the last element we will not undo - if we have to + std::list >::iterator newChanged = --(Changed.end()); + + for (pkgCache::DepIterator D = TargetVer.DependsList(); D.end() == false; ++D) + { + if (D->Type != pkgCache::Dep::PreDepends && D->Type != pkgCache::Dep::Depends && + ((D->Type != pkgCache::Dep::Recommends && D->Type != pkgCache::Dep::Suggests) || + IsImportantDep(D) == false)) + continue; + // walk over an or-group and check if we need to do anything + // for simpilicity no or-group is handled as a or-group including one dependency + pkgCache::DepIterator Start = D; + bool itsFine = false; + for (bool stillOr = true; stillOr == true; ++Start) + { + stillOr = (Start->CompareOp & Dep::Or) == Dep::Or; + pkgCache::PkgIterator const P = Start.TargetPkg(); + // virtual packages can't be a solution + if (P.end() == true || (P->ProvidesList == 0 && P->VersionList == 0)) + continue; + pkgCache::VerIterator const Cand = PkgState[P->ID].CandidateVerIter(*this); + // no versioned dependency - but is it installable? + if (Start.TargetVer() == 0 || Start.TargetVer()[0] == '\0') + { + // Check if one of the providers is installable + if (P->ProvidesList != 0) + { + pkgCache::PrvIterator Prv = P.ProvidesList(); + for (; Prv.end() == false; ++Prv) + { + pkgCache::VerIterator const C = PkgState[Prv.OwnerPkg()->ID].CandidateVerIter(*this); + if (C.end() == true || C != Prv.OwnerVer() || + (VersionState(C.DependsList(), DepInstall, DepCandMin, DepCandPolicy) & DepCandMin) != DepCandMin) + continue; + break; + } + if (Prv.end() == true) + continue; + } + // no providers, so check if we have an installable candidate version + else if (Cand.end() == true || + (VersionState(Cand.DependsList(), DepInstall, DepCandMin, DepCandPolicy) & DepCandMin) != DepCandMin) + continue; + itsFine = true; + break; + } + if (Cand.end() == true) + continue; + // check if the current candidate is enough for the versioned dependency - and installable? + if (VS().CheckDep(P.CandVersion(), Start->CompareOp, Start.TargetVer()) == true && + (VersionState(Cand.DependsList(), DepInstall, DepCandMin, DepCandPolicy) & DepCandMin) == DepCandMin) + { + itsFine = true; + break; + } + } + + if (itsFine == true) { + // something in the or-group was fine, skip all other members + for (; (D->CompareOp & Dep::Or) == Dep::Or; ++D); + continue; + } + + // walk again over the or-group and check each if a candidate switch would help + itsFine = false; + for (bool stillOr = true; stillOr == true; ++D) + { + stillOr = (D->CompareOp & Dep::Or) == Dep::Or; + // changing candidate will not help if the dependency is not versioned + if (D.TargetVer() == 0 || D.TargetVer()[0] == '\0') + { + if (stillOr == true) + continue; + break; + } + + pkgCache::VerIterator V; + if (TargetRel == "newest") + V = D.TargetPkg().VersionList(); + else + V = Match.Find(D.TargetPkg()); + + // check if the version from this release could satisfy the dependency + if (V.end() == true || VS().CheckDep(V.VerStr(), D->CompareOp, D.TargetVer()) == false) + { + if (stillOr == true) + continue; + break; + } + + pkgCache::VerIterator oldCand = PkgState[D.TargetPkg()->ID].CandidateVerIter(*this); + if (V == oldCand) + { + // Do we already touched this Version? If so, their versioned dependencies are okay, no need to check again + for (std::list >::const_iterator c = Changed.begin(); + c != Changed.end(); ++c) + { + if (c->first->ParentPkg != V->ParentPkg) + continue; + itsFine = true; + break; + } + } + + if (itsFine == false) + { + // change the candidate + Changed.push_back(make_pair(oldCand, TargetVer)); + if (SetCandidateRelease(V, TargetRel, Changed) == false) + { + if (stillOr == false) + break; + // undo the candidate changing + SetCandidateVersion(oldCand); + Changed.pop_back(); + continue; + } + itsFine = true; + } + + // something in the or-group was fine, skip all other members + for (; (D->CompareOp & Dep::Or) == Dep::Or; ++D); + break; + } + + if (itsFine == false && (D->Type == pkgCache::Dep::PreDepends || D->Type == pkgCache::Dep::Depends)) + { + // undo all changes which aren't lead to a solution + for (std::list >::const_iterator c = ++newChanged; + c != Changed.end(); ++c) + SetCandidateVersion(c->first); + Changed.erase(newChanged, Changed.end()); + return false; + } + } + return true; +} + /*}}}*/ +// DepCache::MarkAuto - set the Auto flag for a package /*{{{*/ +// --------------------------------------------------------------------- +/* */ void pkgDepCache::MarkAuto(const PkgIterator &Pkg, bool Auto) { StateCache &state = PkgState[Pkg->ID]; @@ -1416,25 +1531,26 @@ const char *pkgDepCache::StateCache::StripEpoch(const char *Ver) // --------------------------------------------------------------------- /* The default just returns the highest available version that is not a source and automatic. */ -pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg) +pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator const &Pkg) { /* Not source/not automatic versions cannot be a candidate version unless they are already installed */ VerIterator Last(*(pkgCache *)this,0); - for (VerIterator I = Pkg.VersionList(); I.end() == false; I++) + for (VerIterator I = Pkg.VersionList(); I.end() == false; ++I) { if (Pkg.CurrentVer() == I) return I; - for (VerFileIterator J = I.FileList(); J.end() == false; J++) + for (VerFileIterator J = I.FileList(); J.end() == false; ++J) { if ((J.File()->Flags & Flag::NotSource) != 0) continue; /* Stash the highest version of a not-automatic source, we use it if there is nothing better */ - if ((J.File()->Flags & Flag::NotAutomatic) != 0) + if ((J.File()->Flags & Flag::NotAutomatic) != 0 || + (J.File()->Flags & Flag::ButAutomaticUpgrades) != 0) { if (Last.end() == true) Last = I; @@ -1451,13 +1567,13 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg) // Policy::IsImportantDep - True if the dependency is important /*{{{*/ // --------------------------------------------------------------------- /* */ -bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) +bool pkgDepCache::Policy::IsImportantDep(DepIterator const &Dep) { if(Dep.IsCritical()) return true; else if(Dep->Type == pkgCache::Dep::Recommends) { - if ( _config->FindB("APT::Install-Recommends", false)) + if (InstallRecommends) return true; // we suport a special mode to only install-recommends for certain // sections @@ -1468,58 +1584,16 @@ bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) return true; } else if(Dep->Type == pkgCache::Dep::Suggests) - return _config->FindB("APT::Install-Suggests", false); + return InstallSuggests; return false; } /*}}}*/ -pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc() /*{{{*/ - : constructedSuccessfully(false) -{ - 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); - delete p; - _error->Error("Regex compilation error for APT::NeverAutoRemove"); - return; - } - - rootSetRegexp.push_back(p); - } - } - - constructedSuccessfully = true; -} - /*}}}*/ -pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc() /*{{{*/ -{ - for(unsigned int i = 0; i < rootSetRegexp.size(); i++) - { - regfree(rootSetRegexp[i]); - delete rootSetRegexp[i]; - } -} - /*}}}*/ -bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg) /*{{{*/ -{ - for(unsigned int i = 0; i < rootSetRegexp.size(); i++) - if (regexec(rootSetRegexp[i], pkg.Name(), 0, 0, 0) == 0) - return true; - - return false; -} +// Policy::GetPriority - Get the priority of the package pin /*{{{*/ +signed short pkgDepCache::Policy::GetPriority(pkgCache::PkgIterator const &Pkg) +{ return 0; }; +signed short pkgDepCache::Policy::GetPriority(pkgCache::PkgFileIterator const &File) +{ return 0; }; /*}}}*/ pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc() /*{{{*/ { @@ -1540,12 +1614,15 @@ bool pkgDepCache::MarkFollowsRecommends() bool pkgDepCache::MarkFollowsSuggests() { - return _config->FindB("APT::AutoRemove::SuggestsImportant", false); + return _config->FindB("APT::AutoRemove::SuggestsImportant", true); } // pkgDepCache::MarkRequired - the main mark algorithm /*{{{*/ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) { + if (_config->Find("APT::Solver", "internal") != "internal") + return true; + bool follow_recommends; bool follow_suggests; bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false); @@ -1572,8 +1649,12 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) { if(!(PkgState[p->ID].Flags & Flag::Auto) || (p->Flags & Flag::Essential) || - userFunc.InRootSet(p)) - + (p->Flags & Flag::Important) || + userFunc.InRootSet(p) || + // be nice even then a required package violates the policy (#583517) + // and do the full mark process also for required packages + (p.CurrentVer().end() != true && + p.CurrentVer()->Priority == pkgCache::State::Required)) { // the package is installed (and set to keep) if(PkgState[p->ID].Keep() && !p.CurrentVer().end()) @@ -1602,10 +1683,11 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, return; VerIterator const currver = pkg.CurrentVer(); - VerIterator const candver = state.CandidateVerIter(*this); VerIterator const instver = state.InstVerIter(*this); #if 0 + VerIterator const candver = state.CandidateVerIter(*this); + // 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 @@ -1648,31 +1730,6 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, if(ver.end() == true) return; - // If the version belongs to a Multi-Arch all package - // we will mark all others in this Group with this version also - // Beware: We compare versions here the lazy way: string comparision - // this is bad if multiple repositories provide different versions - // of the package with an identical version number - but even in this - // case the dependencies are likely the same. - if (ver->MultiArch == pkgCache::Version::All && - strcmp(ver.Arch(true), "all") == 0) - { - GrpIterator G = pkg.Group(); - const char* const VerStr = ver.VerStr(); - for (PkgIterator P = G.FindPkg("any"); - P.end() != true; P = G.NextPkg(P)) - { - for (VerIterator V = P.VersionList(); - V.end() != true; ++V) - { - if (strcmp(VerStr, V.VerStr()) != 0) - continue; - MarkPackage(P, V, follow_recommends, follow_suggests); - break; - } - } - } - for(DepIterator d = ver.DependsList(); !d.end(); ++d) { if(d->Type == Dep::Depends || @@ -1754,7 +1811,7 @@ bool pkgDepCache::Sweep() /*{{{*/ { state.Garbage=true; if(debug_autoremove) - std::cout << "Garbage: " << p.FullName() << std::endl; + std::clog << "Garbage: " << p.FullName() << std::endl; } }