X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/349cd3b8dbb1e218b31443be55933b01042c4acf..3fb71b275346f24cf60e44c27fdccc9083d14cba:/cmdline/apt-cache.cc diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 12d306fc1..5928676de 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: apt-cache.cc,v 1.37 1999/07/15 03:15:49 jgg Exp $ +// $Id: apt-cache.cc,v 1.43 2000/05/12 04:00:59 jgg Exp $ /* ###################################################################### apt-cache - Manages the cache files @@ -24,12 +24,15 @@ #include #include #include +#include +#include #include #include #include #include #include +#include /*}}}*/ pkgCache *GCache = 0; @@ -379,7 +382,7 @@ bool DumpAvail(CommandLine &Cmd) return true; } /*}}}*/ -// Depends - Print out a dependency tree /*{{{*/ +// Depends - Print out a dependency tree /*{{{*/ // --------------------------------------------------------------------- /* */ bool Depends(CommandLine &CmdL) @@ -432,6 +435,214 @@ bool Depends(CommandLine &CmdL) } } + return true; +} + /*}}}*/ +// Dotty - Generate a graph for Dotty /*{{{*/ +// --------------------------------------------------------------------- +/* Dotty is the graphvis program for generating graphs. It is a fairly + simple queuing algorithm that just writes dependencies and nodes. + http://www.research.att.com/sw/tools/graphviz/ */ +bool Dotty(CommandLine &CmdL) +{ + pkgCache &Cache = *GCache; + bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false); + + /* Normal packages are boxes + Pure Provides are triangles + Mixed are diamonds + Hexagons are missing packages*/ + const char *Shapes[] = {"hexagon","triangle","box","diamond"}; + + /* Initialize the list of packages to show. + 1 = To Show + 2 = To Show no recurse + 3 = Emitted no recurse + 4 = Emitted + 0 = None */ + enum States {None=0, ToShow, ToShowNR, DoneNR, Done}; + enum TheFlags {ForceNR=(1<<0)}; + unsigned char *Show = new unsigned char[Cache.Head().PackageCount]; + unsigned char *Flags = new unsigned char[Cache.Head().PackageCount]; + unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount]; + + // Show everything if no arguments given + if (CmdL.FileList[1] == 0) + for (unsigned long I = 0; I != Cache.Head().PackageCount; I++) + Show[I] = ToShow; + else + for (unsigned long I = 0; I != Cache.Head().PackageCount; I++) + Show[I] = None; + memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount); + + // Map the shapes + for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++) + { + if (Pkg->VersionList == 0) + { + // Missing + if (Pkg->ProvidesList == 0) + ShapeMap[Pkg->ID] = 0; + else + ShapeMap[Pkg->ID] = 1; + } + else + { + // Normal + if (Pkg->ProvidesList == 0) + ShapeMap[Pkg->ID] = 2; + else + ShapeMap[Pkg->ID] = 3; + } + } + + // Load the list of packages from the command line into the show list + for (const char **I = CmdL.FileList + 1; *I != 0; I++) + { + // Process per-package flags + string P = *I; + bool Force = false; + if (P.length() > 3) + { + if (P.end()[-1] == '^') + { + Force = true; + P.erase(P.end()-1); + } + + if (P.end()[-1] == ',') + P.erase(P.end()-1); + } + + // Locate the package + pkgCache::PkgIterator Pkg = Cache.FindPkg(P); + if (Pkg.end() == true) + { + _error->Warning("Unable to locate package %s",*I); + continue; + } + Show[Pkg->ID] = ToShow; + + if (Force == true) + Flags[Pkg->ID] |= ForceNR; + } + + // Little header + printf("digraph packages {\n"); + printf("concentrate=true;\n"); + printf("size=\"30,40\";\n"); + + bool Act = true; + while (Act == true) + { + Act = false; + for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++) + { + // See we need to show this package + if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR) + continue; + + // Colour as done + if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR) + { + // Pure Provides and missing packages have no deps! + if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1) + Show[Pkg->ID] = Done; + else + Show[Pkg->ID] = DoneNR; + } + else + Show[Pkg->ID] = Done; + Act = true; + + // No deps to map out + if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR) + continue; + + pkgCache::VerIterator Ver = Pkg.VersionList(); + for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++) + { + // See if anything can meet this dep + // Walk along the actual package providing versions + bool Hit = false; + pkgCache::PkgIterator DPkg = D.TargetPkg(); + for (pkgCache::VerIterator I = DPkg.VersionList(); + I.end() == false && Hit == false; I++) + { + if (pkgCheckDep(D.TargetVer(),I.VerStr(),D->CompareOp) == true) + Hit = true; + } + + // Follow all provides + for (pkgCache::PrvIterator I = DPkg.ProvidesList(); + I.end() == false && Hit == false; I++) + { + if (pkgCheckDep(D.TargetVer(),I.ProvideVersion(),D->CompareOp) == false) + Hit = true; + } + + // Only graph critical deps + if (D.IsCritical() == true) + { + printf("\"%s\" -> \"%s\"",Pkg.Name(),D.TargetPkg().Name()); + + // Colour the node for recursion + if (Show[D.TargetPkg()->ID] <= DoneNR) + { + /* If a conflicts does not meet anything in the database + then show the relation but do not recurse */ + if (Hit == false && D->Type == pkgCache::Dep::Conflicts) + { + if (Show[D.TargetPkg()->ID] == None && + Show[D.TargetPkg()->ID] != ToShow) + Show[D.TargetPkg()->ID] = ToShowNR; + } + else + { + if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow) + Show[D.TargetPkg()->ID] = ToShowNR; + else + Show[D.TargetPkg()->ID] = ToShow; + } + } + + // Edge colour + switch(D->Type) + { + case pkgCache::Dep::Conflicts: + printf("[color=springgreen];\n"); + break; + + case pkgCache::Dep::PreDepends: + printf("[color=blue];\n"); + break; + + default: + printf(";\n"); + break; + } + } + } + } + } + + /* Draw the box colours after the fact since we can not tell what colour + they should be until everything is finished drawing */ + for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++) + { + if (Show[Pkg->ID] < DoneNR) + continue; + + // Orange box for early recursion stoppage + if (Show[Pkg->ID] == DoneNR) + printf("\"%s\" [color=orange,shape=%s];\n",Pkg.Name(), + Shapes[ShapeMap[Pkg->ID]]); + else + printf("\"%s\" [shape=%s];\n",Pkg.Name(), + Shapes[ShapeMap[Pkg->ID]]); + } + + printf("}\n"); return true; } /*}}}*/ @@ -588,12 +799,82 @@ bool ShowPackage(CommandLine &CmdL) } // Find the proper version to use. We should probably use the DepCache. - pkgCache::VerIterator V = Cache.GetCandidateVer(Pkg); - if (V.end() == true || V.FileList().end() == true) + if (_config->FindB("APT::Cache::AllVersions","true") == true) + { + pkgCache::VerIterator V; + for (V = Pkg.VersionList(); V.end() == false; V++) + { + if (DisplayRecord(V) == false) + return false; + } + } + else + { + pkgCache::VerIterator V = Cache.GetCandidateVer(Pkg); + if (V.end() == true || V.FileList().end() == true) + continue; + if (DisplayRecord(V) == false) + return false; + } + } + return true; +} + /*}}}*/ +// ShowPkgNames - Show package names /*{{{*/ +// --------------------------------------------------------------------- +/* This does a prefix match on the first argument */ +bool ShowPkgNames(CommandLine &CmdL) +{ + pkgCache &Cache = *GCache; + pkgCache::PkgIterator I = Cache.PkgBegin(); + bool All = _config->FindB("APT::Cache::AllNames","false"); + + if (CmdL.FileList[1] != 0) + { + for (;I.end() != true; I++) + { + if (All == false && I->VersionList == 0) + continue; + + if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0) + cout << I.Name() << endl; + } + + return true; + } + + // Show all pkgs + for (;I.end() != true; I++) + { + if (All == false && I->VersionList == 0) continue; - if (DisplayRecord(V) == false) - return false; + cout << I.Name() << endl; } + + return true; +} + /*}}}*/ +// ShowSrcPackage - Show source package records /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool ShowSrcPackage(CommandLine &CmdL) +{ + pkgSourceList List; + List.ReadMainList(); + + // Create the text record parsers + pkgSrcRecords SrcRecs(List); + if (_error->PendingError() == true) + return false; + + for (const char **I = CmdL.FileList + 1; *I != 0; I++) + { + SrcRecs.Restart(); + + pkgSrcRecords::Parser *Parse; + while ((Parse = SrcRecs.Find(*I,false)) != 0) + cout << Parse->AsStr(); + } return true; } /*}}}*/ @@ -639,6 +920,8 @@ bool ShowHelp(CommandLine &Cmd) cout << " search - Search the package list for a regex pattern" << endl; cout << " show - Show a readable record for the package" << endl; cout << " depends - Show raw dependency information for a package" << endl; + cout << " pkgnames - List the names of all packages" << endl; + cout << " dotty - Generate package graphs for GraphVis" << endl; cout << endl; cout << "Options:" << endl; cout << " -h This help text." << endl; @@ -672,13 +955,17 @@ int main(int argc,const char *argv[]) {'q',"quiet","quiet",CommandLine::IntLevel}, {'i',"important","APT::Cache::Important",0}, {'f',"full","APT::Cache::ShowFull",0}, + {'g',"no-generate","APT::Cache::NoGenerate",0}, + {'a',"all-versions","APT::Cache::AllVersions",0}, {0,"names-only","APT::Cache::NamesOnly",0}, + {0,"all-names","APT::Cache::AllNames",0}, {'c',"config-file",0,CommandLine::ConfigFile}, {'o',"option",0,CommandLine::ArbItem}, {0,0,0,0}}; CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp}, {"add",&DoAdd}, {"gencaches",&GenCaches}, + {"showsrc",&ShowSrcPackage}, {0,0}}; CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage}, {"stats",&Stats}, @@ -688,7 +975,9 @@ int main(int argc,const char *argv[]) {"check",&Check}, {"search",&Search}, {"depends",&Depends}, + {"dotty",&Dotty}, {"show",&ShowPackage}, + {"pkgnames",&ShowPkgNames}, {0,0}}; CacheInitialize(); @@ -712,14 +1001,24 @@ int main(int argc,const char *argv[]) _config->Set("quiet","1"); if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false) - { - // Open the cache file - pkgSourceList List; - List.ReadMainList(); - - // Generate it and map it - OpProgress Prog; - MMap *Map = pkgMakeStatusCacheMem(List,Prog); + { + MMap *Map; + if (_config->FindB("APT::Cache::NoGenerate",false) == true) + { + Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"), + FileFd::ReadOnly),MMap::Public|MMap::ReadOnly); + } + else + { + // Open the cache file + pkgSourceList List; + List.ReadMainList(); + + // Generate it and map it + OpProgress Prog; + Map = pkgMakeStatusCacheMem(List,Prog); + } + if (_error->PendingError() == false) { pkgCache Cache(*Map);