Install zypp-NameReqPrv helper for evaluating testcases.
[platform/upstream/libzypp.git] / tools / zypp-NameReqPrv.cc
1 #define INCLUDE_TESTSETUP_WITHOUT_BOOST
2 #include "zypp/../tests/lib/TestSetup.h"
3 #undef  INCLUDE_TESTSETUP_WITHOUT_BOOST
4
5 #include <algorithm>
6 #include <zypp/PoolQuery.h>
7 #include <zypp/ResObjects.h>
8
9 static std::string appname( "NameReqPrv" );
10
11 #define message cout
12 using std::flush;
13
14 int errexit( const std::string & msg_r = std::string(), int exit_r = 100 )
15 {
16   if ( ! msg_r.empty() )
17   {
18     cerr << endl << msg_r << endl << endl;
19   }
20   return exit_r;
21 }
22
23 int usage( const std::string & msg_r = std::string(), int exit_r = 100 )
24 {
25   if ( ! msg_r.empty() )
26   {
27     cerr << endl << msg_r << endl << endl;
28   }
29   cerr << "Usage: " << appname << " [--root ROOTDIR] [OPTIONS] NAME... [[OPTIONS] NAME...]..." << endl;
30   cerr << "  Load all enabled repositories (no refresh) and search for" << endl;
31   cerr << "  occurrences of NAME (regex) in package names, provides or" << endl;
32   cerr << "  requires." << endl;
33   cerr << "  --root   Load repos from the system located below ROOTDIR. If ROOTDIR" << endl;
34   cerr << "           denotes a sover testcase, the testcase is loaded." << endl;
35   cerr << "  --installed Process installed packages only." << endl;
36   cerr << "  -i/-I    turn on/off case insensitive search (default on)" << endl;
37   cerr << "  -n/-N    turn on/off looking for names       (default on)" << endl;
38   cerr << "  -p/-P    turn on/off looking for provides    (default off)" << endl;
39   cerr << "  -r/-R    turn on/off looking for requires    (default off)" << endl;
40   cerr << "  -c/-C    turn on/off looking for conflicts   (default off)" << endl;
41   cerr << "  -o/-O    turn on/off looking for obsoletes   (default off)" << endl;
42   cerr << "  -m/-M    turn on/off looking for recommends  (default off)" << endl;
43   cerr << "  -s/-S    turn on/off looking for supplements (default off)" << endl;
44   cerr << "  -a       short for -n -p -r" << endl;
45   cerr << "  -A       short for -n -P -R" << endl;
46   cerr << "  -D <pkg> dump dependencies of <pkg>" << endl;
47   cerr << "" << endl;
48   return exit_r;
49 }
50
51 void tableOut( const std::string & s1 = std::string(),
52                const std::string & s2 = std::string(),
53                const std::string & s3 = std::string(),
54                const std::string & s4 = std::string(),
55                const std::string & s5 = std::string() )
56 {
57   message << "  ";
58 #define TABEL(N) static unsigned w##N = 0; if ( ! s##N.empty() ) w##N = std::max( w##N, unsigned(s##N.size()) ); message << str::form( " %-*s ", w##N, s##N.c_str() )
59 #define TABER(N) static unsigned w##N = 0; if ( ! s##N.empty() ) w##N = std::max( w##N, unsigned(s##N.size()) ); message << str::form( " %*s ", w##N, s##N.c_str() )
60   TABER( 1 ); TABEL( 2 ); TABEL( 3 ); TABEL( 4 ); TABEL( 5 );
61 #undef TABEL
62   message << endl;
63 }
64
65
66 ///////////////////////////////////////////////////////////////////
67
68 void dDump( const std::string & spec_r )
69 {
70   message << "DUMP " << spec_r << " {";
71
72   sat::WhatProvides q( Capability::guessPackageSpec( spec_r ) );
73   if ( q.empty() )
74   {
75     message << "}" << endl;
76     return;
77   }
78
79   for ( const auto & el : q )
80   {
81     message << endl << "==============================" << endl << dump(el);
82     if ( isKind<Pattern>(el) )
83     {
84       message << endl << "CONTENT: " << make<Pattern>(el)->contents();
85     }
86   }
87   message << endl << "}" << endl;
88 }
89
90 /******************************************************************
91 **
92 **      FUNCTION NAME : main
93 **      FUNCTION TYPE : int
94 */
95 int main( int argc, char * argv[] )
96 {
97   INT << "===[START]==========================================" << endl;
98   appname = Pathname::basename( argv[0] );
99   --argc,++argv;
100
101   if ( ! argc )
102   {
103     return usage();
104   }
105
106   ///////////////////////////////////////////////////////////////////
107
108   ZConfig::instance();
109   Pathname sysRoot("/");
110   sat::Pool satpool( sat::Pool::instance() );
111
112   if ( argc && (*argv) == std::string("--root") )
113   {
114     --argc,++argv;
115     if ( ! argc )
116       return errexit("--root requires an argument.");
117
118     if ( ! PathInfo( *argv ).isDir() )
119       return errexit("--root requires a directory.");
120
121     sysRoot = *argv;
122     --argc,++argv;
123   }
124
125   bool onlyInstalled( false );
126   if ( argc && (*argv) == std::string("--installed") )
127   {
128     --argc,++argv;
129     onlyInstalled = true;
130   }
131
132   if ( TestSetup::isTestcase( sysRoot ) )
133   {
134     message << str::form( "*** Load Testcase from '%s'", sysRoot.c_str() ) << endl;
135     TestSetup test;
136     test.loadTestcaseRepos( sysRoot );
137     dumpRange( message, satpool.reposBegin(), satpool.reposEnd() ) << endl;
138   }
139   else if ( TestSetup::isTestSetup( sysRoot ) )
140   {
141     message << str::form( "*** Load TestSetup from '%s'", sysRoot.c_str() ) << endl;
142     TestSetup test( sysRoot, Arch_x86_64 );
143     test.loadRepos();
144     dumpRange( message, satpool.reposBegin(), satpool.reposEnd() ) << endl;
145   }
146   else
147   {
148     // a system
149     message << str::form( "*** Load system at '%s'", sysRoot.c_str() ) << endl;
150     if ( true )
151     {
152       message << "*** load target '" << Repository::systemRepoAlias() << "'\t" << endl;
153       getZYpp()->initializeTarget( sysRoot );
154       getZYpp()->target()->load();
155       message << satpool.systemRepo() << endl;
156     }
157
158     if ( !onlyInstalled )
159     {
160       RepoManager repoManager( sysRoot );
161       RepoInfoList repos = repoManager.knownRepositories();
162       for_( it, repos.begin(), repos.end() )
163       {
164         RepoInfo & nrepo( *it );
165
166         if ( ! nrepo.enabled() )
167           continue;
168
169         if ( ! repoManager.isCached( nrepo ) )
170         {
171           message << str::form( "*** omit uncached repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl;
172           continue;
173         }
174
175         message << str::form( "*** load repo '%s'\t", nrepo.name().c_str() ) << flush;
176         try
177         {
178           repoManager.loadFromCache( nrepo );
179           message << satpool.reposFind( nrepo.alias() ) << endl;
180         }
181         catch ( const Exception & exp )
182         {
183           message << exp.asString() + "\n" + exp.historyAsString() << endl;
184           message << str::form( "*** omit broken repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl;
185           continue;
186         }
187       }
188     }
189   }
190
191   ///////////////////////////////////////////////////////////////////
192
193   bool ignorecase       ( true );
194   bool names            ( true );
195   bool provides         ( false );
196   bool requires         ( false );
197   bool conflicts        ( false );
198   bool obsoletes        ( false );
199   bool recommends       ( false );
200   bool supplements      ( false );
201
202   for ( ; argc; --argc,++argv )
203   {
204     if ( (*argv)[0] == '-' )
205     {
206       switch ( (*argv)[1] )
207       {
208         case 'a': names =       true,   requires = provides =   true;   break;
209         case 'A': names =       true,   requires = provides =   false;  break;
210         case 'D':
211           if ( argc > 1 )
212           {
213             --argc,++argv;
214             dDump( *argv );
215           }
216           else
217             return errexit("-D <pkgspec> requires an argument.");
218           break;
219         case 'i': ignorecase =  true;   break;
220         case 'I': ignorecase =  false;  break;
221         case 'n': names =       true;   break;
222         case 'N': names =       false;  break;
223         case 'r': requires =    true;   break;
224         case 'R': requires =    false;  break;
225         case 'p': provides =    true;   break;
226         case 'P': provides =    false;  break;
227         case 'c': conflicts =   true;   break;
228         case 'C': conflicts =   false;  break;
229         case 'o': obsoletes =   true;   break;
230         case 'O': obsoletes =   false;  break;
231         case 'm': recommends =  true;   break;
232         case 'M': recommends =  false;  break;
233         case 's': supplements = true;   break;
234         case 'S': supplements = false;  break;
235       }
236       continue;
237     }
238
239     PoolQuery q;
240     if ( onlyInstalled )
241       q.setInstalledOnly();
242     std::string qstr( *argv );
243
244     if ( *argv == ResKind::product )
245     {
246       q.addKind( ResKind::product );
247     }
248     else if ( *argv == ResKind::patch )
249     {
250       q.addKind( ResKind::patch );
251     }
252     else if ( *argv == ResKind::pattern )
253     {
254       q.addKind( ResKind::pattern );
255     }
256     else
257     {
258       sat::Solvable::SplitIdent ident( qstr );
259       if ( ident.kind() != ResKind::package )
260       {
261         q.addKind( ident.kind() );
262         q.addString( ident.name().asString() );
263       }
264       else
265         q.addString( qstr );
266
267       q.setMatchRegex();
268       q.setCaseSensitive( ! ignorecase );
269
270       if ( names )
271         q.addAttribute( sat::SolvAttr::name );
272       if ( provides )
273         q.addDependency( sat::SolvAttr::provides );
274       if ( requires )
275         q.addDependency( sat::SolvAttr::requires );
276       if ( conflicts )
277         q.addDependency( sat::SolvAttr::conflicts );
278       if ( obsoletes )
279         q.addDependency( sat::SolvAttr::obsoletes );
280       if ( recommends )
281         q.addDependency( sat::SolvAttr::recommends );
282       if ( supplements )
283         q.addDependency( sat::SolvAttr::supplements );
284     }
285
286     message << *argv << " [" << (ignorecase?'i':'_') << (names?'n':'_') << (requires?'r':'_') << (provides?'p':'_')
287     << (conflicts?'c':'_') << (obsoletes?'o':'_') << (recommends?'m':'_') << (supplements?'s':'_') << "] {" << endl;
288
289     for_( it, q.begin(), q.end() )
290     {
291       tableOut( str::numstring( it->id() ), it->asString(),
292                 str::form( "(%d)%s", it->repository().info().priority(), it->repository().name().c_str() ),
293                 it->vendor().asString(),
294                 str::numstring( PoolItem(*it)->buildtime() ) );
295       if ( ! it.matchesEmpty() )
296       {
297         for_( match, it.matchesBegin(), it.matchesEnd() )
298         {
299           tableOut( "", "", "", match->inSolvAttr().asString().substr( 9, 3 )+": " +match->asString() );
300         }
301       }
302     }
303
304     message << "}" << endl;
305   }
306
307   INT << "===[END]============================================" << endl << endl;
308   return 0;
309 }