|
@@ -1,6 +1,6 @@
|
|
|
// -*- mode: cpp; mode: fold -*-
|
|
// -*- mode: cpp; mode: fold -*-
|
|
|
// Description /*{{{*/
|
|
// 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
|
|
apt-cache - Manages the cache files
|
|
@@ -25,12 +25,14 @@
|
|
|
#include <apt-pkg/strutl.h>
|
|
#include <apt-pkg/strutl.h>
|
|
|
#include <apt-pkg/pkgrecords.h>
|
|
#include <apt-pkg/pkgrecords.h>
|
|
|
#include <apt-pkg/srcrecords.h>
|
|
#include <apt-pkg/srcrecords.h>
|
|
|
|
|
+#include <apt-pkg/version.h>
|
|
|
#include <config.h>
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <iostream.h>
|
|
#include <iostream.h>
|
|
|
#include <unistd.h>
|
|
#include <unistd.h>
|
|
|
#include <errno.h>
|
|
#include <errno.h>
|
|
|
#include <regex.h>
|
|
#include <regex.h>
|
|
|
|
|
+#include <stdio.h>
|
|
|
/*}}}*/
|
|
/*}}}*/
|
|
|
|
|
|
|
|
pkgCache *GCache = 0;
|
|
pkgCache *GCache = 0;
|
|
@@ -433,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;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
/*}}}*/
|
|
/*}}}*/
|
|
@@ -711,6 +921,7 @@ bool ShowHelp(CommandLine &Cmd)
|
|
|
cout << " show - Show a readable record for the package" << endl;
|
|
cout << " show - Show a readable record for the package" << endl;
|
|
|
cout << " depends - Show raw dependency information for a package" << endl;
|
|
cout << " depends - Show raw dependency information for a package" << endl;
|
|
|
cout << " pkgnames - List the names of all packages" << endl;
|
|
cout << " pkgnames - List the names of all packages" << endl;
|
|
|
|
|
+ cout << " dotty - Generate package graphs for GraphVis" << endl;
|
|
|
cout << endl;
|
|
cout << endl;
|
|
|
cout << "Options:" << endl;
|
|
cout << "Options:" << endl;
|
|
|
cout << " -h This help text." << endl;
|
|
cout << " -h This help text." << endl;
|
|
@@ -764,6 +975,7 @@ int main(int argc,const char *argv[])
|
|
|
{"check",&Check},
|
|
{"check",&Check},
|
|
|
{"search",&Search},
|
|
{"search",&Search},
|
|
|
{"depends",&Depends},
|
|
{"depends",&Depends},
|
|
|
|
|
+ {"dotty",&Dotty},
|
|
|
{"show",&ShowPackage},
|
|
{"show",&ShowPackage},
|
|
|
{"pkgnames",&ShowPkgNames},
|
|
{"pkgnames",&ShowPkgNames},
|
|
|
{0,0}};
|
|
{0,0}};
|