|
@@ -0,0 +1,386 @@
|
|
|
|
|
+// -*- mode: cpp; mode: fold -*-
|
|
|
|
|
+// Description /*{{{*/
|
|
|
|
|
+// $Id: apt-cache.cc,v 1.1 1998/07/15 05:56:47 jgg Exp $
|
|
|
|
|
+/* ######################################################################
|
|
|
|
|
+
|
|
|
|
|
+ apt-cache - Manages the cache file.
|
|
|
|
|
+
|
|
|
|
|
+ This program should eventually handle both low and high level
|
|
|
|
|
+ manipulation of the cache file. Depending how far things go it
|
|
|
|
|
+ might get quite a sophisticated UI.
|
|
|
|
|
+
|
|
|
|
|
+ Currently the command line is as follows:
|
|
|
|
|
+ apt-cache add cache file1:dist:ver file2:dist:ver ...
|
|
|
|
|
+ ie:
|
|
|
|
|
+ apt-cache add ./cache Pacakges:hamm:1.0
|
|
|
|
|
+
|
|
|
|
|
+ A usefull feature is 'upgradable' ie
|
|
|
|
|
+ apt-cache upgradable ./cache
|
|
|
|
|
+ will list .debs that should be installed to make all packages the latest
|
|
|
|
|
+ version.
|
|
|
|
|
+
|
|
|
|
|
+ Returns 100 on failure, 0 on success.
|
|
|
|
|
+
|
|
|
|
|
+ ##################################################################### */
|
|
|
|
|
+ /*}}}*/
|
|
|
|
|
+// Include Files /*{{{*/
|
|
|
|
|
+#include <apt-pkg/error.h>
|
|
|
|
|
+#include <apt-pkg/pkgcachegen.h>
|
|
|
|
|
+#include <apt-pkg/deblistparser.h>
|
|
|
|
|
+
|
|
|
|
|
+#include <iostream.h>
|
|
|
|
|
+#include <fstream.h>
|
|
|
|
|
+
|
|
|
|
|
+ /*}}}*/
|
|
|
|
|
+
|
|
|
|
|
+string CacheFile;
|
|
|
|
|
+
|
|
|
|
|
+// SplitArg - Split the triple /*{{{*/
|
|
|
|
|
+// ---------------------------------------------------------------------
|
|
|
|
|
+/* */
|
|
|
|
|
+bool SplitArg(const char *Arg,string &File,string &Dist,string Ver)
|
|
|
|
|
+{
|
|
|
|
|
+ const char *Start = Arg;
|
|
|
|
|
+ const char *I = Arg;
|
|
|
|
|
+ for (;*I != 0 && *I != ':'; I++);
|
|
|
|
|
+ if (*I != ':')
|
|
|
|
|
+ return _error->Error("Malformed argument %s, must be in file:dist:rev form",Arg);
|
|
|
|
|
+ File = string(Start,I - Start);
|
|
|
|
|
+
|
|
|
|
|
+ I++;
|
|
|
|
|
+ Start = I;
|
|
|
|
|
+ for (;*I != 0 && *I != ':'; I++);
|
|
|
|
|
+ if (*I != ':')
|
|
|
|
|
+ return _error->Error("Malformed argument %s, must be in file:dist:rev form",Arg);
|
|
|
|
|
+ Dist = string(Start,I - Start);
|
|
|
|
|
+
|
|
|
|
|
+ I++;
|
|
|
|
|
+ Start = I;
|
|
|
|
|
+ for (;*I != 0 && *I != ':'; I++);
|
|
|
|
|
+ if (I == Start)
|
|
|
|
|
+ return _error->Error("Malformed argument %s, must be in file:dist:rev form",Arg);
|
|
|
|
|
+ Ver = string(Start,I - Start);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+ /*}}}*/
|
|
|
|
|
+// DoAdd - Perform an adding operation /*{{{*/
|
|
|
|
|
+// ---------------------------------------------------------------------
|
|
|
|
|
+/* */
|
|
|
|
|
+bool DoAdd(int argc,char *argv[])
|
|
|
|
|
+{
|
|
|
|
|
+ string FileName;
|
|
|
|
|
+ string Dist;
|
|
|
|
|
+ string Ver;
|
|
|
|
|
+
|
|
|
|
|
+ File CacheF(CacheFile,File::WriteEmpty);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ DynamicMMap Map(CacheF,MMap::Public);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ pkgCacheGenerator Gen(Map);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ for (int I = 0; I != argc; I++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (SplitArg(argv[I],FileName,Dist,Ver) == false)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ // Do the merge
|
|
|
|
|
+ File TagF(FileName.c_str(),File::ReadOnly);
|
|
|
|
|
+ debListParser Parser(TagF);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+ if (Gen.SelectFile(FileName) == false)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ if (Gen.MergeList(Parser) == false)
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+ /*}}}*/
|
|
|
|
|
+// DumpPackage - Show a dump of a package record /*{{{*/
|
|
|
|
|
+// ---------------------------------------------------------------------
|
|
|
|
|
+/* */
|
|
|
|
|
+bool DumpPackage(int argc,char *argv[])
|
|
|
|
|
+{
|
|
|
|
|
+ File CacheF(CacheFile,File::ReadOnly);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ pkgCache Cache(Map);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ for (int I = 0; I != argc; I++)
|
|
|
|
|
+ {
|
|
|
|
|
+ pkgCache::PkgIterator Pkg = Cache.FindPkg(argv[I]);
|
|
|
|
|
+ if (Pkg.end() == true)
|
|
|
|
|
+ {
|
|
|
|
|
+ _error->Warning("Unable to locate package %s",argv[0]);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ cout << "Package: " << Pkg.Name() << endl;
|
|
|
|
|
+ cout << "Versions: ";
|
|
|
|
|
+ for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
|
|
|
|
|
+ cout << Cur.VerStr() << ',';
|
|
|
|
|
+ cout << endl;
|
|
|
|
|
+
|
|
|
|
|
+ cout << "Reverse Depends: " << endl;
|
|
|
|
|
+ for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
|
|
|
|
|
+ cout << " " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name() << endl;
|
|
|
|
|
+
|
|
|
|
|
+ cout << "Dependencies: " << endl;
|
|
|
|
|
+ for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
|
|
|
|
|
+ {
|
|
|
|
|
+ cout << Cur.VerStr() << " - ";
|
|
|
|
|
+ for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
|
|
|
|
|
+ cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << Dep.TargetVer() << ") ";
|
|
|
|
|
+ cout << endl;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ cout << "Provides: " << endl;
|
|
|
|
|
+ for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
|
|
|
|
|
+ {
|
|
|
|
|
+ cout << Cur.VerStr() << " - ";
|
|
|
|
|
+ for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
|
|
|
|
|
+ cout << Prv.ParentPkg().Name() << " ";
|
|
|
|
|
+ cout << endl;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+ /*}}}*/
|
|
|
|
|
+// Stats - Dump some nice statistics /*{{{*/
|
|
|
|
|
+// ---------------------------------------------------------------------
|
|
|
|
|
+/* */
|
|
|
|
|
+bool Stats(const char *FileName)
|
|
|
|
|
+{
|
|
|
|
|
+ File CacheF(FileName,File::ReadOnly);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ pkgCache Cache(Map);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ cout << "Total Package Names : " << Cache.Head().PackageCount << endl;
|
|
|
|
|
+ pkgCache::PkgIterator I = Cache.PkgBegin();
|
|
|
|
|
+
|
|
|
|
|
+ int Normal = 0;
|
|
|
|
|
+ int Virtual = 0;
|
|
|
|
|
+ int NVirt = 0;
|
|
|
|
|
+ int DVirt = 0;
|
|
|
|
|
+ int Missing = 0;
|
|
|
|
|
+ for (;I.end() != true; I++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (I->VersionList != 0 && I->ProvidesList == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ Normal++;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (I->VersionList != 0 && I->ProvidesList != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ NVirt++;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (I->VersionList == 0 && I->ProvidesList != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Only 1 provides
|
|
|
|
|
+ if (I.ProvidesList()->NextProvides == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ DVirt++;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ Virtual++;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (I->VersionList == 0 && I->ProvidesList == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ Missing++;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ cout << " Normal Packages: " << Normal << endl;
|
|
|
|
|
+ cout << " Pure Virtual Packages: " << Virtual << endl;
|
|
|
|
|
+ cout << " Single Virtual Packages: " << DVirt << endl;
|
|
|
|
|
+ cout << " Mixed Virtual Packages: " << NVirt << endl;
|
|
|
|
|
+ cout << " Missing: " << Missing << endl;
|
|
|
|
|
+
|
|
|
|
|
+ cout << "Total Distinct Versions: " << Cache.Head().VersionCount << endl;
|
|
|
|
|
+ cout << "Total Dependencies: " << Cache.Head().DependsCount << endl;
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+ /*}}}*/
|
|
|
|
|
+// Dump - show everything /*{{{*/
|
|
|
|
|
+// ---------------------------------------------------------------------
|
|
|
|
|
+/* */
|
|
|
|
|
+bool Dump()
|
|
|
|
|
+{
|
|
|
|
|
+ File CacheF(CacheFile,File::ReadOnly);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ pkgCache Cache(Map);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
|
|
|
|
|
+ {
|
|
|
|
|
+ cout << "Package: " << P.Name() << endl;
|
|
|
|
|
+ for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
|
|
|
|
|
+ {
|
|
|
|
|
+ cout << " Version: " << V.VerStr() << endl;
|
|
|
|
|
+ cout << " File: " << V.FileList().File().FileName() << endl;
|
|
|
|
|
+ for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
|
|
|
|
|
+ cout << " Depends: " << D.TargetPkg().Name() << ' ' << D.TargetVer() << endl;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
|
|
|
|
|
+ {
|
|
|
|
|
+ cout << "File: " << F.FileName() << endl;
|
|
|
|
|
+ cout << " Size: " << F->Size << endl;
|
|
|
|
|
+ cout << " ID: " << F->ID << endl;
|
|
|
|
|
+ cout << " Flags: " << F->Flags << endl;
|
|
|
|
|
+ cout << " Time: " << ctime(&F->mtime) << endl;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+ /*}}}*/
|
|
|
|
|
+// DumpAvail - Print out the available list /*{{{*/
|
|
|
|
|
+// ---------------------------------------------------------------------
|
|
|
|
|
+/* This is needed to make dpkg --merge happy */
|
|
|
|
|
+bool DumpAvail()
|
|
|
|
|
+{
|
|
|
|
|
+#if 0
|
|
|
|
|
+ pkgCache Cache(CacheFile,true,true);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ pkgControlCache CCache(Cache);
|
|
|
|
|
+ if (_error->PendingError() == true)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ vector<string> Lines;
|
|
|
|
|
+ Lines.reserve(30);
|
|
|
|
|
+
|
|
|
|
|
+ pkgCache::PkgIterator I = Cache.PkgBegin();
|
|
|
|
|
+ for (;I.end() != true; I++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (I->VersionList == 0)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ pkgSPkgCtrlInfo Inf = CCache[I.VersionList()];
|
|
|
|
|
+ if (Inf.isNull() == true)
|
|
|
|
|
+ return _error->Error("Couldn't locate info record");
|
|
|
|
|
+
|
|
|
|
|
+ // Iterate over each element
|
|
|
|
|
+ pkgPkgCtrlInfo::const_iterator Elm = Inf->begin();
|
|
|
|
|
+ for (; Elm != Inf->end(); Elm++)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Write the tag: value
|
|
|
|
|
+ cout << (*Elm)->Tag() << ": " << (*Elm)->Value() << endl;
|
|
|
|
|
+
|
|
|
|
|
+ // Write the multiline
|
|
|
|
|
+ (*Elm)->GetLines(Lines);
|
|
|
|
|
+ for (vector<string>::iterator j = Lines.begin(); j != Lines.end(); j++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if ((*j).length() == 0)
|
|
|
|
|
+ cout << " ." << endl;
|
|
|
|
|
+ else
|
|
|
|
|
+ cout << " " << *j << endl;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Lines.erase(Lines.begin(),Lines.end());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ cout << endl;
|
|
|
|
|
+ }
|
|
|
|
|
+#endif
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+ /*}}}*/
|
|
|
|
|
+
|
|
|
|
|
+int main(int argc, char *argv[])
|
|
|
|
|
+{
|
|
|
|
|
+ // Check arguments.
|
|
|
|
|
+ if (argc < 3)
|
|
|
|
|
+ {
|
|
|
|
|
+ cerr << "Usage is apt-cache add cache file1:dist:ver file2:dist:ver ..." << endl;
|
|
|
|
|
+ return 100;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ while (1)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (strcmp(argv[1],"add") == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ CacheFile = argv[2];
|
|
|
|
|
+ if (DoAdd(argc - 3,argv + 3) == true)
|
|
|
|
|
+ Stats(argv[2]);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (strcmp(argv[1],"showpkg") == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ CacheFile = argv[2];
|
|
|
|
|
+ DumpPackage(argc - 3,argv + 3);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (strcmp(argv[1],"stats") == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ Stats(argv[2]);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (strcmp(argv[1],"dump") == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ CacheFile = argv[2];
|
|
|
|
|
+ Dump();
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (strcmp(argv[1],"dumpavail") == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ CacheFile = argv[2];
|
|
|
|
|
+ DumpAvail();
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _error->Error("Invalid operation %s", argv[1]);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Print any errors or warnings found during parsing
|
|
|
|
|
+ if (_error->empty() == false)
|
|
|
|
|
+ {
|
|
|
|
|
+ _error->DumpErrors();
|
|
|
|
|
+ return 100;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|