diff options
author | Arch Librarian <arch@canonical.com> | 2004-09-20 16:55:54 +0000 |
---|---|---|
committer | Arch Librarian <arch@canonical.com> | 2004-09-20 16:55:54 +0000 |
commit | 3e94da1bf263d70579c0aba6f1af6ee75700affb (patch) | |
tree | 72330326b7337b23906fb7fa8dcdab9ed2e04e3a /cmdline/apt-cache.cc | |
parent | 5633a7c28bb3f7bdc10a2fba41caaeb4d67c17f4 (diff) |
Dotty
Author: jgg
Date: 2000-05-12 04:00:59 GMT
Dotty
Diffstat (limited to 'cmdline/apt-cache.cc')
-rw-r--r-- | cmdline/apt-cache.cc | 214 |
1 files changed, 213 insertions, 1 deletions
diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 227b13c96..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.42 1999/12/09 07:32:45 jgg Exp $ +// $Id: apt-cache.cc,v 1.43 2000/05/12 04:00:59 jgg Exp $ /* ###################################################################### apt-cache - Manages the cache files @@ -25,12 +25,14 @@ #include <apt-pkg/strutl.h> #include <apt-pkg/pkgrecords.h> #include <apt-pkg/srcrecords.h> +#include <apt-pkg/version.h> #include <config.h> #include <iostream.h> #include <unistd.h> #include <errno.h> #include <regex.h> +#include <stdio.h> /*}}}*/ pkgCache *GCache = 0; @@ -436,6 +438,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; +} + /*}}}*/ // DoAdd - Perform an adding operation /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -711,6 +921,7 @@ bool ShowHelp(CommandLine &Cmd) 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; @@ -764,6 +975,7 @@ int main(int argc,const char *argv[]) {"check",&Check}, {"search",&Search}, {"depends",&Depends}, + {"dotty",&Dotty}, {"show",&ShowPackage}, {"pkgnames",&ShowPkgNames}, {0,0}}; |