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 )
41 const char * ident = ident_r.c_str();
42 const char * sep = ::strchr( ident, ':' );
44 // no ':' in package names (hopefully)
47 _kind = ResKind::package;
53 _name = IdString( sep+1 );
54 // quick check for well known kinds
59 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) _kind = ResKind::K
61 case 'c': OUTS( patch, 5 ); return; break;
62 case 'd': OUTS( product, 7 ); return; break;
63 case 'i': OUTS( script, 6 ); return; break;
64 case 'k': OUTS( package, 7 ); return; break;
65 case 'm': OUTS( atom, 4 ); return; break;
66 case 'p': OUTS( srcpackage, 10 ); return; break;
67 case 's': OUTS( message, 7 ); return; break;
68 case 't': OUTS( pattern, 7 ); return; break;
74 _kind = ResKind( std::string( ident, sep-ident ) );
77 Solvable::SplitIdent::SplitIdent( ResKind kind_r, IdString name_r )
81 if ( kind_r == ResKind::package || kind_r == ResKind::srcpackage )
84 _ident = IdString( str::form( "%s:%s", kind_r.c_str(), name_r.c_str() ) );
87 Solvable::SplitIdent::SplitIdent( ResKind kind_r, const C_Str & name_r )
91 if ( kind_r == ResKind::package || kind_r == ResKind::srcpackage )
94 _ident = IdString( str::form( "%s:%s", kind_r.c_str(), name_r.c_str() ) );
97 /////////////////////////////////////////////////////////////////
99 const Solvable Solvable::noSolvable;
101 /////////////////////////////////////////////////////////////////
103 ::_Solvable * Solvable::get() const
104 { return myPool().getSolvable( _id ); }
106 #define NO_SOLVABLE_RETURN( VAL ) \
107 ::_Solvable * _solvable( get() ); \
108 if ( ! _solvable ) return VAL
110 Solvable Solvable::nextInPool() const
111 { return Solvable( myPool().getNextId( _id ) ); }
113 Solvable Solvable::nextInRepo() const
115 NO_SOLVABLE_RETURN( noSolvable );
116 for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
118 ::_Solvable * nextS( myPool().getSolvable( next ) );
119 if ( nextS && nextS->repo == _solvable->repo )
121 return Solvable( next );
127 Repository Solvable::repository() const
129 NO_SOLVABLE_RETURN( Repository::noRepository );
130 return Repository( _solvable->repo );
133 bool Solvable::isSystem() const
135 NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
136 return Repository( _solvable->repo ).isSystemRepo();
139 IdString Solvable::ident() const
141 NO_SOLVABLE_RETURN( IdString() );
142 return IdString( _solvable->name );
145 std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
147 NO_SOLVABLE_RETURN( std::string() );
148 const char * s = ::solvable_lookup_str( _solvable, attr.id() );
149 return s ? s : std::string();
152 std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
154 NO_SOLVABLE_RETURN( std::string() );
156 if ( lang_r == Locale::noCode )
158 s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
162 s = ::solvable_lookup_str_lang( _solvable, attr.id(), lang_r.code().c_str() );
164 return s ? s : std::string();
167 unsigned Solvable::lookupNumAttribute( const SolvAttr & attr ) const
169 NO_SOLVABLE_RETURN( 0 );
170 return ::solvable_lookup_num( _solvable, attr.id(), 0 );
173 bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
175 NO_SOLVABLE_RETURN( false );
176 return ::solvable_lookup_bool( _solvable, attr.id() );
179 detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
181 NO_SOLVABLE_RETURN( detail::noId );
182 return ::solvable_lookup_id( _solvable, attr.id() );
185 CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
187 NO_SOLVABLE_RETURN( CheckSum() );
188 detail::IdType chksumtype = 0;
189 const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
192 switch ( chksumtype )
194 case REPOKEY_TYPE_MD5: return CheckSum::md5( s );
195 case REPOKEY_TYPE_SHA1: return CheckSum::sha1( s );
196 case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
198 return CheckSum( std::string(), s ); // try to autodetect
201 OnMediaLocation Solvable::lookupLocation() const
202 //std::string Solvable::lookupLocation( unsigned & medianr ) const
204 NO_SOLVABLE_RETURN( OnMediaLocation() );
205 // medianumber and path
207 char * file = ::solvable_get_location( _solvable, &medianr );
209 return OnMediaLocation();
214 if ( repository().info().type().toEnum() == repo::RepoType::YAST2_e )
216 #warning STILL HARDCODED /suse PREFIX in location
217 // (ma@) loading a susetags repo search for a solvable with attribute
218 // susetags:datadir. this is the prefix. store it in RepoInfo(?).
221 ret.setLocation ( path/file, medianr );
222 ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ), ByteCount::K ) );
223 ret.setChecksum ( lookupCheckSumAttribute( SolvAttr::checksum ) );
224 // Not needed/available for solvables?
225 //ret.setOpenSize ( ByteCount( lookupNumAttribute( SolvAttr::opensize ), ByteCount::K ) );
226 //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
230 ResKind Solvable::kind() const
232 NO_SOLVABLE_RETURN( ResKind() );
233 // detect srcpackages by 'arch'
234 switch ( _solvable->arch )
238 return ResKind::srcpackage;
242 const char * ident = IdString( _solvable->name ).c_str();
243 const char * sep = ::strchr( ident, ':' );
245 // no ':' in package names (hopefully)
247 return ResKind::package;
249 // quick check for well known kinds
250 if ( sep-ident >= 4 )
254 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
256 case 'c': OUTS( patch, 5 ); break;
257 case 'd': OUTS( product, 7 ); break;
258 case 'i': OUTS( script, 6 ); break;
259 case 'k': OUTS( package, 7 ); break;
260 case 'm': OUTS( atom, 4 ); break;
261 case 'p': OUTS( srcpackage, 10 ); break;
262 case 's': OUTS( message, 7 ); break;
263 case 't': OUTS( pattern, 7 ); break;
269 return ResKind( std::string( ident, sep-ident ) );
272 bool Solvable::isKind( const ResKind & kind_r ) const
274 NO_SOLVABLE_RETURN( false );
276 // detect srcpackages by 'arch'
277 switch ( _solvable->arch )
281 return( kind_r == ResKind::srcpackage );
285 // no ':' in package names (hopefully)
286 const char * ident = IdString( _solvable->name ).c_str();
287 if ( kind_r == ResKind::package )
289 return( ::strchr( ident, ':' ) == 0 );
292 // look for a 'kind:' prefix
293 const char * kind = kind_r.c_str();
294 unsigned ksize = ::strlen( kind );
295 return( ::strncmp( ident, kind, ksize ) == 0
296 && ident[ksize] == ':' );
299 std::string Solvable::name() const
301 NO_SOLVABLE_RETURN( std::string() );
302 const char * ident = IdString( _solvable->name ).c_str();
303 const char * sep = ::strchr( ident, ':' );
304 return( sep ? sep+1 : ident );
307 Edition Solvable::edition() const
309 NO_SOLVABLE_RETURN( Edition() );
310 return Edition( _solvable->evr );
313 Arch Solvable::arch() const
315 NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
316 switch ( _solvable->arch )
320 return Arch_noarch; //ArchId( ARCH_NOARCH );
323 return Arch( IdString(_solvable->arch).asString() );
324 //return ArchId( _solvable->arch );
327 IdString Solvable::vendor() const
329 NO_SOLVABLE_RETURN( IdString() );
330 return IdString( _solvable->vendor );
333 Capabilities Solvable::operator[]( Dep which_r ) const
335 switch( which_r.inSwitch() )
337 case Dep::PROVIDES_e: return provides(); break;
338 case Dep::REQUIRES_e: return requires(); break;
339 case Dep::CONFLICTS_e: return conflicts(); break;
340 case Dep::OBSOLETES_e: return obsoletes(); break;
341 case Dep::RECOMMENDS_e: return recommends(); break;
342 case Dep::SUGGESTS_e: return suggests(); break;
343 case Dep::FRESHENS_e: return freshens(); break;
344 case Dep::ENHANCES_e: return enhances(); break;
345 case Dep::SUPPLEMENTS_e: return supplements(); break;
346 case Dep::PREREQUIRES_e: return prerequires(); break;
348 return Capabilities();
351 inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
353 return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
355 Capabilities Solvable::provides() const
357 NO_SOLVABLE_RETURN( Capabilities() );
358 return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
360 Capabilities Solvable::requires() const
362 NO_SOLVABLE_RETURN( Capabilities() );
363 return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
365 Capabilities Solvable::conflicts() const
367 NO_SOLVABLE_RETURN( Capabilities() );
368 return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
370 Capabilities Solvable::obsoletes() const
372 NO_SOLVABLE_RETURN( Capabilities() );
373 return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
375 Capabilities Solvable::recommends() const
377 NO_SOLVABLE_RETURN( Capabilities() );
378 return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
380 Capabilities Solvable::suggests() const
382 NO_SOLVABLE_RETURN( Capabilities() );
383 return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
385 Capabilities Solvable::freshens() const
387 NO_SOLVABLE_RETURN( Capabilities() );
388 return _getCapabilities( _solvable->repo->idarraydata, _solvable->freshens );
390 Capabilities Solvable::enhances() const
392 NO_SOLVABLE_RETURN( Capabilities() );
393 return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
395 Capabilities Solvable::supplements() const
397 NO_SOLVABLE_RETURN( Capabilities() );
398 return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
400 Capabilities Solvable::prerequires() const
402 NO_SOLVABLE_RETURN( Capabilities() );
403 // prerequires are a subset of requires
404 ::Offset offs = _solvable->requires;
405 return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
409 ///////////////////////////////////////////////////////////////////
411 { /////////////////////////////////////////////////////////////////
412 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
413 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
414 * false to indicate abort.
416 int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
418 CapDetail detail( cap_r );
419 if ( detail.kind() == CapDetail::EXPRESSION )
421 switch ( detail.capRel() )
423 case CapDetail::CAP_AND:
424 case CapDetail::CAP_OR:
427 int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
429 return res; // negative on abort.
430 int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
432 return -res + res2; // negative on abort.
437 case CapDetail::CAP_NAMESPACE:
438 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
440 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
444 case CapDetail::REL_NONE:
445 case CapDetail::CAP_WITH:
446 case CapDetail::CAP_ARCH:
453 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
454 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
455 * false to indicate abort.
457 inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
460 for_( cit, cap_r.begin(), cap_r.end() )
462 int res = invokeOnEachSupportedLocale( *cit, fnc_r );
464 return -cnt + res; // negative on abort.
471 // Functor returning false if a Locale is in the set.
474 NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
476 bool operator()( const Locale & locale_r ) const
478 return _locales.find( locale_r ) == _locales.end();
481 const LocaleSet & _locales;
484 } /////////////////////////////////////////////////////////////////
486 bool Solvable::supportsLocales() const
488 // false_c stops on 1st Locale.
489 return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
492 bool Solvable::supportsLocale( const Locale & locale_r ) const
494 // not_equal_to stops on == Locale.
495 return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
498 bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
500 if ( locales_r.empty() )
502 // NoMatchIn stops if Locale is included.
503 return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
506 bool Solvable::supportsRequestedLocales() const
507 { return supportsLocale( myPool().getRequestedLocales() ); }
509 void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
511 invokeOnEachSupportedLocale( supplements(),
512 functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
515 /******************************************************************
517 ** FUNCTION NAME : operator<<
518 ** FUNCTION TYPE : std::ostream &
520 std::ostream & operator<<( std::ostream & str, const Solvable & obj )
523 return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
525 return str << "(" << obj.id() << ")"
526 << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
527 << '-' << obj.edition() << '.' << obj.arch() << "("
528 << obj.repository().name() << ")";
531 /******************************************************************
533 ** FUNCTION NAME : dumpOn
534 ** FUNCTION TYPE : std::ostream &
536 std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
541 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
557 /////////////////////////////////////////////////////////////////
559 ///////////////////////////////////////////////////////////////////
560 /////////////////////////////////////////////////////////////////
562 ///////////////////////////////////////////////////////////////////