source: lliurex-resolver/trunk/fuentes/src/main.cpp @ 1154

Last change on this file since 1154 was 1154, checked in by kbut, 5 years ago

add files

File size: 10.5 KB
Line 
1
2
3#include <iostream>
4#include <fstream>
5#include <iomanip>
6#include <string>
7#include <map>
8#include <vector>
9
10#include <apt-pkg/cachefile.h>
11#include <apt-pkg/pkgcache.h>
12
13using namespace std;
14
15enum class Option {None=0,UseInput=1,UseOutput=2,UseBanned=4,Verbose=8,DumpProvide=16,AddBootstrap=32};
16
17class Application
18{
19        public:
20       
21        map<string,string> bootstrap;
22        map<string,string> depmap;
23        map<string,vector<string> > prvmap;
24        map<string,string> virtuals;
25        vector<pkgCache::DepIterator> multiples;
26        map<string,string> banmap;
27       
28        string filename;
29        bool dump_provide;
30        bool add_bootstrap;
31               
32        pkgCache* cache;
33       
34        /*!
35                Constructor
36                application start point
37        */
38        Application(int argc,char * argv[])
39        {
40       
41                vector<string> targets;
42                vector<string> bad_targets;
43               
44                filename="";
45                dump_provide=false;
46                add_bootstrap=false;
47       
48       
49                if(argc<2)
50                {
51                        PrintUsage();
52                        return;
53                }
54       
55                Option option=Option::None;
56               
57                for(int n=0;n<argc;n++)
58                {
59                        string arg = argv[n];
60                       
61                        if(arg=="-i")
62                        {
63                                option=Option::UseInput;
64                                continue;
65                        }
66                               
67                        if(arg=="-o")
68                        {
69                                option=Option::UseOutput;
70                                continue;
71                        }
72                       
73                        if(arg=="-b")
74                        {
75                                option=Option::UseBanned;
76                                continue;
77                        }
78                       
79                        if(arg=="-p")
80                        {
81                                option=Option::DumpProvide;
82                                dump_provide=true;
83                                continue;
84                        }
85                       
86                        if(arg=="-d")
87                        {
88                                option=Option::AddBootstrap;
89                                add_bootstrap=true;
90                                continue;
91                        }
92                       
93                        switch(option)
94                        {
95                                case Option::UseOutput:
96                                        filename=arg;
97                                break;
98                               
99                                case Option::UseInput:
100                                        targets.push_back(arg);
101                                break;
102                               
103                                case Option::UseBanned:
104                                        banmap[arg]="";
105                                break;
106                        }
107                       
108                       
109                }
110       
111               
112       
113                pkgInitConfig(*_config);
114                pkgInitSystem(*_config, _system);
115
116                pkgCacheFile cache_file;
117                cache = cache_file.GetPkgCache();
118               
119               
120                /* building bootstrap and provide map*/
121                cout<<"* Building cache..."<<endl;
122               
123                for(pkgCache::PkgIterator pkg = cache->PkgBegin();!pkg.end();pkg++)
124                {
125                        if(IsVirtual(pkg))continue;
126                       
127                       
128                        //we just take first available version
129                        pkgCache::VerIterator ver = pkg.VersionList();
130                       
131                        if(ver->Priority == pkgCache::State::Required ||
132                         ver->Priority == pkgCache::State::Important)
133                        {
134                                bootstrap[pkg.Name()]=ver.VerStr();
135                        }
136                       
137                       
138                        for(pkgCache::PrvIterator prv=ver.ProvidesList();!prv.end();prv++)
139                        {
140                               
141                                pkgCache::PkgIterator owner= prv.OwnerPkg();
142                               
143                                string pname = prv.Name();
144                                string oname = pkg.Name();
145                                       
146                                if(pname!=oname)
147                                {
148                                        prvmap[pname].push_back(oname);
149                                }
150                                                       
151                       
152                        }
153                       
154                }
155       
156                //main targets
157                for(string target : targets)
158                {
159                        pkgCache::PkgIterator pkg;
160                        string vname;
161               
162                        try
163                        {
164                                pkg = Find(target);
165                        }
166                        catch(runtime_error e)
167                        {
168                                //package does not exists
169                                bad_targets.push_back(target);
170                                continue;
171                        }
172                       
173                        if(IsVirtual(pkg))
174                        {
175
176                               
177                                try
178                                {
179                                        vname = ResolveProvide(target);
180                                }
181                                catch(runtime_error e)
182                                {
183                                        //no one provide this virtual package
184                                        bad_targets.push_back(target);
185                                        continue;
186                                }
187                               
188                                //using provided name
189                                pkg = Find(vname);
190                               
191                        }
192                       
193                        depmap[pkg.Name()]="";
194                        cout<<"[ 0]->"<<pkg.Name()<<endl;
195                        Build(pkg.VersionList(),1);
196                }                               
197               
198                map<string,pkgCache::DepIterator> newdep;
199               
200               
201                /* solving multiple choices */
202                recompute_multiples:
203                               
204                cout<<"multiple choices:"<<endl;
205               
206               
207                for(pkgCache::DepIterator q : multiples)
208                {
209                        pkgCache::DepIterator dep=q;
210                       
211                        cout<<"* (";
212                       
213                                                       
214                        while(true)
215                        {
216                                string pkgname = dep.TargetPkg().Name();
217                                cout<<pkgname;
218                                                                       
219                                if((dep->CompareOp & pkgCache::Dep::Or)!=pkgCache::Dep::Or)break;
220                                dep++;
221                               
222                                cout<<" | ";
223                        }
224                       
225                        cout<<")"<<endl;
226                       
227                }
228               
229                for(pkgCache::DepIterator q : multiples)
230                {
231                        pkgCache::DepIterator dep=q;
232                       
233                        bool found=false;
234                       
235                        while(true)
236                        {
237                       
238                                string pkgname = dep.TargetPkg().Name();
239                               
240                               
241                                if(depmap.find(pkgname)!=depmap.end())
242                                {
243                                        cout<<"Using "<<pkgname<<" already included"<<endl;
244                                        found=true;
245                                        break;
246                                }
247                               
248                                if(bootstrap.find(pkgname)!=bootstrap.end())
249                                {
250                                        cout<<"Using "<<pkgname<<" from bootstrap"<<endl;
251                                        found=true;
252                                        break;
253                                }
254                               
255                               
256                               
257                               
258                                if((dep->CompareOp & pkgCache::Dep::Or)!=pkgCache::Dep::Or)break;
259                                dep++;
260                        }
261                       
262                        if(!found)
263                        {
264                       
265                                /*
266                                 no choice has be done, let's look for a
267                                 not banned option     
268                                */
269                               
270                                pkgCache::DepIterator t = q;
271                               
272                                while(true)
273                                {
274                               
275                                        string pkgname = t.TargetPkg().Name();
276                                       
277                                        if(banmap.find(pkgname)==banmap.end())
278                                        {
279                                                if(newdep.find(pkgname)==newdep.end())
280                                                {
281                                                        cout<<"Adding "<<pkgname<<endl;
282                                                        newdep[pkgname]=t;
283                                                        break;
284                                                }
285                                                else
286                                                {
287                                                        //already queued for resolve
288                                                        break;
289                                                }
290                                        }
291                                        else
292                                        {
293                                                cout<<"Avoiding "<<pkgname<<endl;
294                                        }
295                                       
296                                        if((t->CompareOp & pkgCache::Dep::Or)!=pkgCache::Dep::Or)break;
297                                        t++;
298                                }
299                               
300                               
301                               
302                               
303                        }                               
304                }
305               
306               
307                multiples.clear();
308               
309               
310                for(pair<string,pkgCache::DepIterator> q: newdep)
311                {
312                        cout<<"* RECOMPUTING: "<<q.first<<endl;
313                       
314                        pkgCache::PkgIterator pkg = q.second.TargetPkg();
315                       
316                        if(IsVirtual(pkg))
317                        {
318                                try
319                                {
320                                        string pkgname=pkg.Name();
321                                        string vname = ResolveProvide(pkgname);
322                                        cout<<pkgname<<" is a virtual package, using "<<vname<<endl;
323
324                                        if(bootstrap.find(vname)==bootstrap.end())
325                                        {
326                                                if(depmap.find(vname)==depmap.end())
327                                                {
328                                                        pkgCache::PkgIterator provider = Find(vname);
329                               
330                                                        depmap[vname]="";
331                                                        Build(provider.VersionList(),0);
332                                                }
333                                        }
334                                }
335                                catch(runtime_error e)
336                                {
337                                        cout<<"Could not find a provide for: "<<pkg.Name()<<endl;
338                                        cout<<pkg.Name()<<" has been banned"<<endl;
339                                        banmap[pkg.Name()]="";
340                                        multiples.push_back(q.second);
341                                }                               
342                               
343                        }
344                        else
345                        {
346                                depmap[pkg.Name()]="";
347                                Build(pkg.VersionList(),0);
348                        }
349                }
350               
351                if(newdep.size()>0)
352                {
353                        newdep.clear();
354                        goto recompute_multiples;
355                }
356
357                //does it ever happen?
358                cout<<"Missing multiples:"<<multiples.size()<<endl;
359               
360                if(bad_targets.size()>0)
361                {
362                        cout<<"Bad inputs:"<<endl;
363                       
364                        for(string target : bad_targets)
365                        {
366                                cout<<"* "<<target<<endl;
367                        }
368                }
369               
370               
371                //bootstrap count is included too
372                int total = depmap.size();
373                if(add_bootstrap)total+=bootstrap.size();
374               
375                cout<<"Total:"<<total<<endl;
376               
377               
378                if(dump_provide)
379                {
380                        if(prvmap.size()>0)
381                        {
382                                cout<<"Provide : Provided from"<<endl;
383                                for(pair<string,vector<string> > p : prvmap)
384                                {
385                                        cout<<"* "<<p.first<<" : ";
386                                        for(string s : p.second)
387                                        {
388                                                cout<<s<<" ";
389                                        }
390                                        cout<<endl;
391                                }
392                                cout<<"Total provides: "<<prvmap.size()<<endl;
393                        }
394                }
395               
396               
397               
398               
399               
400        }
401       
402               
403       
404        /*!
405                Finds a package iterator from apt cache
406                \param pkgname string matching package name
407        */
408        pkgCache::PkgIterator Find(string pkgname)
409        {
410                pkgCache::PkgIterator pkg = cache->FindPkg(pkgname);
411                                       
412                if(pkg.end())throw runtime_error("package does not exists");
413               
414                return pkg;
415        }
416       
417        /*!
418                Recursive dependency build
419                \param ver Version start point
420                \param depth used for debugging, use 0
421        */
422        void Build(pkgCache::VerIterator ver,int depth)
423        {
424               
425       
426                       
427                bool last_or=false;
428               
429                for(pkgCache::DepIterator dep=ver.DependsList();!dep.end();dep++)
430                {
431               
432               
433               
434                        if(dep->Type==pkgCache::Dep::Depends || 
435                        dep->Type==pkgCache::Dep::Recommends ||
436                        dep->Type==pkgCache::Dep::PreDepends
437                        )
438                        {
439                               
440                       
441                                //deferred resolution of multiple choices
442                                if((dep->CompareOp & pkgCache::Dep::Or)==pkgCache::Dep::Or)
443                                {
444                                        if(!last_or)
445                                        {
446                                                last_or=true;
447                                                multiples.push_back(dep);
448                                        }
449                                        continue;
450                                }
451                                else
452                                {
453                                        if(last_or)
454                                        {
455                                                last_or=false;
456                                                continue;
457                                        }
458                                }
459                               
460                                                               
461                               
462                                pkgCache::PkgIterator pkg = dep.TargetPkg();
463                                string pkgname = pkg.Name();
464                                       
465                               
466                                if(IsVirtual(pkg))
467                                {
468                               
469                                        try
470                                        {
471                                                string vname = ResolveProvide(pkgname);
472                                                cout<<pkgname<<" is a virtual package, using "<<vname<<endl;
473                                               
474                                                if(bootstrap.find(vname)==bootstrap.end())
475                                                {
476                                                        if(depmap.find(vname)==depmap.end())
477                                                        {
478                                                                pkgCache::PkgIterator provider = Find(vname);
479
480                                       
481                                                                depmap[vname]="";
482                                                                cout<<"["<<setw(2)<<depth<<"]";
483                                                                for(int n=0;n<depth;n++)cout<<"-";
484                                                                cout<<"->"<<vname<<endl;
485                                                                Build(provider.VersionList(),depth+1);
486                                                        }
487                                                }
488                                        }
489                                        catch(runtime_error e)
490                                        {
491                                                banmap[pkgname]="";
492                                        }
493                                       
494                                }
495                                else
496                                {                               
497                               
498                                        if(depmap.find(pkgname)==depmap.end())
499                                        {
500                                       
501                                                for(pkgCache::VerIterator ver = pkg.VersionList();
502                                                 !ver.end();ver++)
503                                                {
504                                                        if(dep.IsSatisfied(ver))
505                                                        {
506                                               
507                                                                               
508                                                                /* check against bootstrap package list */
509                                                                if(bootstrap.find(pkgname)==bootstrap.end())
510                                                                {
511                                                                        depmap[pkgname]=ver.VerStr();
512                                                                        cout<<"["<<setw(2)<<depth<<"]";
513                                                                        for(int n=0;n<depth;n++)cout<<"-";
514                                                                        cout<<"->"<<pkgname<<endl;
515                                                                        Build(ver,depth+1);
516                                                                }
517                                                                break;
518                                                        }
519                                                }//for
520                                       
521                                        }//if
522                                }//else
523
524                        }//if
525                                               
526                       
527
528                }//for
529               
530               
531               
532               
533               
534        }//method
535       
536       
537        /*!
538                Resolves a provide
539        */
540        string ResolveProvide(string prvname)
541        {
542                string ret="";
543
544                if(virtuals.find(prvname)==virtuals.end())
545                {
546               
547                        if(prvmap.find(prvname)!=prvmap.end())
548                        {
549                                for(string s : prvmap[prvname])
550                                {
551                                        if(depmap.find(s)!=depmap.end())
552                                        {
553                                                ret=s;
554                                                break;
555                                        }
556                                }
557                       
558                                if(ret=="")ret=prvmap[prvname][0];
559                        }
560                       
561                        virtuals[prvname]=ret;
562                }
563                else
564                {
565                        ret = virtuals[prvname];
566                }
567               
568               
569                if(ret=="")throw runtime_error("Could not find provide "+prvname);
570                return ret;
571               
572        }
573       
574        /*!
575                Checks whenever a package is virtual
576        */
577        bool IsVirtual(pkgCache::PkgIterator pkg)
578        {
579                pkgCache::VerIterator ver = pkg.VersionList();
580               
581                return (ver.end());
582        }
583       
584        /*!
585                Dump result
586        */
587        void Dump()
588        {
589       
590               
591                if(filename!="")
592                {
593                        cout<<"Output to: "<<filename<<endl;
594               
595                        fstream f;
596                        f.open(filename,std::fstream::out);
597               
598                        for(pair<string,string> q : depmap)
599                        {
600                                f<<q.first<<"\tinstall"<<endl;
601                        }
602                       
603                        if(add_bootstrap)
604                        {
605                                for(pair<string,string> q : bootstrap)
606                                {
607                                        f<<q.first<<"\tinstall"<<endl;
608                                }
609                        }
610                       
611                        f.close();
612                }
613        }
614       
615       
616        void PrintUsage()
617        {
618                cout<<"usage: "<<endl;
619                cout<<"lliurex-resolver [OPTIONS]"<<endl;
620                cout<<endl;
621               
622                cout<<"Available options:"<<endl;
623                cout<<"-i <targets>\tInput packages"<<endl;
624                cout<<"-o <file>\tOutput file"<<endl;
625                cout<<"-d adds bootstrap to output list"<<endl;
626                cout<<"-b <targets>\tPackages to avoid"<<endl;
627                cout<<"-p\tDumps provide list"<<endl;
628
629        }
630};
631
632
633
634
635
636int main(int argc,char * argv[])
637{
638
639        Application app(argc,argv);
640        app.Dump();
641       
642        return 0;
643}
Note: See TracBrowser for help on using the repository browser.