Brought in the GUI
[ntk/apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: apt-cache.cc,v 1.6 1998/07/26 23:11:56 jgg Exp $
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>
30 #include <apt-pkg/init.h>
31 #include <apt-pkg/progress.h>
32 #include <apt-pkg/sourcelist.h>
33
34 #include <iostream.h>
35 #include <fstream.h>
36
37 /*}}}*/
38
39 string CacheFile;
40
41 // SplitArg - Split the triple /*{{{*/
42 // ---------------------------------------------------------------------
43 /* */
44 bool 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
67 return true;
68 }
69 /*}}}*/
70 // DumpPackage - Show a dump of a package record /*{{{*/
71 // ---------------------------------------------------------------------
72 /* */
73 bool DumpPackage(pkgCache &Cache,int argc,char *argv[])
74 {
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;
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;
115 }
116
117 return true;
118 }
119 /*}}}*/
120 // Stats - Dump some nice statistics /*{{{*/
121 // ---------------------------------------------------------------------
122 /* */
123 bool Stats(pkgCache &Cache)
124 {
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 /* */
178 bool Dump(pkgCache &Cache)
179 {
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 */
207 bool DumpAvail(pkgCache &Cache)
208 {
209 unsigned char *Buffer = new unsigned char[Cache.HeaderP->MaxVerFileSize];
210
211 for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++)
212 {
213 if ((I->Flags & pkgCache::Flag::NotSource) != 0)
214 continue;
215
216 if (I.IsOk() == false)
217 {
218 delete [] Buffer;
219 return _error->Error("Package file %s is out of sync.",I.FileName());
220 }
221
222 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
223 if (_error->PendingError() == true)
224 {
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++)
234 {
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 }
248 }
249 }
250 }
251
252 return true;
253 }
254 /*}}}*/
255 // DoAdd - Perform an adding operation /*{{{*/
256 // ---------------------------------------------------------------------
257 /* */
258 bool DoAdd(int argc,char *argv[])
259 {
260 string FileName;
261 string Dist;
262 string Ver;
263
264 // Open the cache
265 FileFd CacheF(CacheFile,FileFd::WriteEmpty);
266 if (_error->PendingError() == true)
267 return false;
268
269 DynamicMMap Map(CacheF,MMap::Public);
270 if (_error->PendingError() == true)
271 return false;
272
273 OpTextProgress Progress;
274 pkgCacheGenerator Gen(Map,Progress);
275 if (_error->PendingError() == true)
276 return false;
277
278 for (int I = 0; I != argc; I++)
279 {
280 Progress.OverallProgress(I,argc,1,"Generating cache");
281 if (SplitArg(argv[I],FileName,Dist,Ver) == false)
282 return false;
283
284 // Do the merge
285 FileFd TagF(FileName.c_str(),FileFd::ReadOnly);
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");
295 }
296
297 Progress.Done();
298 Stats(Gen.GetCache());
299
300 return true;
301 }
302 /*}}}*/
303 // GenCaches - Call the main cache generator /*{{{*/
304 // ---------------------------------------------------------------------
305 /* */
306 bool GenCaches()
307 {
308 OpTextProgress Progress;
309 pkgSourceList List;
310 List.ReadMainList();
311 return pkgMakeStatusCache(List,Progress);
312 }
313 /*}}}*/
314
315 int 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 }
323
324 pkgInitialize(*_config);
325 while (1)
326 {
327 CacheFile = argv[2];
328 if (strcmp(argv[1],"add") == 0)
329 {
330 DoAdd(argc - 3,argv + 3);
331 break;
332 }
333
334 if (strcmp(argv[1],"gencaches") == 0)
335 {
336 GenCaches();
337 break;
338 }
339
340 // Open the cache file
341 FileFd CacheF(CacheFile,FileFd::ReadOnly);
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;
352
353 if (strcmp(argv[1],"showpkg") == 0)
354 {
355 CacheFile = argv[2];
356 DumpPackage(Cache,argc - 3,argv + 3);
357 break;
358 }
359
360 if (strcmp(argv[1],"stats") == 0)
361 {
362 Stats(Cache);
363 break;
364 }
365
366 if (strcmp(argv[1],"dump") == 0)
367 {
368 Dump(Cache);
369 break;
370 }
371
372 if (strcmp(argv[1],"dumpavail") == 0)
373 {
374 DumpAvail(Cache);
375 break;
376 }
377
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 }