1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/sat/Solvable.cc
14 #include "zypp/base/Logger.h"
15 #include "zypp/base/Gettext.h"
16 #include "zypp/base/Exception.h"
17 #include "zypp/base/Functional.h"
18 #include "zypp/base/Collector.h"
20 #include "zypp/sat/detail/PoolImpl.h"
21 #include "zypp/sat/Solvable.h"
22 #include "zypp/sat/Pool.h"
23 #include "zypp/Repository.h"
24 #include "zypp/OnMediaLocation.h"
28 ///////////////////////////////////////////////////////////////////
30 { /////////////////////////////////////////////////////////////////
31 ///////////////////////////////////////////////////////////////////
33 { /////////////////////////////////////////////////////////////////
35 Solvable::SplitIdent::SplitIdent( IdString ident_r )
40 const char * ident = ident_r.c_str();
41 const char * sep = ::strchr( ident, ':' );
43 // no ':' in package names (hopefully)
46 _kind = ResKind::package;
47 _name = ident_r.asString();
53 // quick check for well known kinds
58 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) _kind = ResKind::K
60 case 'c': OUTS( patch, 5 ); return; break;
61 case 'd': OUTS( product, 7 ); return; break;
62 case 'i': OUTS( script, 6 ); return; break;
63 case 'k': OUTS( package, 7 ); return; break;
64 case 'm': OUTS( atom, 4 ); return; break;
65 case 'p': OUTS( srcpackage, 10 ); return; break;
66 case 's': OUTS( message, 7 ); return; break;
67 case 't': OUTS( pattern, 7 ); return; break;
73 _kind = ResKind( std::string( ident, sep-ident ) );
76 /////////////////////////////////////////////////////////////////
78 const Solvable Solvable::noSolvable;
80 /////////////////////////////////////////////////////////////////
82 ::_Solvable * Solvable::get() const
83 { return myPool().getSolvable( _id ); }
85 #define NO_SOLVABLE_RETURN( VAL ) \
86 ::_Solvable * _solvable( get() ); \
87 if ( ! _solvable ) return VAL
89 Solvable Solvable::nextInPool() const
90 { return Solvable( myPool().getNextId( _id ) ); }
92 Solvable Solvable::nextInRepo() const
94 NO_SOLVABLE_RETURN( noSolvable );
95 for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
97 ::_Solvable * nextS( myPool().getSolvable( next ) );
98 if ( nextS && nextS->repo == _solvable->repo )
100 return Solvable( next );
106 Repository Solvable::repository() const
108 NO_SOLVABLE_RETURN( Repository::noRepository );
109 return Repository( _solvable->repo );
112 bool Solvable::isSystem() const
114 NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
115 return Repository( _solvable->repo ).isSystemRepo();
118 IdString Solvable::ident() const
120 NO_SOLVABLE_RETURN( IdString() );
121 return IdString( _solvable->name );
124 std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
126 NO_SOLVABLE_RETURN( std::string() );
127 const char * s = ::solvable_lookup_str( _solvable, attr.id() );
128 return s ? s : std::string();
131 std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
133 NO_SOLVABLE_RETURN( std::string() );
135 if ( lang_r == Locale::noCode )
137 s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
141 s = ::solvable_lookup_str_lang( _solvable, attr.id(), lang_r.code().c_str() );
143 return s ? s : std::string();
146 unsigned Solvable::lookupNumAttribute( const SolvAttr & attr ) const
148 NO_SOLVABLE_RETURN( 0 );
149 return ::solvable_lookup_num( _solvable, attr.id(), 0 );
152 bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
154 NO_SOLVABLE_RETURN( false );
155 return ::solvable_lookup_bool( _solvable, attr.id() );
158 detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
160 NO_SOLVABLE_RETURN( detail::noId );
161 return ::solvable_lookup_id( _solvable, attr.id() );
164 CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
166 NO_SOLVABLE_RETURN( CheckSum() );
167 detail::IdType chksumtype = 0;
168 const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
171 switch ( chksumtype )
173 case REPOKEY_TYPE_MD5: return CheckSum::md5( s );
174 case REPOKEY_TYPE_SHA1: return CheckSum::sha1( s );
175 case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
177 return CheckSum( std::string(), s ); // try to autodetect
180 OnMediaLocation Solvable::lookupLocation() const
181 //std::string Solvable::lookupLocation( unsigned & medianr ) const
183 NO_SOLVABLE_RETURN( OnMediaLocation() );
184 // medianumber and path
186 char * file = ::solvable_get_location( _solvable, &medianr );
188 return OnMediaLocation();
193 if ( repository().info().type().toEnum() == repo::RepoType::YAST2_e )
195 #warning STILL HARDCODED /suse PREFIX in location
196 // (ma@) loading a susetags repo search for a solvable with attribute
197 // susetags:datadir. this is the prefix. store it in RepoInfo(?).
200 ret.setLocation ( path/file, medianr );
201 ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ), ByteCount::K ) );
202 ret.setChecksum ( lookupCheckSumAttribute( SolvAttr::checksum ) );
203 // Not needed/available for solvables?
204 //ret.setOpenSize ( ByteCount( lookupNumAttribute( SolvAttr::opensize ), ByteCount::K ) );
205 //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
209 ResKind Solvable::kind() const
211 NO_SOLVABLE_RETURN( ResKind() );
212 // detect srcpackages by 'arch'
213 switch ( _solvable->arch )
217 return ResKind::srcpackage;
221 const char * ident = IdString( _solvable->name ).c_str();
222 const char * sep = ::strchr( ident, ':' );
224 // no ':' in package names (hopefully)
226 return ResKind::package;
228 // quick check for well known kinds
229 if ( sep-ident >= 4 )
233 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
235 case 'c': OUTS( patch, 5 ); break;
236 case 'd': OUTS( product, 7 ); break;
237 case 'i': OUTS( script, 6 ); break;
238 case 'k': OUTS( package, 7 ); break;
239 case 'm': OUTS( atom, 4 ); break;
240 case 'p': OUTS( srcpackage, 10 ); break;
241 case 's': OUTS( message, 7 ); break;
242 case 't': OUTS( pattern, 7 ); break;
248 return ResKind( std::string( ident, sep-ident ) );
251 bool Solvable::isKind( const ResKind & kind_r ) const
253 NO_SOLVABLE_RETURN( false );
255 // detect srcpackages by 'arch'
256 switch ( _solvable->arch )
260 return( kind_r == ResKind::srcpackage );
264 // no ':' in package names (hopefully)
265 const char * ident = IdString( _solvable->name ).c_str();
266 if ( kind_r == ResKind::package )
268 return( ::strchr( ident, ':' ) == 0 );
271 // look for a 'kind:' prefix
272 const char * kind = kind_r.c_str();
273 unsigned ksize = ::strlen( kind );
274 return( ::strncmp( ident, kind, ksize ) == 0
275 && ident[ksize] == ':' );
278 std::string Solvable::name() const
280 NO_SOLVABLE_RETURN( std::string() );
281 const char * ident = IdString( _solvable->name ).c_str();
282 const char * sep = ::strchr( ident, ':' );
283 return( sep ? sep+1 : ident );
286 Edition Solvable::edition() const
288 NO_SOLVABLE_RETURN( Edition() );
289 return Edition( _solvable->evr );
292 Arch Solvable::arch() const
294 NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
295 switch ( _solvable->arch )
299 return Arch_noarch; //ArchId( ARCH_NOARCH );
302 return Arch( IdString(_solvable->arch).asString() );
303 //return ArchId( _solvable->arch );
306 IdString Solvable::vendor() const
308 NO_SOLVABLE_RETURN( IdString() );
309 return IdString( _solvable->vendor );
312 Capabilities Solvable::operator[]( Dep which_r ) const
314 switch( which_r.inSwitch() )
316 case Dep::PROVIDES_e: return provides(); break;
317 case Dep::REQUIRES_e: return requires(); break;
318 case Dep::CONFLICTS_e: return conflicts(); break;
319 case Dep::OBSOLETES_e: return obsoletes(); break;
320 case Dep::RECOMMENDS_e: return recommends(); break;
321 case Dep::SUGGESTS_e: return suggests(); break;
322 case Dep::FRESHENS_e: return freshens(); break;
323 case Dep::ENHANCES_e: return enhances(); break;
324 case Dep::SUPPLEMENTS_e: return supplements(); break;
325 case Dep::PREREQUIRES_e: return prerequires(); break;
327 return Capabilities();
330 inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
332 return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
334 Capabilities Solvable::provides() const
336 NO_SOLVABLE_RETURN( Capabilities() );
337 return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
339 Capabilities Solvable::requires() const
341 NO_SOLVABLE_RETURN( Capabilities() );
342 return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
344 Capabilities Solvable::conflicts() const
346 NO_SOLVABLE_RETURN( Capabilities() );
347 return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
349 Capabilities Solvable::obsoletes() const
351 NO_SOLVABLE_RETURN( Capabilities() );
352 return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
354 Capabilities Solvable::recommends() const
356 NO_SOLVABLE_RETURN( Capabilities() );
357 return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
359 Capabilities Solvable::suggests() const
361 NO_SOLVABLE_RETURN( Capabilities() );
362 return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
364 Capabilities Solvable::freshens() const
366 NO_SOLVABLE_RETURN( Capabilities() );
367 return _getCapabilities( _solvable->repo->idarraydata, _solvable->freshens );
369 Capabilities Solvable::enhances() const
371 NO_SOLVABLE_RETURN( Capabilities() );
372 return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
374 Capabilities Solvable::supplements() const
376 NO_SOLVABLE_RETURN( Capabilities() );
377 return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
379 Capabilities Solvable::prerequires() const
381 NO_SOLVABLE_RETURN( Capabilities() );
382 // prerequires are a subset of requires
383 ::Offset offs = _solvable->requires;
384 return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
388 ///////////////////////////////////////////////////////////////////
390 { /////////////////////////////////////////////////////////////////
391 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
392 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
393 * false to indicate abort.
395 int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
397 CapDetail detail( cap_r );
398 if ( detail.kind() == CapDetail::EXPRESSION )
400 switch ( detail.capRel() )
402 case CapDetail::CAP_AND:
403 case CapDetail::CAP_OR:
406 int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
408 return res; // negative on abort.
409 int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
411 return -res + res2; // negative on abort.
416 case CapDetail::CAP_NAMESPACE:
417 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
419 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
423 case CapDetail::REL_NONE:
424 case CapDetail::CAP_WITH:
431 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
432 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
433 * false to indicate abort.
435 inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
438 for_( cit, cap_r.begin(), cap_r.end() )
440 int res = invokeOnEachSupportedLocale( *cit, fnc_r );
442 return -cnt + res; // negative on abort.
449 // Functor returning false if a Locale is in the set.
452 NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
454 bool operator()( const Locale & locale_r ) const
456 return _locales.find( locale_r ) == _locales.end();
459 const LocaleSet & _locales;
462 } /////////////////////////////////////////////////////////////////
464 bool Solvable::supportsLocales() const
466 // false_c stops on 1st Locale.
467 return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
470 bool Solvable::supportsLocale( const Locale & locale_r ) const
472 // not_equal_to stops on == Locale.
473 return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
476 bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
478 if ( locales_r.empty() )
480 // NoMatchIn stops if Locale is included.
481 return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
484 bool Solvable::supportsRequestedLocales() const
485 { return supportsLocale( myPool().getRequestedLocales() ); }
487 void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
489 invokeOnEachSupportedLocale( supplements(),
490 functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
493 /******************************************************************
495 ** FUNCTION NAME : operator<<
496 ** FUNCTION TYPE : std::ostream &
498 std::ostream & operator<<( std::ostream & str, const Solvable & obj )
501 return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
503 return str << "(" << obj.id() << ")"
504 << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
505 << '-' << obj.edition() << '.' << obj.arch() << "("
506 << obj.repository().name() << ")";
509 /******************************************************************
511 ** FUNCTION NAME : dumpOn
512 ** FUNCTION TYPE : std::ostream &
514 std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
519 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
535 /////////////////////////////////////////////////////////////////
537 ///////////////////////////////////////////////////////////////////
538 /////////////////////////////////////////////////////////////////
540 ///////////////////////////////////////////////////////////////////