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"
19 #include "zypp/base/Xml.h"
21 #include "zypp/sat/detail/PoolImpl.h"
22 #include "zypp/sat/Solvable.h"
23 #include "zypp/sat/Pool.h"
24 #include "zypp/sat/LookupAttr.h"
26 #include "zypp/Repository.h"
27 #include "zypp/OnMediaLocation.h"
28 #include "zypp/ZConfig.h"
32 ///////////////////////////////////////////////////////////////////
34 { /////////////////////////////////////////////////////////////////
35 ///////////////////////////////////////////////////////////////////
37 { /////////////////////////////////////////////////////////////////
41 void _doSplit( IdString & _ident, ResKind & _kind, IdString & _name )
46 ResKind explicitKind = ResKind::explicitBuiltin( _ident.c_str() );
47 // NOTE: kind package and srcpackage do not have namespaced ident!
51 // No kind defaults to package
53 _kind = ResKind::package;
54 else if ( ! ( _kind == ResKind::package || _kind == ResKind::srcpackage ) )
55 _ident = IdString( str::form( "%s:%s", _kind.c_str(), _ident.c_str() ) );
59 // strip kind spec from name
60 _name = IdString( ::strchr( _ident.c_str(), ':' )+1 );
62 if ( _kind == ResKind::package || _kind == ResKind::srcpackage )
69 Solvable::SplitIdent::SplitIdent( IdString ident_r )
71 { _doSplit( _ident, _kind, _name ); }
73 Solvable::SplitIdent::SplitIdent( const char * ident_r )
75 { _doSplit( _ident, _kind, _name ); }
77 Solvable::SplitIdent::SplitIdent( const std::string & ident_r )
79 { _doSplit( _ident, _kind, _name ); }
81 Solvable::SplitIdent::SplitIdent( ResKind kind_r, IdString name_r )
84 { _doSplit( _ident, _kind, _name ); }
86 Solvable::SplitIdent::SplitIdent( ResKind kind_r, const C_Str & name_r )
89 { _doSplit( _ident, _kind, _name ); }
91 /////////////////////////////////////////////////////////////////
93 const Solvable Solvable::noSolvable;
95 /////////////////////////////////////////////////////////////////
97 ::_Solvable * Solvable::get() const
98 { return myPool().getSolvable( _id ); }
100 #define NO_SOLVABLE_RETURN( VAL ) \
101 ::_Solvable * _solvable( get() ); \
102 if ( ! _solvable ) return VAL
104 Solvable Solvable::nextInPool() const
105 { return Solvable( myPool().getNextId( _id ) ); }
107 Solvable Solvable::nextInRepo() const
109 NO_SOLVABLE_RETURN( noSolvable );
110 for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
112 ::_Solvable * nextS( myPool().getSolvable( next ) );
113 if ( nextS && nextS->repo == _solvable->repo )
115 return Solvable( next );
121 Repository Solvable::repository() const
123 NO_SOLVABLE_RETURN( Repository::noRepository );
124 return Repository( _solvable->repo );
127 bool Solvable::isSystem() const
129 NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
130 return myPool().isSystemRepo( _solvable->repo );
133 bool Solvable::onSystemByUser() const
135 return isSystem() && myPool().isOnSystemByUser( ident() );
138 IdString Solvable::ident() const
140 NO_SOLVABLE_RETURN( IdString() );
141 return IdString( _solvable->name );
144 std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
146 NO_SOLVABLE_RETURN( std::string() );
147 const char * s = ::solvable_lookup_str( _solvable, attr.id() );
148 return s ? s : std::string();
151 std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
153 NO_SOLVABLE_RETURN( std::string() );
155 if ( lang_r == Locale::noCode )
157 s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
161 for ( Locale l( lang_r ); l != Locale::noCode; l = l.fallback() )
162 if ( (s = ::solvable_lookup_str_lang( _solvable, attr.id(), l.code().c_str(), 0 )) )
164 // here: no matching locale, so use default
165 s = ::solvable_lookup_str_lang( _solvable, attr.id(), 0, 0 );
167 return s ? s : std::string();
170 unsigned long long Solvable::lookupNumAttribute( const SolvAttr & attr ) const
172 NO_SOLVABLE_RETURN( 0 );
173 return ::solvable_lookup_num( _solvable, attr.id(), 0 );
176 bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
178 NO_SOLVABLE_RETURN( false );
179 return ::solvable_lookup_bool( _solvable, attr.id() );
182 detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
184 NO_SOLVABLE_RETURN( detail::noId );
185 return ::solvable_lookup_id( _solvable, attr.id() );
188 CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
190 NO_SOLVABLE_RETURN( CheckSum() );
191 detail::IdType chksumtype = 0;
192 const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
195 switch ( chksumtype )
197 case REPOKEY_TYPE_MD5: return CheckSum::md5( s );
198 case REPOKEY_TYPE_SHA1: return CheckSum::sha1( s );
199 case REPOKEY_TYPE_SHA224: return CheckSum::sha224( s );
200 case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
201 case REPOKEY_TYPE_SHA384: return CheckSum::sha384( s );
202 case REPOKEY_TYPE_SHA512: return CheckSum::sha512( s );
204 return CheckSum( std::string(), s ); // try to autodetect
207 ///////////////////////////////////////////////////////////////////
210 inline Pathname lookupDatadirIn( Repository repor_r )
212 static const sat::SolvAttr susetagsDatadir( "susetags:datadir" );
214 // First look for repo attribute "susetags:datadir". If not found,
215 // look into the solvables as Code11 libsolv placed it there.
216 sat::LookupRepoAttr datadir( susetagsDatadir, repor_r );
217 if ( ! datadir.empty() )
218 ret = datadir.begin().asString();
221 sat::LookupAttr datadir( susetagsDatadir, repor_r );
222 if ( ! datadir.empty() )
223 ret = datadir.begin().asString();
228 ///////////////////////////////////////////////////////////////////
230 OnMediaLocation Solvable::lookupLocation() const
232 NO_SOLVABLE_RETURN( OnMediaLocation() );
233 // medianumber and path
235 const char * file = ::solvable_lookup_location( _solvable, &medianr );
237 return OnMediaLocation();
244 switch ( repository().info().type().toEnum() )
246 case repo::RepoType::NONE_e:
248 path = lookupDatadirIn( repository() );
249 if ( ! path.empty() )
250 repository().info().setProbedType( repo::RepoType::YAST2_e );
254 case repo::RepoType::YAST2_e:
256 path = lookupDatadirIn( repository() );
265 ret.setLocation ( path/file, medianr );
266 ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ) ) );
267 ret.setChecksum ( lookupCheckSumAttribute( SolvAttr::checksum ) );
268 // Not needed/available for solvables?
269 //ret.setOpenSize ( ByteCount( lookupNumAttribute( SolvAttr::opensize ) ) );
270 //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
274 ResKind Solvable::kind() const
276 NO_SOLVABLE_RETURN( ResKind() );
277 // detect srcpackages by 'arch'
278 switch ( _solvable->arch )
282 return ResKind::srcpackage;
286 // either explicitly prefixed...
287 const char * ident = IdString( _solvable->name ).c_str();
288 ResKind knownKind( ResKind::explicitBuiltin( ident ) );
292 // ...or no ':' in package names (hopefully)...
293 const char * sep = ::strchr( ident, ':' );
295 return ResKind::package;
297 // ...or something unknown.
298 return ResKind( std::string( ident, sep-ident ) );
301 bool Solvable::isKind( const ResKind & kind_r ) const
303 NO_SOLVABLE_RETURN( false );
305 // detect srcpackages by 'arch'
306 switch ( _solvable->arch )
310 return( kind_r == ResKind::srcpackage );
314 // no ':' in package names (hopefully)
315 const char * ident = IdString( _solvable->name ).c_str();
316 if ( kind_r == ResKind::package )
318 return( ::strchr( ident, ':' ) == 0 );
321 // look for a 'kind:' prefix
322 const char * kind = kind_r.c_str();
323 unsigned ksize = ::strlen( kind );
324 return( ::strncmp( ident, kind, ksize ) == 0
325 && ident[ksize] == ':' );
328 std::string Solvable::name() const
330 NO_SOLVABLE_RETURN( std::string() );
331 const char * ident = IdString( _solvable->name ).c_str();
332 const char * sep = ::strchr( ident, ':' );
333 return( sep ? sep+1 : ident );
336 Edition Solvable::edition() const
338 NO_SOLVABLE_RETURN( Edition() );
339 return Edition( _solvable->evr );
342 Arch Solvable::arch() const
344 NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
345 switch ( _solvable->arch )
349 return Arch_noarch; //ArchId( ARCH_NOARCH );
352 return Arch( IdString(_solvable->arch).asString() );
353 //return ArchId( _solvable->arch );
356 bool Solvable::multiversionInstall() const
358 return myPool().isMultiversion( ident() );
361 IdString Solvable::vendor() const
363 NO_SOLVABLE_RETURN( IdString() );
364 return IdString( _solvable->vendor );
367 Capabilities Solvable::operator[]( Dep which_r ) const
369 switch( which_r.inSwitch() )
371 case Dep::PROVIDES_e: return provides(); break;
372 case Dep::REQUIRES_e: return requires(); break;
373 case Dep::CONFLICTS_e: return conflicts(); break;
374 case Dep::OBSOLETES_e: return obsoletes(); break;
375 case Dep::RECOMMENDS_e: return recommends(); break;
376 case Dep::SUGGESTS_e: return suggests(); break;
377 case Dep::ENHANCES_e: return enhances(); break;
378 case Dep::SUPPLEMENTS_e: return supplements(); break;
379 case Dep::PREREQUIRES_e: return prerequires(); break;
381 return Capabilities();
384 inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
386 return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
388 Capabilities Solvable::provides() const
390 NO_SOLVABLE_RETURN( Capabilities() );
391 return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
393 Capabilities Solvable::requires() const
395 NO_SOLVABLE_RETURN( Capabilities() );
396 return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
398 Capabilities Solvable::conflicts() const
400 NO_SOLVABLE_RETURN( Capabilities() );
401 return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
403 Capabilities Solvable::obsoletes() const
405 NO_SOLVABLE_RETURN( Capabilities() );
406 return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
408 Capabilities Solvable::recommends() const
410 NO_SOLVABLE_RETURN( Capabilities() );
411 return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
413 Capabilities Solvable::suggests() const
415 NO_SOLVABLE_RETURN( Capabilities() );
416 return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
418 Capabilities Solvable::enhances() const
420 NO_SOLVABLE_RETURN( Capabilities() );
421 return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
423 Capabilities Solvable::supplements() const
425 NO_SOLVABLE_RETURN( Capabilities() );
426 return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
428 Capabilities Solvable::prerequires() const
430 NO_SOLVABLE_RETURN( Capabilities() );
431 // prerequires are a subset of requires
432 ::Offset offs = _solvable->requires;
433 return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
437 CapabilitySet Solvable::providesNamespace( const std::string & namespace_r ) const
439 NO_SOLVABLE_RETURN( CapabilitySet() );
441 Capabilities caps( provides() );
442 for_( it, caps.begin(), caps.end() )
444 CapDetail caprep( it->detail() );
445 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
451 CapabilitySet Solvable::valuesOfNamespace( const std::string & namespace_r ) const
453 NO_SOLVABLE_RETURN( CapabilitySet() );
455 Capabilities caps( provides() );
456 for_( it, caps.begin(), caps.end() )
458 CapDetail caprep( it->detail() );
459 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
461 std::string value( caprep.name().c_str()+namespace_r.size()+1 );
462 value[value.size()-1] = '\0'; // erase the trailing ')'
463 ret.insert( Capability( value, caprep.op(), caprep.ed() ) );
470 std::string Solvable::asString() const
472 NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
473 return str::form( "%s-%s.%s",
474 IdString( _solvable->name ).c_str(),
475 IdString( _solvable->evr ).c_str(),
476 IdString( _solvable->arch ).c_str() );
479 std::string Solvable::asUserString() const\
481 NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
482 return str::form( "%s-%s.%s (%s)",
483 IdString( _solvable->name ).c_str(),
484 IdString( _solvable->evr ).c_str(),
485 IdString( _solvable->arch ).c_str(),
486 repository().asUserString().c_str() );
489 bool Solvable::identical( Solvable rhs ) const
491 NO_SOLVABLE_RETURN( ! rhs.get() );
492 ::_Solvable * rhssolvable( rhs.get() );
493 return rhssolvable && ( _solvable == rhssolvable || ::solvable_identical( _solvable, rhssolvable ) );
496 ///////////////////////////////////////////////////////////////////
498 { /////////////////////////////////////////////////////////////////
499 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
500 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
501 * false to indicate abort.
503 int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
505 CapDetail detail( cap_r );
506 if ( detail.kind() == CapDetail::EXPRESSION )
508 switch ( detail.capRel() )
510 case CapDetail::CAP_AND:
511 case CapDetail::CAP_OR:
514 int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
516 return res; // negative on abort.
517 int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
519 return -res + res2; // negative on abort.
524 case CapDetail::CAP_NAMESPACE:
525 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
527 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
531 case CapDetail::REL_NONE:
532 case CapDetail::CAP_WITH:
533 case CapDetail::CAP_ARCH:
540 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
541 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
542 * false to indicate abort.
544 inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
547 for_( cit, cap_r.begin(), cap_r.end() )
549 int res = invokeOnEachSupportedLocale( *cit, fnc_r );
551 return -cnt + res; // negative on abort.
558 // Functor returning false if a Locale is in the set.
561 NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
563 bool operator()( const Locale & locale_r ) const
565 return _locales.find( locale_r ) == _locales.end();
568 const LocaleSet & _locales;
571 } /////////////////////////////////////////////////////////////////
573 bool Solvable::supportsLocales() const
575 // false_c stops on 1st Locale.
576 return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
579 bool Solvable::supportsLocale( const Locale & locale_r ) const
581 // not_equal_to stops on == Locale.
582 return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
585 bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
587 if ( locales_r.empty() )
589 // NoMatchIn stops if Locale is included.
590 return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
593 bool Solvable::supportsRequestedLocales() const
594 { return supportsLocale( myPool().getRequestedLocales() ); }
596 void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
598 invokeOnEachSupportedLocale( supplements(),
599 functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
602 /******************************************************************
604 ** FUNCTION NAME : operator<<
605 ** FUNCTION TYPE : std::ostream &
607 std::ostream & operator<<( std::ostream & str, const Solvable & obj )
610 return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
612 return str << "(" << obj.id() << ")"
613 << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
614 << '-' << obj.edition() << '.' << obj.arch() << "("
615 << obj.repository().alias() << ")";
618 /******************************************************************
620 ** FUNCTION NAME : dumpOn
621 ** FUNCTION TYPE : std::ostream &
623 std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
628 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
643 std::ostream & dumpAsXmlOn( std::ostream & str, const Solvable & obj )
645 xmlout::Node guard( str, "solvable" );
647 dumpAsXmlOn( *guard, obj.kind() );
648 *xmlout::Node( *guard, "name" ) << obj.name();
649 dumpAsXmlOn( *guard, obj.edition() );
650 dumpAsXmlOn( *guard, obj.arch() );
651 dumpAsXmlOn( *guard, obj.repository() );
655 /////////////////////////////////////////////////////////////////
657 ///////////////////////////////////////////////////////////////////
658 /////////////////////////////////////////////////////////////////
660 ///////////////////////////////////////////////////////////////////