##################################################################### */
/*}}}*/
// Include Files /*{{{*/
-#ifdef __GNUG__
-#pragma implementation "apt-pkg/depcache.h"
-#endif
#include <apt-pkg/depcache.h>
#include <apt-pkg/version.h>
#include <apt-pkg/error.h>
#include <sstream>
#include <set>
+#include <sys/stat.h>
+
#include <apti18n.h>
pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) :
return true;
}
-bool pkgDepCache::writeStateFile(OpProgress *prog)
+bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)
{
if(_config->FindB("Debug::pkgAutoRemove",false))
std::clog << "pkgDepCache::writeStateFile()" << std::endl;
pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname);
if(pkg.end() || pkg.VersionList().end())
continue;
- bool oldAuto = section.FindI("Auto-Installed");
bool newAuto = (PkgState[pkg->ID].Flags & Flag::Auto);
if(_config->FindB("Debug::pkgAutoRemove",false))
std::clog << "Update exisiting AutoInstall info: "
std::clog << "Skipping already written " << pkg.Name() << std::endl;
continue;
}
+ // skip not installed ones if requested
+ if(InstalledOnly && pkg->CurrentVer == 0)
+ continue;
if(_config->FindB("Debug::pkgAutoRemove",false))
std::clog << "Writing new AutoInstall: "
<< pkg.Name() << std::endl;
}
fclose(OutFile);
- // move the outfile over the real file
+ // move the outfile over the real file and set permissions
rename(outfile.c_str(), state.c_str());
+ chmod(state.c_str(), 0644);
return true;
}
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::Obsoletes))
+ (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes))
{
PkgIterator Pkg = Dep.TargetPkg();
// Check the base package
{
/* 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)
+ if (P.OwnerPkg() == Pkg &&
+ (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks))
continue;
// Check if the provides is a hit
/* 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::Obsoletes)
+ if (D->Type == Dep::Conflicts ||
+ D->Type == Dep::DpkgBreaks ||
+ D->Type == Dep::Obsoletes)
State = ~State;
// Add to the group if we are within an or..
Group = 0;
// Invert for Conflicts
- if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+ if (D->Type == Dep::Conflicts ||
+ D->Type == Dep::DpkgBreaks ||
+ D->Type == Dep::Obsoletes)
State = ~State;
}
}
Group = 0;
// Invert for Conflicts
- if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+ if (D->Type == Dep::Conflicts ||
+ D->Type == Dep::DpkgBreaks ||
+ D->Type == Dep::Obsoletes)
State = ~State;
}
}
State = DependencyState(D);
// Invert for Conflicts
- if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
+ if (D->Type == Dep::Conflicts ||
+ D->Type == Dep::DpkgBreaks ||
+ D->Type == Dep::Obsoletes)
State = ~State;
RemoveStates(D.ParentPkg());
// We dont even try to keep virtual packages..
if (Pkg->VersionList == 0)
return;
-
+#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
+ // - this makes sense as default when all Garbage dependencies
+ // are automatically marked for removal (as aptitude does).
+ // setting a package for keep then makes it no longer autoinstalled
+ // for all other use-case this action is rather suprising
if(FromUser && !P.Marked)
P.Flags &= ~Flag::Auto;
+#endif
+
RemoveSizes(Pkg);
RemoveStates(Pkg);
/* This bit is for processing the possibilty of an install/upgrade
fixing the problem */
SPtrArray<Version *> List = Start.AllTargets();
- if ((DepState[Start->ID] & DepCVer) == DepCVer)
+ if (Start->Type != Dep::DpkgBreaks &&
+ (DepState[Start->ID] & DepCVer) == DepCVer)
{
// Right, find the best version to install..
Version **Cur = List;
std::clog << "Installing " << InstPkg.Name()
<< " as dep of " << Pkg.Name()
<< std::endl;
- MarkInstall(InstPkg, true, Depth + 1, false, ForceImportantDeps);
- // Set the autoflag, after MarkInstall because MarkInstall
- // unsets it
- if (P->CurrentVer == 0)
- PkgState[InstPkg->ID].Flags |= Flag::Auto;
+ // now check if we should consider it a automatic dependency or not
+ string sec = _config->Find("APT::Never-MarkAuto-Section","");
+ if(Pkg.Section() && (string(Pkg.Section()) == sec))
+ {
+ if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true)
+ std::clog << "Setting NOT as auto-installed because its a direct dep of a package in section " << sec << std::endl;
+ MarkInstall(InstPkg,true,Depth + 1, true);
+ }
+ else
+ {
+ // mark automatic dependency
+ MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps);
+ // Set the autoflag, after MarkInstall because MarkInstall unsets it
+ if (P->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 */
- if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes)
+ 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)
{
for (Version **I = List; *I != 0; I++)
{
VerIterator Ver(*this,*I);
PkgIterator Pkg = Ver.ParentPkg();
-
- MarkDelete(Pkg);
+
+ if (Start->Type != Dep::DpkgBreaks)
+ MarkDelete(Pkg);
+ else
+ if (PkgState[Pkg->ID].CandidateVer != *I)
+ MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps);
}
continue;
}
string s = _config->Find("APT::Install-Recommends-Section","");
if(s.size() > 0)
{
- const char *sec = Dep.TargetPkg().Section();
+ const char *sec = Dep.ParentVer().Section();
if (sec && strcmp(sec, s.c_str()) == 0)
return true;
}
bool follow_suggests)
{
pkgDepCache::StateCache &state = PkgState[pkg->ID];
+ VerIterator currver = pkg.CurrentVer();
VerIterator candver = state.CandidateVerIter(*this);
VerIterator instver = state.InstVerIter(*this);
}
#endif
- // Ignore versions other than the InstVer, and ignore packages
- // that are already going to be removed or just left uninstalled.
- if(!(ver == instver && !instver.end()))
+ // For packages that are not going to be removed, ignore versions
+ // other than the InstVer. For packages that are going to be
+ // removed, ignore versions other than the current version.
+ if(!(ver == instver && !instver.end()) &&
+ !(ver == currver && instver.end() && !ver.end()))
return;
// if we are marked already we are done
{
StateCache &state=PkgState[p->ID];
+ // skip required packages
+ if (!p.CurrentVer().end() &&
+ (p.CurrentVer()->Priority == pkgCache::State::Required))
+ continue;
+
// if it is not marked and it is installed, it's garbage
- if(!state.Marked && (!p.CurrentVer().end() || state.Install()) &&
- !state.Delete())
+ if(!state.Marked && (!p.CurrentVer().end() || state.Install()))
{
state.Garbage=true;
if(_config->FindB("Debug::pkgAutoRemove",false))