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