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