X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/28166356f30ad13729f7f952e6f1fc6131036591..718f797cef0fb766b6f7cfa1d34b617ad047dbc5:/apt-pkg/depcache.cc?ds=sidebyside diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index fba6ad054..580056687 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -70,7 +70,7 @@ void pkgDepCache::ActionGroup::release() cache.MarkAndSweep(); } - released = false; + released = true; } } @@ -129,7 +129,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); @@ -292,7 +292,7 @@ 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++) { + 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()) { @@ -339,8 +339,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 @@ -366,12 +365,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 (or group) if it is a conflicts. See the comment above. */ - if (P.OwnerPkg()->Group == Pkg->Group && - (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks)) + if (P.OwnerPkg()->Group == Pkg->Group && Dep.IsNegative() == true) continue; // Check if the provides is a hit @@ -549,8 +547,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) @@ -587,16 +585,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.. @@ -607,9 +603,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; } } @@ -631,7 +625,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; @@ -721,15 +715,15 @@ void pkgDepCache::Update(OpProgress *Prog) // Perform the depends pass 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); - 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]; @@ -742,9 +736,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; } } @@ -768,15 +760,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()); @@ -803,13 +793,13 @@ 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()); } /*}}}*/ @@ -819,8 +809,7 @@ void pkgDepCache::Update(PkgIterator const &Pkg) void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser, unsigned long Depth) { - // Simplifies other routines. - if (Pkg.end() == true) + if (IsModeChangeOk(ModeKeep, Pkg, Depth, FromUser) == false) return; /* Reject an attempt to keep a non-source broken installed package, those @@ -828,25 +817,22 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser, if (Pkg.State() == PkgIterator::NeedsUnpack && Pkg.CurrentVer().Downloadable() == false) return; - - /** \todo Can this be moved later in the method? */ - ActionGroup group(*this); /* 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; + 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 @@ -883,30 +869,26 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser, void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, unsigned long Depth, bool FromUser) { - // Simplifies other routines. - if (Pkg.end() == true) + if (IsModeChangeOk(ModeDelete, Pkg, Depth, FromUser) == false) return; - 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; - // 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; + P.iFlags &= ~(AutoKept | Purge); + if (rPurge == true) + P.iFlags |= Purge; + + ActionGroup group(*this); + if (DebugMarker == true) std::clog << OutputInDepth(Depth) << (rPurge ? "MarkPurge " : "MarkDelete ") << Pkg << " FU=" << FromUser << std::endl; @@ -927,19 +909,12 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, /*}}}*/ // 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 (DebugMarker == true) - std::clog << OutputInDepth(Depth) << "Hold prevents MarkDelete of " << Pkg << " FU=" << FromUser << std::endl; - return false; - } - else if (FromUser == false && Pkg->CurrentVer == 0) + if (FromUser == false && Pkg->CurrentVer == 0) { StateCache &P = PkgState[Pkg->ID]; if (P.InstallVer != 0 && P.Status == 2 && (P.Flags & Flag::Auto) != Flag::Auto) @@ -949,6 +924,61 @@ bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge, 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; } /*}}}*/ @@ -959,19 +989,17 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, unsigned long Depth, bool FromUser, bool ForceImportantDeps) { - if (Depth > 100) + if (IsModeChangeOk(ModeInstall, Pkg, Depth, FromUser) == false) return; - - // Simplifies other routines. - if (Pkg.end() == true) + + StateCache &P = PkgState[Pkg->ID]; + + // See if there is even any possible instalation candidate + if (P.CandidateVer == 0) return; - - ActionGroup group(*this); /* 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())) @@ -981,17 +1009,13 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, return; } - // 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; + 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 should have the ability to de-auto a package by changing its state */ @@ -1035,7 +1059,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; @@ -1054,7 +1078,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; + } + /* 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 @@ -1062,57 +1101,49 @@ 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) + { + //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 { - for (DepIterator D = instVer.DependsList(); D.end() != true; D++) - { - //FIXME: deal better with or-groups(?) - 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; + 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 */ @@ -1178,8 +1209,7 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, /* 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) + if (Start.IsNegative() == true) { for (Version **I = List; *I != 0; I++) { @@ -1204,18 +1234,11 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, /*}}}*/ // 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; } /*}}}*/ @@ -1240,11 +1263,6 @@ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To) AddStates(Pkg); AddSizes(Pkg); - - if (unlikely(Pkg.CurrentVer().end() == true)) - return; - - SetReInstall(Pkg.Group().FindPkg("all"), To); } /*}}}*/ // DepCache::SetCandidateVersion - Change the candidate version /*{{{*/ @@ -1504,12 +1522,12 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator const &Pk 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; @@ -1575,7 +1593,7 @@ 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 /*{{{*/