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/sat/LookupAttr.h"
25 #include "zypp/Repository.h"
26 #include "zypp/OnMediaLocation.h"
27 #include "zypp/ZConfig.h"
31 ///////////////////////////////////////////////////////////////////
33 { /////////////////////////////////////////////////////////////////
34 ///////////////////////////////////////////////////////////////////
36 { /////////////////////////////////////////////////////////////////
40 void _doSplit( IdString & _ident, ResKind & _kind, IdString & _name )
45 const char * ident = _ident.c_str();
46 const char * sep = ::strchr( ident, ':' );
48 // no ':' in package names (hopefully)
51 _kind = ResKind::package;
57 _name = IdString( sep+1 );
59 // Quick check for well known kinds.
60 // NOTE: kind package and srcpackage do not
61 // have namespaced ident!
66 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) _kind = ResKind::K
68 case 'c': OUTS( patch, 5 ); return; break;
69 case 'd': OUTS( product, 7 ); return; break;
70 case 'k': OUTS( package, 7 ); _ident = _name; return; break;
71 case 'p': OUTS( srcpackage, 10 ); _ident = _name; return; break;
72 case 't': OUTS( pattern, 7 ); return; break;
78 _kind = ResKind( std::string( ident, sep-ident ) );
82 Solvable::SplitIdent::SplitIdent( IdString ident_r )
84 { _doSplit( _ident, _kind, _name ); }
86 Solvable::SplitIdent::SplitIdent( const char * ident_r )
88 { _doSplit( _ident, _kind, _name ); }
90 Solvable::SplitIdent::SplitIdent( const std::string & ident_r )
92 { _doSplit( _ident, _kind, _name ); }
94 Solvable::SplitIdent::SplitIdent( ResKind kind_r, IdString name_r )
98 if ( kind_r == ResKind::package || kind_r == ResKind::srcpackage )
101 _ident = IdString( str::form( "%s:%s", kind_r.c_str(), name_r.c_str() ) );
104 Solvable::SplitIdent::SplitIdent( ResKind kind_r, const C_Str & name_r )
108 if ( kind_r == ResKind::package || kind_r == ResKind::srcpackage )
111 _ident = IdString( str::form( "%s:%s", kind_r.c_str(), name_r.c_str() ) );
114 /////////////////////////////////////////////////////////////////
116 const Solvable Solvable::noSolvable;
118 /////////////////////////////////////////////////////////////////
120 ::_Solvable * Solvable::get() const
121 { return myPool().getSolvable( _id ); }
123 #define NO_SOLVABLE_RETURN( VAL ) \
124 ::_Solvable * _solvable( get() ); \
125 if ( ! _solvable ) return VAL
127 Solvable Solvable::nextInPool() const
128 { return Solvable( myPool().getNextId( _id ) ); }
130 Solvable Solvable::nextInRepo() const
132 NO_SOLVABLE_RETURN( noSolvable );
133 for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
135 ::_Solvable * nextS( myPool().getSolvable( next ) );
136 if ( nextS && nextS->repo == _solvable->repo )
138 return Solvable( next );
144 Repository Solvable::repository() const
146 NO_SOLVABLE_RETURN( Repository::noRepository );
147 return Repository( _solvable->repo );
150 bool Solvable::isSystem() const
152 NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
153 return myPool().isSystemRepo( _solvable->repo );
156 IdString Solvable::ident() const
158 NO_SOLVABLE_RETURN( IdString() );
159 return IdString( _solvable->name );
162 std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
164 NO_SOLVABLE_RETURN( std::string() );
165 const char * s = ::solvable_lookup_str( _solvable, attr.id() );
166 return s ? s : std::string();
169 std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
171 NO_SOLVABLE_RETURN( std::string() );
173 if ( lang_r == Locale::noCode )
175 s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
179 for ( Locale l( lang_r ); l != Locale::noCode; l = l.fallback() )
180 if ( (s = ::solvable_lookup_str_lang( _solvable, attr.id(), l.code().c_str(), 0 )) )
182 // here: no matching locale, so use default
183 s = ::solvable_lookup_str_lang( _solvable, attr.id(), 0, 0 );
185 return s ? s : std::string();
188 unsigned Solvable::lookupNumAttribute( const SolvAttr & attr ) const
190 NO_SOLVABLE_RETURN( 0 );
191 return ::solvable_lookup_num( _solvable, attr.id(), 0 );
194 bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
196 NO_SOLVABLE_RETURN( false );
197 return ::solvable_lookup_bool( _solvable, attr.id() );
200 detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
202 NO_SOLVABLE_RETURN( detail::noId );
203 return ::solvable_lookup_id( _solvable, attr.id() );
206 CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
208 NO_SOLVABLE_RETURN( CheckSum() );
209 detail::IdType chksumtype = 0;
210 const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
213 switch ( chksumtype )
215 case REPOKEY_TYPE_MD5: return CheckSum::md5( s );
216 case REPOKEY_TYPE_SHA1: return CheckSum::sha1( s );
217 case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
219 return CheckSum( std::string(), s ); // try to autodetect
222 ///////////////////////////////////////////////////////////////////
225 inline Pathname lookupDatadirIn( Repository repor_r )
227 static const sat::SolvAttr susetagsDatadir( "susetags:datadir" );
229 // First look for repo attribute "susetags:datadir". If not found,
230 // look into the solvables as Code11 satsolver placed it there.
231 sat::LookupRepoAttr datadir( susetagsDatadir, repor_r );
232 if ( ! datadir.empty() )
233 ret = datadir.begin().asString();
236 sat::LookupAttr datadir( susetagsDatadir, repor_r );
237 if ( ! datadir.empty() )
238 ret = datadir.begin().asString();
243 ///////////////////////////////////////////////////////////////////
245 OnMediaLocation Solvable::lookupLocation() const
247 NO_SOLVABLE_RETURN( OnMediaLocation() );
248 // medianumber and path
250 char * file = ::solvable_get_location( _solvable, &medianr );
252 return OnMediaLocation();
257 switch ( repository().info().type().toEnum() )
259 case repo::RepoType::NONE_e:
261 path = lookupDatadirIn( repository() );
262 if ( ! path.empty() )
263 repository().info().setProbedType( repo::RepoType::YAST2_e );
267 case repo::RepoType::YAST2_e:
269 path = lookupDatadirIn( repository() );
278 ret.setLocation ( path/file, medianr );
279 ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ), ByteCount::K ) );
280 ret.setChecksum ( lookupCheckSumAttribute( SolvAttr::checksum ) );
281 // Not needed/available for solvables?
282 //ret.setOpenSize ( ByteCount( lookupNumAttribute( SolvAttr::opensize ), ByteCount::K ) );
283 //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
287 ResKind Solvable::kind() const
289 NO_SOLVABLE_RETURN( ResKind() );
290 // detect srcpackages by 'arch'
291 switch ( _solvable->arch )
295 return ResKind::srcpackage;
299 const char * ident = IdString( _solvable->name ).c_str();
300 const char * sep = ::strchr( ident, ':' );
302 // no ':' in package names (hopefully)
304 return ResKind::package;
306 // quick check for well known kinds
307 if ( sep-ident >= 4 )
311 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
313 case 'c': OUTS( patch, 5 ); break;
314 case 'd': OUTS( product, 7 ); break;
315 case 'k': OUTS( package, 7 ); break;
316 case 'p': OUTS( srcpackage, 10 ); break;
317 case 't': OUTS( pattern, 7 ); break;
323 return ResKind( std::string( ident, sep-ident ) );
326 bool Solvable::isKind( const ResKind & kind_r ) const
328 NO_SOLVABLE_RETURN( false );
330 // detect srcpackages by 'arch'
331 switch ( _solvable->arch )
335 return( kind_r == ResKind::srcpackage );
339 // no ':' in package names (hopefully)
340 const char * ident = IdString( _solvable->name ).c_str();
341 if ( kind_r == ResKind::package )
343 return( ::strchr( ident, ':' ) == 0 );
346 // look for a 'kind:' prefix
347 const char * kind = kind_r.c_str();
348 unsigned ksize = ::strlen( kind );
349 return( ::strncmp( ident, kind, ksize ) == 0
350 && ident[ksize] == ':' );
353 std::string Solvable::name() const
355 NO_SOLVABLE_RETURN( std::string() );
356 const char * ident = IdString( _solvable->name ).c_str();
357 const char * sep = ::strchr( ident, ':' );
358 return( sep ? sep+1 : ident );
361 Edition Solvable::edition() const
363 NO_SOLVABLE_RETURN( Edition() );
364 return Edition( _solvable->evr );
367 Arch Solvable::arch() const
369 NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
370 switch ( _solvable->arch )
374 return Arch_noarch; //ArchId( ARCH_NOARCH );
377 return Arch( IdString(_solvable->arch).asString() );
378 //return ArchId( _solvable->arch );
381 bool Solvable::multiversionInstall() const
383 return myPool().isMultiversion( ident() );
386 bool Solvable::installOnly() const { return multiversionInstall(); }
388 IdString Solvable::vendor() const
390 NO_SOLVABLE_RETURN( IdString() );
391 return IdString( _solvable->vendor );
394 Capabilities Solvable::operator[]( Dep which_r ) const
396 switch( which_r.inSwitch() )
398 case Dep::PROVIDES_e: return provides(); break;
399 case Dep::REQUIRES_e: return requires(); break;
400 case Dep::CONFLICTS_e: return conflicts(); break;
401 case Dep::OBSOLETES_e: return obsoletes(); break;
402 case Dep::RECOMMENDS_e: return recommends(); break;
403 case Dep::SUGGESTS_e: return suggests(); break;
404 case Dep::ENHANCES_e: return enhances(); break;
405 case Dep::SUPPLEMENTS_e: return supplements(); break;
406 case Dep::PREREQUIRES_e: return prerequires(); break;
408 return Capabilities();
411 inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
413 return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
415 Capabilities Solvable::provides() const
417 NO_SOLVABLE_RETURN( Capabilities() );
418 return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
420 Capabilities Solvable::requires() const
422 NO_SOLVABLE_RETURN( Capabilities() );
423 return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
425 Capabilities Solvable::conflicts() const
427 NO_SOLVABLE_RETURN( Capabilities() );
428 return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
430 Capabilities Solvable::obsoletes() const
432 NO_SOLVABLE_RETURN( Capabilities() );
433 return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
435 Capabilities Solvable::recommends() const
437 NO_SOLVABLE_RETURN( Capabilities() );
438 return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
440 Capabilities Solvable::suggests() const
442 NO_SOLVABLE_RETURN( Capabilities() );
443 return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
445 Capabilities Solvable::enhances() const
447 NO_SOLVABLE_RETURN( Capabilities() );
448 return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
450 Capabilities Solvable::supplements() const
452 NO_SOLVABLE_RETURN( Capabilities() );
453 return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
455 Capabilities Solvable::prerequires() const
457 NO_SOLVABLE_RETURN( Capabilities() );
458 // prerequires are a subset of requires
459 ::Offset offs = _solvable->requires;
460 return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
464 CapabilitySet Solvable::providesNamespace( const std::string & namespace_r ) const
466 NO_SOLVABLE_RETURN( CapabilitySet() );
468 Capabilities caps( provides() );
469 for_( it, caps.begin(), caps.end() )
471 CapDetail caprep( it->detail() );
472 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
478 CapabilitySet Solvable::valuesOfNamespace( const std::string & namespace_r ) const
480 NO_SOLVABLE_RETURN( CapabilitySet() );
482 Capabilities caps( provides() );
483 for_( it, caps.begin(), caps.end() )
485 CapDetail caprep( it->detail() );
486 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
488 std::string value( caprep.name().c_str()+namespace_r.size()+1 );
489 value[value.size()-1] = '\0'; // erase the trailing ')'
490 ret.insert( Capability( value, caprep.op(), caprep.ed() ) );
497 std::string Solvable::asString() const
499 NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
500 return str::form( "%s-%s.%s",
501 IdString( _solvable->name ).c_str(),
502 IdString( _solvable->evr ).c_str(),
503 IdString( _solvable->arch ).c_str() );
506 bool Solvable::identical( Solvable rhs ) const
508 NO_SOLVABLE_RETURN( ! rhs.get() );
509 ::_Solvable * rhssolvable( rhs.get() );
510 return rhssolvable && ( _solvable == rhssolvable || ::solvable_identical( _solvable, rhssolvable ) );
513 ///////////////////////////////////////////////////////////////////
515 { /////////////////////////////////////////////////////////////////
516 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
517 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
518 * false to indicate abort.
520 int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
522 CapDetail detail( cap_r );
523 if ( detail.kind() == CapDetail::EXPRESSION )
525 switch ( detail.capRel() )
527 case CapDetail::CAP_AND:
528 case CapDetail::CAP_OR:
531 int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
533 return res; // negative on abort.
534 int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
536 return -res + res2; // negative on abort.
541 case CapDetail::CAP_NAMESPACE:
542 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
544 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
548 case CapDetail::REL_NONE:
549 case CapDetail::CAP_WITH:
550 case CapDetail::CAP_ARCH:
557 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
558 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
559 * false to indicate abort.
561 inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
564 for_( cit, cap_r.begin(), cap_r.end() )
566 int res = invokeOnEachSupportedLocale( *cit, fnc_r );
568 return -cnt + res; // negative on abort.
575 // Functor returning false if a Locale is in the set.
578 NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
580 bool operator()( const Locale & locale_r ) const
582 return _locales.find( locale_r ) == _locales.end();
585 const LocaleSet & _locales;
588 } /////////////////////////////////////////////////////////////////
590 bool Solvable::supportsLocales() const
592 // false_c stops on 1st Locale.
593 return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
596 bool Solvable::supportsLocale( const Locale & locale_r ) const
598 // not_equal_to stops on == Locale.
599 return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
602 bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
604 if ( locales_r.empty() )
606 // NoMatchIn stops if Locale is included.
607 return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
610 bool Solvable::supportsRequestedLocales() const
611 { return supportsLocale( myPool().getRequestedLocales() ); }
613 void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
615 invokeOnEachSupportedLocale( supplements(),
616 functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
619 /******************************************************************
621 ** FUNCTION NAME : operator<<
622 ** FUNCTION TYPE : std::ostream &
624 std::ostream & operator<<( std::ostream & str, const Solvable & obj )
627 return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
629 return str << "(" << obj.id() << ")"
630 << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
631 << '-' << obj.edition() << '.' << obj.arch() << "("
632 << obj.repository().alias() << ")";
635 /******************************************************************
637 ** FUNCTION NAME : dumpOn
638 ** FUNCTION TYPE : std::ostream &
640 std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
645 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
660 /////////////////////////////////////////////////////////////////
662 ///////////////////////////////////////////////////////////////////
663 /////////////////////////////////////////////////////////////////
665 ///////////////////////////////////////////////////////////////////