Cache a PkgIterator for each package to install
[mspang/inapt.git] / inapt.cc
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <iostream>
4 #include <cstdio>
5 #include <fstream>
6 #include <apt-pkg/pkgcache.h>
7 #include <apt-pkg/cachefile.h>
8 #include <apt-pkg/dpkgdb.h>
9 #include <apt-pkg/progress.h>
10 #include <apt-pkg/init.h>
11 #include <apt-pkg/error.h>
12 #include <apt-pkg/algorithms.h>
13 #include <apt-pkg/sptr.h>
14 #include <apt-pkg/acquire-item.h>
15
16 #include "inapt.h"
17 #include "util.h"
18 #include "acqprogress.h"
19
20 using namespace std;
21
22 bool InstallPackages(pkgCacheFile &Cache,bool ShwKept = false,bool Ask = true,
23                      bool Safety = true)
24 {
25    if (_config->FindB("APT::Get::Purge",false) == true)
26    {
27       pkgCache::PkgIterator I = Cache->PkgBegin();
28       for (; I.end() == false; I++)
29       {
30          if (I.Purge() == false && Cache[I].Mode == pkgDepCache::ModeDelete)
31             Cache->MarkDelete(I,true);
32       }
33    }
34
35    if (Cache->BrokenCount() != 0)
36    {
37       return _error->Error("Internal error, InstallPackages was called with broken packages!");
38    }
39
40    if (Cache->DelCount() == 0 && Cache->InstCount() == 0 &&
41        Cache->BadCount() == 0)
42       return true;
43
44    if (Cache->DelCount() != 0 && _config->FindB("APT::Get::Remove",true) == false)
45       return _error->Error(("Packages need to be removed but remove is disabled."));
46
47    pkgRecords Recs(Cache);
48    if (_error->PendingError() == true)
49       return false;
50
51    FileFd Lock;
52    if (_config->FindB("Debug::NoLocking",false) == false &&
53        _config->FindB("APT::Get::Print-URIs") == false)
54    {
55       Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
56       if (_error->PendingError() == true)
57          return _error->Error(("Unable to lock the download directory"));
58    }
59
60    unsigned int width = 80;
61    AcqTextStatus status (width, 0);
62    pkgAcquire Fetcher (&status);
63
64    pkgSourceList List;
65    if (List.ReadMainList() == false)
66       return _error->Error(("The list of sources could not be read."));
67
68    SPtr<pkgPackageManager> PM= _system->CreatePM(Cache);
69    if (PM->GetArchives(&Fetcher, &List, &Recs) == false ||
70        _error->PendingError() == true)
71       return false;
72
73    if (_error->PendingError() == true)
74       return false;
75
76    while (1)
77    {
78       bool Transient = false;
79       if (_config->FindB("APT::Get::Download",true) == false)
80       {
81          for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd();)
82          {
83             if ((*I)->Local == true)
84             {
85                I++;
86                continue;
87             }
88
89             // Close the item and check if it was found in cache
90             (*I)->Finished();
91             if ((*I)->Complete == false)
92                Transient = true;
93
94             // Clear it out of the fetch list
95             delete *I;
96             I = Fetcher.ItemsBegin();
97          }
98       }
99
100       if (Fetcher.Run() == pkgAcquire::Failed)
101          return false;
102
103       // Print out errors
104       bool Failed = false;
105       for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
106       {
107          if ((*I)->Status == pkgAcquire::Item::StatDone &&
108              (*I)->Complete == true)
109             continue;
110
111          if ((*I)->Status == pkgAcquire::Item::StatIdle)
112          {
113             Transient = true;
114             // Failed = true;
115             continue;
116          }
117
118          fprintf(stderr,("Failed to fetch %s  %s\n"),(*I)->DescURI().c_str(),
119                  (*I)->ErrorText.c_str());
120          Failed = true;
121       }
122
123       /* If we are in no download mode and missing files and there were
124          'failures' then the user must specify -m. Furthermore, there
125          is no such thing as a transient error in no-download mode! */
126       if (Transient == true &&
127           _config->FindB("APT::Get::Download",true) == false)
128       {
129          Transient = false;
130          Failed = true;
131       }
132
133       if (_config->FindB("APT::Get::Download-Only",false) == true)
134       {
135          if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false)
136             return _error->Error(("Some files failed to download"));
137          //c1out << _("Download complete and in download only mode") << endl;
138          return true;
139       }
140
141       if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false)
142       {
143          return _error->Error(("Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?"));
144       }
145
146       if (Transient == true && Failed == true)
147          return _error->Error(("--fix-missing and media swapping is not currently supported"));
148
149       // Try to deal with missing package files
150       if (Failed == true && PM->FixMissing() == false)
151       {
152          cerr << ("Unable to correct missing packages.") << endl;
153          return _error->Error(("Aborting install."));
154       }
155
156       _system->UnLock();
157       int status_fd = _config->FindI("APT::Status-Fd",-1);
158       pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd);
159       if (Res == pkgPackageManager::Failed || _error->PendingError() == true)
160          return false;
161       if (Res == pkgPackageManager::Completed)
162          return true;
163
164       // Reload the fetcher object and loop again for media swapping
165       Fetcher.Shutdown();
166       if (PM->GetArchives(&Fetcher,&List,&Recs) == false)
167          return false;
168
169       _system->Lock();
170    }
171 }
172
173 int main(int argc, char *argv[]) {
174
175     vector<inapt_action> actions;
176
177     pkgInitConfig(*_config);
178     pkgInitSystem(*_config, _system);
179
180      _config->Set("Debug::pkgProblemResolver", true);
181
182     OpTextProgress prog;
183     pkgCacheFile cachef;
184
185     if (cachef.Open(prog) == false) {
186         _error->DumpErrors();
187         exit(1);
188     }
189
190     pkgCache *cache = cachef;
191     pkgDepCache *DCache = cachef;
192
193     scanner(&actions);
194
195     for (vector<inapt_action>::iterator i = actions.begin(); i < actions.end(); i++) {
196         debug("finding %s", i->package);
197         pkgCache::PkgIterator pkg = cache->FindPkg(i->package);
198         if (pkg.end())
199             fatal("%s:%d: No such package: %s", i->filename, i->linenum, i->package);
200         i->obj = &pkg;
201     }
202
203     for (vector<inapt_action>::iterator i = actions.begin(); i < actions.end(); i++) {
204         pkgCache::PkgIterator j = *(pkgCache::PkgIterator *)i->obj;
205         switch (i->action) {
206             case inapt_action::INSTALL:
207                 printf("preinstall %s %s:%d\n", i->package, i->filename, i->linenum);
208                 DCache->MarkInstall(j, true);
209                 break;
210             case inapt_action::REMOVE:
211                 break;
212             default:
213                 fatal("uninitialized action");
214         }
215     }
216
217     for (vector<inapt_action>::iterator i = actions.begin(); i < actions.end(); i++) {
218         pkgCache::PkgIterator j = *(pkgCache::PkgIterator *)i->obj;
219         switch (i->action) {
220             case inapt_action::INSTALL:
221                 printf("install %s %s:%d\n", i->package, i->filename, i->linenum);
222                 DCache->MarkInstall(j, false);
223                 break;
224             case inapt_action::REMOVE:
225                 printf("remove %s %s:%d\n", i->package, i->filename, i->linenum);
226                 DCache->MarkDelete(j, false);
227                 break;
228             default:
229                 fatal("uninitialized action");
230         }
231     }
232
233     fprintf(stderr, "\n");
234     fprintf(stderr, "nondownloadable packages:\n");
235     for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++) {
236        if (i.CurrentVer() && !i.CurrentVer().Downloadable()) {
237                fprintf(stderr, "%s ", i.Name());
238                fprintf(stderr, "%s\n", DCache->GetCandidateVer(i).VerStr());
239        }
240     }
241
242     fprintf(stderr, "\n");
243     fprintf(stderr, "inst %lu del %lu keep %lu broken %lu bad %lu\n",
244                     DCache->InstCount(), DCache->DelCount(), DCache->KeepCount(),
245                     DCache->BrokenCount(), DCache->BadCount());
246
247     for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++) {
248        if ((*DCache)[i].Install())
249          fprintf(stderr, "inst %s\n", i.Name());
250        if ((*DCache)[i].InstBroken())
251          fprintf(stderr, "instbroken %s\n", i.Name());
252        if ((*DCache)[i].NowBroken())
253          fprintf(stderr, "nowbroken %s\n", i.Name());
254     }
255
256     fprintf(stderr, "\n");
257
258     pkgProblemResolver fix (DCache);
259
260     for (vector<inapt_action>::iterator i = actions.begin(); i < actions.end(); i++)
261             fix.Protect(cache->FindPkg(i->package));
262     for (vector<inapt_action>::iterator i = actions.begin(); i < actions.end(); i++)
263             fix.Protect(cache->FindPkg(i->package));
264     fix.Resolve();
265
266     fprintf(stderr, "\n");
267     fprintf(stderr, "inst %lu del %lu keep %lu broken %lu bad %lu\n",
268                     DCache->InstCount(), DCache->DelCount(), DCache->KeepCount(),
269                     DCache->BrokenCount(), DCache->BadCount());
270     for (pkgCache::PkgIterator i = cache->PkgBegin(); !i.end(); i++) {
271        if ((*DCache)[i].Install())
272          fprintf(stderr, "inst %s\n", i.Name());
273        if ((*DCache)[i].Delete())
274          fprintf(stderr, "del %s\n", i.Name());
275        if ((*DCache)[i].InstBroken())
276          fprintf(stderr, "instbroken %s\n", i.Name());
277        if ((*DCache)[i].NowBroken())
278          fprintf(stderr, "nowbroken %s\n", i.Name());
279     }
280
281     fprintf(stderr, "\n");
282
283     InstallPackages(cachef);
284 }