1 #define INCLUDE_TESTSETUP_WITHOUT_BOOST
2 #include "../tests/lib/TestSetup.h"
3 #undef INCLUDE_TESTSETUP_WITHOUT_BOOST
6 #include <zypp/PoolQuery.h>
7 #include <zypp/ResObjects.h>
8 #include <zypp/ui/SelectableTraits.h>
10 static std::string appname( "NameReqPrv" );
15 int errexit( const std::string & msg_r = std::string(), int exit_r = 100 )
17 if ( ! msg_r.empty() )
19 cerr << endl << msg_r << endl << endl;
24 int usage( const std::string & msg_r = std::string(), int exit_r = 100 )
26 if ( ! msg_r.empty() )
28 cerr << endl << msg_r << endl << endl;
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;
53 #define COL_R "\033[0;31m"
54 #define COL_G "\033[0;32m"
55 #define COL_B "\033[0;34m"
56 #define COL_C "\033[0;36m"
57 #define COL_M "\033[0;35m"
58 #define COL_Y "\033[0;33m"
59 #define COL_BL "\033[0;30m"
60 #define COL_WH "\033[1;37m"
61 #define COL_OFF "\033[0m"
66 bool operator()( const sat::Solvable & lhs, const sat::Solvable & rhs ) const
69 bool l = lhs.isSystem();
70 bool r = rhs.isSystem();
75 IdString l { lhs.ident() };
76 IdString r { rhs.ident() };
80 return avo( PoolItem(lhs), PoolItem(rhs) );
81 return lhs.id() > rhs.id();
84 ui::SelectableTraits::AVOrder avo;
89 using ResultLInes = std::set<std::string>;
91 ResultLInes & row( const sat::Solvable & solv_r )
94 smax( _maxNAME, solv_r.ident().size() + solv_r.edition().size() + solv_r.arch().size() );
95 smax( _maxREPO, solv_r.repository().name().size(), solv_r.repository().name() );
97 //smax( _maxVEND, solv_r.vendor().size() );
101 void row( PoolQuery::const_iterator it_r )
103 ResultLInes & details { row( *it_r ) };
104 for_( match, it_r.matchesBegin(), it_r.matchesEnd() ) {
105 std::string ent { match->inSolvAttr().asString().substr( 9, 3 )+": " +match->asString() };
106 if ( match->inSolvAttr() == sat::SolvAttr::requires
107 && match->inSolvable().prerequires().contains( Capability(match->id()) ) ) {
108 static const char * pre = " " COL_C "[PRE]" COL_OFF;
112 details.insert( std::move(ent) );
116 std::ostream & dumpOn( std::ostream & str ) const
121 #define argSID _maxSID, slv.id()
123 #define fmtNAME COL_B "%s" COL_OFF "-" COL_G "%s" COL_OFF ".%-*s"
124 #define argNAME slv.ident().c_str(), slv.edition().c_str(), _maxNAME-slv.ident().size()-slv.edition().size(), slv.arch().c_str()
126 #define fmtREPO "(%2d)%-*s"
127 #define argREPO slv.repository().info().priority(), _maxREPO, slv.repository().name().c_str()
129 #define fmtTIME "%10ld"
130 #define argTIME time_t( slv.isSystem() ? slv.installtime() : slv.buildtime() )
133 #define argVEND slv.vendor().c_str()
135 std::string dind( _maxSID + _maxNAME+2/*-.*/ + 2*strlen(S), ' ' );
137 for ( const auto & el : _map ) {
138 sat::Solvable slv { el.first };
139 const char * tagCol = slv.isSystem() ? COL_M : ui::Selectable::get(slv)->identicalInstalled(PoolItem(slv)) ? COL_C : "";
141 str << str::form( "%s" fmtSID S fmtNAME S "%s" fmtREPO S fmtTIME S fmtVEND COL_OFF "\n",
142 tagCol, argSID, argNAME, tagCol, argREPO, argTIME, argVEND );
144 for ( const auto & d : el.second )
145 str << dind << d << endl;
151 static void smax( unsigned & var_r, unsigned val_r, std::string_view n = {} )
152 { if ( val_r > var_r ) var_r = val_r; }
155 unsigned _maxSID = 7; // size + indent
156 unsigned _maxNAME = 0;
157 unsigned _maxREPO = 0;
158 //unsigned _maxTIME = 10;
159 //unsigned _maxVEND = 0;
160 std::map<sat::Solvable, ResultLInes, PQSort> _map;
163 inline std::ostream & operator<<( std::ostream & str, const Table & table_r )
164 { return table_r.dumpOn( str ); }
166 ///////////////////////////////////////////////////////////////////
168 void dDump( const std::string & spec_r )
170 message << "DUMP " << spec_r << " {";
172 sat::WhatProvides q( Capability::guessPackageSpec( spec_r ) );
175 message << "}" << endl;
179 for ( const auto & el : q )
181 message << endl << "==============================" << endl << dump(el);
182 if ( isKind<Product>(el) )
184 message << endl << "REPLACES: " << make<Product>(el)->replacedProducts();
186 else if ( isKind<Pattern>(el) )
188 message << endl << "CONTENT: " << make<Pattern>(el)->contents();
190 else if ( isKind<Patch>(el) )
192 message << endl << "STATUS: " << PoolItem(el);
195 message << endl << "}" << endl;
198 ///////////////////////////////////////////////////////////////////
200 void dTree( const std::string & cmd_r, const std::string & spec_r )
202 message << "tree " << spec_r << " {";
204 sat::WhatProvides spec( Capability::guessPackageSpec( spec_r ) );
207 message << "}" << endl;
211 static const std::list<sat::SolvAttr> attrs {
212 sat::SolvAttr::requires,
213 sat::SolvAttr::recommends,
214 sat::SolvAttr::obsoletes,
215 sat::SolvAttr::conflicts,
216 sat::SolvAttr::supplements,
219 std::map<sat::SolvAttr,std::map<sat::Solvable,std::set<std::string>>> result; // solvables recommending provided capability
222 for ( const auto & el : spec )
224 auto & details { t.row( el ) };
225 for ( const auto & cap : el.provides() )
227 //details.push_back( "prv: "+cap.asString() ); // list only matching ones
229 // get attrs matching cap
230 for ( const auto & attr : attrs )
233 q.addDependency( attr, cap );
236 for_( it, q.begin(), q.end() ) {
237 for_( match, it.matchesBegin(), it.matchesEnd() ) {
238 result[attr][*it].insert( match->inSolvAttr().asString().substr( 9, 3 )+": " +match->asString()
239 + " (" + cap.asString() + ")"
246 message << endl << t;
249 for ( const auto & attr : attrs )
251 if ( result[attr].empty() )
254 message << endl << "======== " << attr << " by:" << endl;
256 for ( const auto & el : result[attr] )
258 auto & details { t.row( el.first ) };
259 for ( const auto & cap : el.second )
260 details.insert( cap );
262 message << endl << t << endl;
264 message << "}" << endl;
267 /******************************************************************
269 ** FUNCTION NAME : main
270 ** FUNCTION TYPE : int
272 int main( int argc, char * argv[] )
274 INT << "===[START]==========================================" << endl;
275 appname = Pathname::basename( argv[0] );
283 ///////////////////////////////////////////////////////////////////
286 Pathname sysRoot("/");
287 sat::Pool satpool( sat::Pool::instance() );
289 if ( argc && (*argv) == std::string("--root") )
293 return errexit("--root requires an argument.");
295 if ( ! PathInfo( *argv ).isDir() )
296 return errexit("--root requires a directory.");
302 bool onlyInstalled( false );
303 if ( argc && (*argv) == std::string("--installed") )
306 onlyInstalled = true;
309 if ( TestSetup::isTestcase( sysRoot ) )
311 message << str::form( "*** Load Testcase from '%s'", sysRoot.c_str() ) << endl;
313 test.loadTestcaseRepos( sysRoot );
314 dumpRange( message, satpool.reposBegin(), satpool.reposEnd() ) << endl;
316 else if ( TestSetup::isTestSetup( sysRoot ) )
318 message << str::form( "*** Load TestSetup from '%s'", sysRoot.c_str() ) << endl;
319 const char * astr = getenv( "ZYPP_TESTSUITE_FAKE_ARCH" );
320 if ( !astr || !*astr )
321 astr = getenv( "ZYPP_ARCH" );
322 if ( !astr || !*astr )
324 TestSetup test( sysRoot, Arch( astr ) );
326 dumpRange( message, satpool.reposBegin(), satpool.reposEnd() ) << endl;
331 message << str::form( "*** Load system at '%s'", sysRoot.c_str() ) << endl;
334 message << "*** load target '" << Repository::systemRepoAlias() << "'\t" << endl;
335 getZYpp()->initializeTarget( sysRoot );
336 getZYpp()->target()->load();
337 message << satpool.systemRepo() << endl;
340 if ( !onlyInstalled )
342 RepoManager repoManager( sysRoot );
343 RepoInfoList repos = repoManager.knownRepositories();
344 for_( it, repos.begin(), repos.end() )
346 RepoInfo & nrepo( *it );
348 if ( ! nrepo.enabled() )
351 if ( ! repoManager.isCached( nrepo ) )
353 message << str::form( "*** omit uncached repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl;
357 message << str::form( "*** load repo '%s'\t", nrepo.name().c_str() ) << flush;
360 repoManager.loadFromCache( nrepo );
361 message << satpool.reposFind( nrepo.alias() ) << endl;
363 catch ( const Exception & exp )
365 message << exp.asString() + "\n" + exp.historyAsString() << endl;
366 message << str::form( "*** omit broken repo '%s' (do 'zypper refresh')", nrepo.name().c_str() ) << endl;
372 ///////////////////////////////////////////////////////////////////
374 bool ignorecase ( true );
375 bool matechexact ( false );
376 bool withSrcPackages ( false );
378 bool provides ( false );
379 bool requires ( false );
380 bool conflicts ( false );
381 bool obsoletes ( false );
382 bool recommends ( false );
383 bool supplements ( false );
384 bool enhacements ( false );
387 for ( ; argc; --argc,++argv )
389 if ( (*argv)[0] == '-' )
391 for ( const char * arg = (*argv)+1; *arg != '\0'; ++arg ) // -pr for -p -r
395 case 'a': names = true, requires = provides = true; break;
396 case 'A': names = true, requires = provides = false; break;
404 return errexit("-D <pkgspec> requires an argument.");
409 std::string cmd { *argv };
414 return errexit("-T <pkgspec> requires an argument.");
416 case 'i': ignorecase = true; break;
417 case 'I': ignorecase = false; break;
418 case 'x': matechexact = true; break;
419 case 'n': names = true; break;
420 case 'N': names = false; break;
421 case 'r': requires = true; break;
422 case 'R': requires = false; break;
423 case 'p': provides = true; break;
424 case 'P': provides = false; break;
425 case 'c': conflicts = true; break;
426 case 'C': conflicts = false; break;
427 case 'o': obsoletes = true; break;
428 case 'O': obsoletes = false; break;
429 case 'm': recommends = true; break;
430 case 'M': recommends = false; break;
431 case 's': supplements = true; break;
432 case 'S': supplements = false; break;
433 case 'e': enhacements = true; break;
434 case 'E': enhacements = false; break;
442 q.setInstalledOnly();
443 std::string qstr( *argv );
445 if ( *argv == ResKind::product )
447 q.addKind( ResKind::product );
449 else if ( *argv == ResKind::patch )
451 q.addKind( ResKind::patch );
453 else if ( *argv == ResKind::pattern )
455 q.addKind( ResKind::pattern );
459 sat::Solvable::SplitIdent ident( qstr );
460 if ( ident.kind() != ResKind::package )
462 q.addKind( ident.kind() );
463 q.addString( ident.name().asString() );
472 q.setCaseSensitive( ! ignorecase );
475 q.addAttribute( sat::SolvAttr::name );
478 q.addDependency( sat::SolvAttr::provides );
479 q.addDependency( sat::SolvAttr::provides, Capability(qstr) );
483 q.addDependency( sat::SolvAttr::requires );
484 q.addDependency( sat::SolvAttr::requires, Capability(qstr) );
488 q.addDependency( sat::SolvAttr::conflicts );
489 q.addDependency( sat::SolvAttr::conflicts, Capability(qstr) );
493 q.addDependency( sat::SolvAttr::obsoletes );
494 q.addDependency( sat::SolvAttr::obsoletes, Capability(qstr) );
498 q.addDependency( sat::SolvAttr::recommends );
499 q.addDependency( sat::SolvAttr::recommends, Capability(qstr) );
503 q.addDependency( sat::SolvAttr::supplements );
504 q.addDependency( sat::SolvAttr::supplements, Capability(qstr) );
508 q.addDependency( sat::SolvAttr::enhances );
509 q.addDependency( sat::SolvAttr::enhances, Capability(qstr) );
510 q.addDependency( sat::SolvAttr::suggests );
511 q.addDependency( sat::SolvAttr::suggests, Capability(qstr) );
515 message << *argv << " [" << (ignorecase?'i':'_') << (names?'n':'_') << (requires?'r':'_') << (provides?'p':'_')
516 << (conflicts?'c':'_') << (obsoletes?'o':'_') << (recommends?'m':'_') << (supplements?'s':'_') << (enhacements?'e':'_')
520 for_( it, q.begin(), q.end() )
522 if ( it->isKind( ResKind::srcpackage ) && !withSrcPackages )
526 message << t << "}" << endl;
529 INT << "===[END]============================================" << endl << endl;