Imported Upstream version 17.0.2
[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 #include <zypp/ui/SelectableTraits.h>
9
10 static std::string appname( "NameReqPrv" );
11
12 #define message cout
13 using std::flush;
14
15 int errexit( const std::string & msg_r = std::string(), int exit_r = 100 )
16 {
17   if ( ! msg_r.empty() )
18   {
19     cerr << endl << msg_r << endl << endl;
20   }
21   return exit_r;
22 }
23
24 int usage( const std::string & msg_r = std::string(), int exit_r = 100 )
25 {
26   if ( ! msg_r.empty() )
27   {
28     cerr << endl << msg_r << endl << endl;
29   }
30   cerr << "Usage: " << appname << " [--root ROOTDIR] [OPTIONS] NAME... [[OPTIONS] NAME...]..." << endl;
31   cerr << "  Load all enabled repositories (no refresh) and search for" << endl;
32   cerr << "  occurrences of NAME (regex or -x) in package names or dependencies" << 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 << "  -e/-E    turn on/off looking for enhan./sugg.(default off)" << endl;
45   cerr << "  -a       short for -n -p -r" << endl;
46   cerr << "  -A       short for -n -P -R" << endl;
47   cerr << "  -x       do exact matching (glob) rather than regex (substring)" << endl;
48   cerr << "  -D <pkg> dump dependencies of <pkg>" << endl;
49   cerr << "" << endl;
50   return exit_r;
51 }
52
53 void tableOut( const std::string & s1 = std::string(),
54                const std::string & s2 = std::string(),
55                const std::string & s3 = std::string(),
56                const std::string & s4 = std::string(),
57                const std::string & s5 = std::string() )
58 {
59   message << "  ";
60 #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() )
61 #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() )
62   TABER( 1 ); TABEL( 2 ); TABEL( 3 ); TABEL( 4 ); TABEL( 5 );
63 #undef TABEL
64   message << endl;
65 }
66
67 struct PQSort
68 {
69   // std::less semantic
70   bool operator()( const PoolQuery::const_iterator & lhs, const PoolQuery::const_iterator & rhs ) const
71   {
72     {
73       bool l = lhs->isSystem();
74       bool r = rhs->isSystem();
75       if ( l != r )
76         return r;
77     }
78     {
79       std::string l( lhs->ident().asString() );
80       std::string r( rhs->ident().asString() );
81       if ( l != r )
82         return l < r;
83     }
84     return avo( PoolItem(*lhs), PoolItem(*rhs) );
85     return lhs->id() > rhs->id();
86   }
87
88   ui::SelectableTraits::AVOrder avo;
89 };
90
91 ///////////////////////////////////////////////////////////////////
92
93 void dDump( const std::string & spec_r )
94 {
95   message << "DUMP " << spec_r << " {";
96
97   sat::WhatProvides q( Capability::guessPackageSpec( spec_r ) );
98   if ( q.empty() )
99   {
100     message << "}" << endl;
101     return;
102   }
103
104   for ( const auto & el : q )
105   {
106     message << endl << "==============================" << endl << dump(el);
107     if ( isKind<Product>(el) )
108     {
109       message << endl << "REPLACES: " << make<Product>(el)->replacedProducts();
110     }
111     else if ( isKind<Pattern>(el) )
112     {
113       message << endl << "CONTENT: " << make<Pattern>(el)->contents();
114     }
115   }
116   message << endl << "}" << endl;
117 }
118
119 /******************************************************************
120 **
121 **      FUNCTION NAME : main
122 **      FUNCTION TYPE : int
123 */
124 int main( int argc, char * argv[] )
125 {
126   INT << "===[START]==========================================" << endl;
127   appname = Pathname::basename( argv[0] );
128   --argc,++argv;
129
130   if ( ! argc )
131   {
132     return usage();
133   }
134
135   ///////////////////////////////////////////////////////////////////
136
137   ZConfig::instance();
138   Pathname sysRoot("/");
139   sat::Pool satpool( sat::Pool::instance() );
140
141   if ( argc && (*argv) == std::string("--root") )
142   {
143     --argc,++argv;
144     if ( ! argc )
145       return errexit("--root requires an argument.");
146
147     if ( ! PathInfo( *argv ).isDir() )
148       return errexit("--root requires a directory.");
149
150     sysRoot = *argv;
151     --argc,++argv;
152   }
153
154   bool onlyInstalled( false );
155   if ( argc && (*argv) == std::string("--installed") )
156   {
157     --argc,++argv;
158     onlyInstalled = true;
159   }
160
161   if ( TestSetup::isTestcase( sysRoot ) )
162   {
163     message << str::form( "*** Load Testcase from '%s'", sysRoot.c_str() ) << endl;
164     TestSetup test;
165     test.loadTestcaseRepos( sysRoot );
166     dumpRange( message, satpool.reposBegin(), satpool.reposEnd() ) << endl;
167   }
168   else if ( TestSetup::isTestSetup( sysRoot ) )
169   {
170     message << str::form( "*** Load TestSetup from '%s'", sysRoot.c_str() ) << endl;
171     const char * astr = getenv( "ZYPP_TESTSUITE_FAKE_ARCH" );
172     if ( !astr || !*astr )
173       astr = getenv( "ZYPP_ARCH" );
174     if ( !astr || !*astr )
175       astr = "x86_64";
176     TestSetup test( sysRoot, Arch( astr ) );
177     test.loadRepos();
178     dumpRange( message, satpool.reposBegin(), satpool.reposEnd() ) << endl;
179   }
180   else
181   {
182     // a system
183     message << str::form( "*** Load system at '%s'", sysRoot.c_str() ) << endl;
184     if ( true )
185     {
186       message << "*** load target '" << Repository::systemRepoAlias() << "'\t" << endl;
187       getZYpp()->initializeTarget( sysRoot );
188       getZYpp()->target()->load();
189       message << satpool.systemRepo() << endl;
190     }
191
192     if ( !onlyInstalled )
193     {
194       RepoManager repoManager( sysRoot );
195       RepoInfoList repos = repoManager.knownRepositories();
196       for_( it, repos.begin(), repos.end() )
197       {
198         RepoInfo & nrepo( *it );
199
200         if ( ! nrepo.enabled() )
201           continue;
202
203         if ( ! repoManager.isCached( nrepo ) )
204         {
205           message << str::form( "*** omit uncached repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl;
206           continue;
207         }
208
209         message << str::form( "*** load repo '%s'\t", nrepo.name().c_str() ) << flush;
210         try
211         {
212           repoManager.loadFromCache( nrepo );
213           message << satpool.reposFind( nrepo.alias() ) << endl;
214         }
215         catch ( const Exception & exp )
216         {
217           message << exp.asString() + "\n" + exp.historyAsString() << endl;
218           message << str::form( "*** omit broken repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl;
219           continue;
220         }
221       }
222     }
223   }
224
225   ///////////////////////////////////////////////////////////////////
226
227   bool ignorecase       ( true );
228   bool matechexact      ( false );
229   bool withSrcPackages  ( false );
230   bool names            ( true );
231   bool provides         ( false );
232   bool requires         ( false );
233   bool conflicts        ( false );
234   bool obsoletes        ( false );
235   bool recommends       ( false );
236   bool supplements      ( false );
237   bool enhacements      ( false );
238
239
240   for ( ; argc; --argc,++argv )
241   {
242     if ( (*argv)[0] == '-' )
243     {
244       switch ( (*argv)[1] )
245       {
246         case 'a': names =       true,   requires = provides =   true;   break;
247         case 'A': names =       true,   requires = provides =   false;  break;
248         case 'D':
249           if ( argc > 1 )
250           {
251             --argc,++argv;
252             dDump( *argv );
253           }
254           else
255             return errexit("-D <pkgspec> requires an argument.");
256           break;
257         case 'i': ignorecase =  true;   break;
258         case 'I': ignorecase =  false;  break;
259         case 'x': matechexact = true;   break;
260         case 'n': names =       true;   break;
261         case 'N': names =       false;  break;
262         case 'r': requires =    true;   break;
263         case 'R': requires =    false;  break;
264         case 'p': provides =    true;   break;
265         case 'P': provides =    false;  break;
266         case 'c': conflicts =   true;   break;
267         case 'C': conflicts =   false;  break;
268         case 'o': obsoletes =   true;   break;
269         case 'O': obsoletes =   false;  break;
270         case 'm': recommends =  true;   break;
271         case 'M': recommends =  false;  break;
272         case 's': supplements = true;   break;
273         case 'S': supplements = false;  break;
274         case 'e': enhacements = true;   break;
275         case 'E': enhacements = false;  break;
276       }
277       continue;
278     }
279
280     PoolQuery q;
281     if ( onlyInstalled )
282       q.setInstalledOnly();
283     std::string qstr( *argv );
284
285     if ( *argv == ResKind::product )
286     {
287       q.addKind( ResKind::product );
288     }
289     else if ( *argv == ResKind::patch )
290     {
291       q.addKind( ResKind::patch );
292     }
293     else if ( *argv == ResKind::pattern )
294     {
295       q.addKind( ResKind::pattern );
296     }
297     else
298     {
299       sat::Solvable::SplitIdent ident( qstr );
300       if ( ident.kind() != ResKind::package )
301       {
302         q.addKind( ident.kind() );
303         q.addString( ident.name().asString() );
304       }
305       else
306         q.addString( qstr );
307
308       if ( matechexact )
309         q.setMatchGlob();
310       else
311         q.setMatchRegex();
312       q.setCaseSensitive( ! ignorecase );
313
314       if ( names )
315         q.addAttribute( sat::SolvAttr::name );
316       if ( provides )
317         q.addDependency( sat::SolvAttr::provides, Capability(qstr) );
318       if ( requires )
319         q.addDependency( sat::SolvAttr::requires, Capability(qstr) );
320       if ( conflicts )
321         q.addDependency( sat::SolvAttr::conflicts, Capability(qstr) );
322       if ( obsoletes )
323         q.addDependency( sat::SolvAttr::obsoletes, Capability(qstr) );
324       if ( recommends )
325         q.addDependency( sat::SolvAttr::recommends, Capability(qstr) );
326       if ( supplements )
327         q.addDependency( sat::SolvAttr::supplements, Capability(qstr) );
328       if ( enhacements )
329       {
330         q.addDependency( sat::SolvAttr::enhances, Capability(qstr) );
331         q.addDependency( sat::SolvAttr::suggests, Capability(qstr) );
332       }
333     }
334
335     message << *argv << " [" << (ignorecase?'i':'_') << (names?'n':'_') << (requires?'r':'_') << (provides?'p':'_')
336     << (conflicts?'c':'_') << (obsoletes?'o':'_') << (recommends?'m':'_') << (supplements?'s':'_') << (enhacements?'e':'_')
337     << "] {" << endl;
338
339     std::set<PoolQuery::const_iterator,PQSort> qsorted;
340     for_( it, q.begin(), q.end() )
341       qsorted.insert( it );
342
343     for ( auto && it : qsorted )
344     {
345       if ( it->isKind( ResKind::srcpackage ) && !withSrcPackages )
346         continue;
347
348       tableOut( str::numstring( it->id() ), it->asString(),
349                 str::form( "(%d)%s", it->repository().info().priority(), it->repository().name().c_str() ),
350                 str::numstring( PoolItem(*it)->buildtime() ) );
351       tableOut( "", "",
352                 it->vendor().asString() );
353       if ( ! it.matchesEmpty() )
354       {
355         for_( match, it.matchesBegin(), it.matchesEnd() )
356         {
357           tableOut( "", "", match->inSolvAttr().asString().substr( 9, 3 )+": " +match->asString() );
358         }
359       }
360     }
361
362     message << "}" << endl;
363   }
364
365   INT << "===[END]============================================" << endl << endl;
366   return 0;
367 }