Sync
[ntk/apt.git] / cmdline / apt-cache.cc
CommitLineData
1164783d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
880e9be4 3// $Id: apt-cache.cc,v 1.6 1998/07/26 23:11:56 jgg Exp $
1164783d
AL
4/* ######################################################################
5
6 apt-cache - Manages the cache file.
7
8 This program should eventually handle both low and high level
9 manipulation of the cache file. Depending how far things go it
10 might get quite a sophisticated UI.
11
12 Currently the command line is as follows:
13 apt-cache add cache file1:dist:ver file2:dist:ver ...
14 ie:
15 apt-cache add ./cache Pacakges:hamm:1.0
16
17 A usefull feature is 'upgradable' ie
18 apt-cache upgradable ./cache
19 will list .debs that should be installed to make all packages the latest
20 version.
21
22 Returns 100 on failure, 0 on success.
23
24 ##################################################################### */
25 /*}}}*/
26// Include Files /*{{{*/
27#include <apt-pkg/error.h>
28#include <apt-pkg/pkgcachegen.h>
29#include <apt-pkg/deblistparser.h>
8efa2a3b 30#include <apt-pkg/init.h>
404ec98e 31#include <apt-pkg/progress.h>
880e9be4 32#include <apt-pkg/sourcelist.h>
1164783d
AL
33
34#include <iostream.h>
35#include <fstream.h>
36
37 /*}}}*/
38
39string CacheFile;
40
41// SplitArg - Split the triple /*{{{*/
42// ---------------------------------------------------------------------
43/* */
44bool SplitArg(const char *Arg,string &File,string &Dist,string Ver)
45{
46 const char *Start = Arg;
47 const char *I = Arg;
48 for (;*I != 0 && *I != ':'; I++);
49 if (*I != ':')
50 return _error->Error("Malformed argument %s, must be in file:dist:rev form",Arg);
51 File = string(Start,I - Start);
52
53 I++;
54 Start = I;
55 for (;*I != 0 && *I != ':'; I++);
56 if (*I != ':')
57 return _error->Error("Malformed argument %s, must be in file:dist:rev form",Arg);
58 Dist = string(Start,I - Start);
59
60 I++;
61 Start = I;
62 for (;*I != 0 && *I != ':'; I++);
63 if (I == Start)
64 return _error->Error("Malformed argument %s, must be in file:dist:rev form",Arg);
65 Ver = string(Start,I - Start);
66
1164783d
AL
67 return true;
68}
69 /*}}}*/
70// DumpPackage - Show a dump of a package record /*{{{*/
71// ---------------------------------------------------------------------
72/* */
ad00ae81
AL
73bool DumpPackage(pkgCache &Cache,int argc,char *argv[])
74{
1164783d
AL
75 for (int I = 0; I != argc; I++)
76 {
77 pkgCache::PkgIterator Pkg = Cache.FindPkg(argv[I]);
78 if (Pkg.end() == true)
79 {
80 _error->Warning("Unable to locate package %s",argv[0]);
81 continue;
82 }
83
84 cout << "Package: " << Pkg.Name() << endl;
85 cout << "Versions: ";
86 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
87 cout << Cur.VerStr() << ',';
88 cout << endl;
89
90 cout << "Reverse Depends: " << endl;
91 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
92 cout << " " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name() << endl;
93
94 cout << "Dependencies: " << endl;
95 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
96 {
97 cout << Cur.VerStr() << " - ";
98 for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
99 cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << Dep.TargetVer() << ") ";
100 cout << endl;
101 }
102
103 cout << "Provides: " << endl;
104 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
105 {
106 cout << Cur.VerStr() << " - ";
107 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
108 cout << Prv.ParentPkg().Name() << " ";
109 cout << endl;
8efa2a3b
AL
110 }
111 cout << "Reverse Provides: " << endl;
112 for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
113 cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr();
114 cout << endl;
1164783d
AL
115 }
116
117 return true;
118}
119 /*}}}*/
120// Stats - Dump some nice statistics /*{{{*/
121// ---------------------------------------------------------------------
122/* */
ad00ae81 123bool Stats(pkgCache &Cache)
1164783d 124{
1164783d
AL
125 cout << "Total Package Names : " << Cache.Head().PackageCount << endl;
126 pkgCache::PkgIterator I = Cache.PkgBegin();
127
128 int Normal = 0;
129 int Virtual = 0;
130 int NVirt = 0;
131 int DVirt = 0;
132 int Missing = 0;
133 for (;I.end() != true; I++)
134 {
135 if (I->VersionList != 0 && I->ProvidesList == 0)
136 {
137 Normal++;
138 continue;
139 }
140
141 if (I->VersionList != 0 && I->ProvidesList != 0)
142 {
143 NVirt++;
144 continue;
145 }
146
147 if (I->VersionList == 0 && I->ProvidesList != 0)
148 {
149 // Only 1 provides
150 if (I.ProvidesList()->NextProvides == 0)
151 {
152 DVirt++;
153 }
154 else
155 Virtual++;
156 continue;
157 }
158 if (I->VersionList == 0 && I->ProvidesList == 0)
159 {
160 Missing++;
161 continue;
162 }
163 }
164 cout << " Normal Packages: " << Normal << endl;
165 cout << " Pure Virtual Packages: " << Virtual << endl;
166 cout << " Single Virtual Packages: " << DVirt << endl;
167 cout << " Mixed Virtual Packages: " << NVirt << endl;
168 cout << " Missing: " << Missing << endl;
169
170 cout << "Total Distinct Versions: " << Cache.Head().VersionCount << endl;
171 cout << "Total Dependencies: " << Cache.Head().DependsCount << endl;
172 return true;
173}
174 /*}}}*/
175// Dump - show everything /*{{{*/
176// ---------------------------------------------------------------------
177/* */
ad00ae81 178bool Dump(pkgCache &Cache)
1164783d 179{
1164783d
AL
180 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
181 {
182 cout << "Package: " << P.Name() << endl;
183 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
184 {
185 cout << " Version: " << V.VerStr() << endl;
186 cout << " File: " << V.FileList().File().FileName() << endl;
187 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
188 cout << " Depends: " << D.TargetPkg().Name() << ' ' << D.TargetVer() << endl;
189 }
190 }
191
192 for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
193 {
194 cout << "File: " << F.FileName() << endl;
195 cout << " Size: " << F->Size << endl;
196 cout << " ID: " << F->ID << endl;
197 cout << " Flags: " << F->Flags << endl;
198 cout << " Time: " << ctime(&F->mtime) << endl;
199 }
200
201 return true;
202}
203 /*}}}*/
204// DumpAvail - Print out the available list /*{{{*/
205// ---------------------------------------------------------------------
206/* This is needed to make dpkg --merge happy */
ad00ae81 207bool DumpAvail(pkgCache &Cache)
1164783d 208{
ad00ae81 209 unsigned char *Buffer = new unsigned char[Cache.HeaderP->MaxVerFileSize];
1164783d 210
ad00ae81 211 for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++)
1164783d 212 {
ad00ae81 213 if ((I->Flags & pkgCache::Flag::NotSource) != 0)
1164783d
AL
214 continue;
215
ad00ae81
AL
216 if (I.IsOk() == false)
217 {
218 delete [] Buffer;
219 return _error->Error("Package file %s is out of sync.",I.FileName());
220 }
1164783d 221
8e06abb2 222 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
ad00ae81 223 if (_error->PendingError() == true)
1164783d 224 {
ad00ae81
AL
225 delete [] Buffer;
226 return false;
227 }
228
229 /* Write all of the records from this package file, we search the entire
230 structure to find them */
231 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
232 {
233 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
1164783d 234 {
ad00ae81
AL
235 if (V->FileList == 0)
236 continue;
237 if (V.FileList().File() != I)
238 continue;
239
240 // Read the record and then write it out again.
241 if (PkgF.Seek(V.FileList()->Offset) == false ||
242 PkgF.Read(Buffer,V.FileList()->Size) == false ||
243 write(STDOUT_FILENO,Buffer,V.FileList()->Size) != V.FileList()->Size)
244 {
245 delete [] Buffer;
246 return false;
247 }
1164783d 248 }
1164783d 249 }
ad00ae81
AL
250 }
251
252 return true;
253}
254 /*}}}*/
255// DoAdd - Perform an adding operation /*{{{*/
256// ---------------------------------------------------------------------
257/* */
258bool DoAdd(int argc,char *argv[])
259{
260 string FileName;
261 string Dist;
262 string Ver;
263
264 // Open the cache
8e06abb2 265 FileFd CacheF(CacheFile,FileFd::WriteEmpty);
ad00ae81
AL
266 if (_error->PendingError() == true)
267 return false;
268
269 DynamicMMap Map(CacheF,MMap::Public);
270 if (_error->PendingError() == true)
271 return false;
404ec98e
AL
272
273 OpTextProgress Progress;
274 pkgCacheGenerator Gen(Map,Progress);
ad00ae81
AL
275 if (_error->PendingError() == true)
276 return false;
277
278 for (int I = 0; I != argc; I++)
279 {
404ec98e 280 Progress.OverallProgress(I,argc,1,"Generating cache");
ad00ae81
AL
281 if (SplitArg(argv[I],FileName,Dist,Ver) == false)
282 return false;
1164783d 283
ad00ae81 284 // Do the merge
8e06abb2 285 FileFd TagF(FileName.c_str(),FileFd::ReadOnly);
ad00ae81
AL
286 debListParser Parser(TagF);
287 if (_error->PendingError() == true)
288 return _error->Error("Problem opening %s",FileName.c_str());
289
290 if (Gen.SelectFile(FileName) == false)
291 return _error->Error("Problem with SelectFile");
292
293 if (Gen.MergeList(Parser) == false)
294 return _error->Error("Problem with MergeList");
1164783d 295 }
404ec98e
AL
296
297 Progress.Done();
ad00ae81
AL
298 Stats(Gen.GetCache());
299
1164783d
AL
300 return true;
301}
302 /*}}}*/
880e9be4
AL
303// GenCaches - Call the main cache generator /*{{{*/
304// ---------------------------------------------------------------------
305/* */
306bool GenCaches()
307{
308 OpTextProgress Progress;
309 pkgSourceList List;
310 List.ReadMainList();
311 return pkgMakeStatusCache(List,Progress);
312}
313 /*}}}*/
1164783d
AL
314
315int main(int argc, char *argv[])
316{
317 // Check arguments.
318 if (argc < 3)
319 {
320 cerr << "Usage is apt-cache add cache file1:dist:ver file2:dist:ver ..." << endl;
321 return 100;
322 }
8efa2a3b
AL
323
324 pkgInitialize(*_config);
1164783d
AL
325 while (1)
326 {
ad00ae81 327 CacheFile = argv[2];
1164783d
AL
328 if (strcmp(argv[1],"add") == 0)
329 {
ad00ae81 330 DoAdd(argc - 3,argv + 3);
1164783d
AL
331 break;
332 }
ad00ae81 333
880e9be4
AL
334 if (strcmp(argv[1],"gencaches") == 0)
335 {
336 GenCaches();
337 break;
338 }
339
ad00ae81 340 // Open the cache file
8e06abb2 341 FileFd CacheF(CacheFile,FileFd::ReadOnly);
ad00ae81
AL
342 if (_error->PendingError() == true)
343 break;
344
345 MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
346 if (_error->PendingError() == true)
347 break;
348
349 pkgCache Cache(Map);
350 if (_error->PendingError() == true)
351 break;
1164783d
AL
352
353 if (strcmp(argv[1],"showpkg") == 0)
354 {
355 CacheFile = argv[2];
ad00ae81 356 DumpPackage(Cache,argc - 3,argv + 3);
1164783d
AL
357 break;
358 }
359
360 if (strcmp(argv[1],"stats") == 0)
361 {
ad00ae81 362 Stats(Cache);
1164783d
AL
363 break;
364 }
365
366 if (strcmp(argv[1],"dump") == 0)
367 {
ad00ae81 368 Dump(Cache);
1164783d
AL
369 break;
370 }
371
372 if (strcmp(argv[1],"dumpavail") == 0)
373 {
ad00ae81 374 DumpAvail(Cache);
1164783d
AL
375 break;
376 }
880e9be4 377
1164783d
AL
378 _error->Error("Invalid operation %s", argv[1]);
379 break;
380 }
381
382 // Print any errors or warnings found during parsing
383 if (_error->empty() == false)
384 {
385 _error->DumpErrors();
386 return 100;
387 }
388
389 return 0;
390}