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 { /////////////////////////////////////////////////////////////////
38 Solvable::SplitIdent::SplitIdent( IdString ident_r )
44 const char * ident = ident_r.c_str();
45 const char * sep = ::strchr( ident, ':' );
47 // no ':' in package names (hopefully)
50 _kind = ResKind::package;
56 _name = IdString( sep+1 );
57 // quick check for well known kinds
62 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) _kind = ResKind::K
64 case 'c': OUTS( patch, 5 ); return; break;
65 case 'd': OUTS( product, 7 ); return; break;
66 case 'k': OUTS( package, 7 ); return; break;
67 case 'p': OUTS( srcpackage, 10 ); 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 myPool().isSystemRepo( _solvable->repo );
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 ///////////////////////////////////////////////////////////////////
204 inline Pathname lookupDatadirIn( Repository repor_r )
206 static const sat::SolvAttr susetagsDatadir( "susetags:datadir" );
208 // First look for repo attribute "susetags:datadir". If not found,
209 // look into the solvables as Code11 satsolver placed it there.
210 sat::LookupRepoAttr datadir( susetagsDatadir, repor_r );
211 if ( ! datadir.empty() )
212 ret = datadir.begin().asString();
215 sat::LookupAttr datadir( susetagsDatadir, repor_r );
216 if ( ! datadir.empty() )
217 ret = datadir.begin().asString();
222 ///////////////////////////////////////////////////////////////////
224 OnMediaLocation Solvable::lookupLocation() const
226 NO_SOLVABLE_RETURN( OnMediaLocation() );
227 // medianumber and path
229 char * file = ::solvable_get_location( _solvable, &medianr );
231 return OnMediaLocation();
236 switch ( repository().info().type().toEnum() )
238 case repo::RepoType::NONE_e:
240 path = lookupDatadirIn( repository() );
241 if ( ! path.empty() )
242 repository().info().setProbedType( repo::RepoType::YAST2_e );
246 case repo::RepoType::YAST2_e:
248 path = lookupDatadirIn( repository() );
257 ret.setLocation ( path/file, medianr );
258 ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ), ByteCount::K ) );
259 ret.setChecksum ( lookupCheckSumAttribute( SolvAttr::checksum ) );
260 // Not needed/available for solvables?
261 //ret.setOpenSize ( ByteCount( lookupNumAttribute( SolvAttr::opensize ), ByteCount::K ) );
262 //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
266 ResKind Solvable::kind() const
268 NO_SOLVABLE_RETURN( ResKind() );
269 // detect srcpackages by 'arch'
270 switch ( _solvable->arch )
274 return ResKind::srcpackage;
278 const char * ident = IdString( _solvable->name ).c_str();
279 const char * sep = ::strchr( ident, ':' );
281 // no ':' in package names (hopefully)
283 return ResKind::package;
285 // quick check for well known kinds
286 if ( sep-ident >= 4 )
290 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
292 case 'c': OUTS( patch, 5 ); break;
293 case 'd': OUTS( product, 7 ); break;
294 case 'k': OUTS( package, 7 ); break;
295 case 'p': OUTS( srcpackage, 10 ); break;
296 case 't': OUTS( pattern, 7 ); break;
302 return ResKind( std::string( ident, sep-ident ) );
305 bool Solvable::isKind( const ResKind & kind_r ) const
307 NO_SOLVABLE_RETURN( false );
309 // detect srcpackages by 'arch'
310 switch ( _solvable->arch )
314 return( kind_r == ResKind::srcpackage );
318 // no ':' in package names (hopefully)
319 const char * ident = IdString( _solvable->name ).c_str();
320 if ( kind_r == ResKind::package )
322 return( ::strchr( ident, ':' ) == 0 );
325 // look for a 'kind:' prefix
326 const char * kind = kind_r.c_str();
327 unsigned ksize = ::strlen( kind );
328 return( ::strncmp( ident, kind, ksize ) == 0
329 && ident[ksize] == ':' );
332 std::string Solvable::name() const
334 NO_SOLVABLE_RETURN( std::string() );
335 const char * ident = IdString( _solvable->name ).c_str();
336 const char * sep = ::strchr( ident, ':' );
337 return( sep ? sep+1 : ident );
340 Edition Solvable::edition() const
342 NO_SOLVABLE_RETURN( Edition() );
343 return Edition( _solvable->evr );
346 Arch Solvable::arch() const
348 NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
349 switch ( _solvable->arch )
353 return Arch_noarch; //ArchId( ARCH_NOARCH );
356 return Arch( IdString(_solvable->arch).asString() );
357 //return ArchId( _solvable->arch );
360 bool Solvable::installOnly() const
362 std::set<IdString> multiversion = ZConfig::instance().multiversion();
363 if (multiversion.find(ident()) != multiversion.end())
368 IdString Solvable::vendor() const
370 NO_SOLVABLE_RETURN( IdString() );
371 return IdString( _solvable->vendor );
374 Capabilities Solvable::operator[]( Dep which_r ) const
376 switch( which_r.inSwitch() )
378 case Dep::PROVIDES_e: return provides(); break;
379 case Dep::REQUIRES_e: return requires(); break;
380 case Dep::CONFLICTS_e: return conflicts(); break;
381 case Dep::OBSOLETES_e: return obsoletes(); break;
382 case Dep::RECOMMENDS_e: return recommends(); break;
383 case Dep::SUGGESTS_e: return suggests(); break;
384 case Dep::ENHANCES_e: return enhances(); break;
385 case Dep::SUPPLEMENTS_e: return supplements(); break;
386 case Dep::PREREQUIRES_e: return prerequires(); break;
388 return Capabilities();
391 inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
393 return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
395 Capabilities Solvable::provides() const
397 NO_SOLVABLE_RETURN( Capabilities() );
398 return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
400 Capabilities Solvable::requires() const
402 NO_SOLVABLE_RETURN( Capabilities() );
403 return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
405 Capabilities Solvable::conflicts() const
407 NO_SOLVABLE_RETURN( Capabilities() );
408 return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
410 Capabilities Solvable::obsoletes() const
412 NO_SOLVABLE_RETURN( Capabilities() );
413 return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
415 Capabilities Solvable::recommends() const
417 NO_SOLVABLE_RETURN( Capabilities() );
418 return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
420 Capabilities Solvable::suggests() const
422 NO_SOLVABLE_RETURN( Capabilities() );
423 return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
425 Capabilities Solvable::enhances() const
427 NO_SOLVABLE_RETURN( Capabilities() );
428 return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
430 Capabilities Solvable::supplements() const
432 NO_SOLVABLE_RETURN( Capabilities() );
433 return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
435 Capabilities Solvable::prerequires() const
437 NO_SOLVABLE_RETURN( Capabilities() );
438 // prerequires are a subset of requires
439 ::Offset offs = _solvable->requires;
440 return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
444 std::string Solvable::asString() const
446 NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
447 return str::form( "%s-%s.%s",
448 IdString( _solvable->name ).c_str(),
449 IdString( _solvable->evr ).c_str(),
450 IdString( _solvable->arch ).c_str() );
454 ///////////////////////////////////////////////////////////////////
456 { /////////////////////////////////////////////////////////////////
457 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
458 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
459 * false to indicate abort.
461 int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
463 CapDetail detail( cap_r );
464 if ( detail.kind() == CapDetail::EXPRESSION )
466 switch ( detail.capRel() )
468 case CapDetail::CAP_AND:
469 case CapDetail::CAP_OR:
472 int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
474 return res; // negative on abort.
475 int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
477 return -res + res2; // negative on abort.
482 case CapDetail::CAP_NAMESPACE:
483 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
485 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
489 case CapDetail::REL_NONE:
490 case CapDetail::CAP_WITH:
491 case CapDetail::CAP_ARCH:
498 /** Expand \ref Capability and call \c fnc_r for each namescpace:language
499 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
500 * false to indicate abort.
502 inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
505 for_( cit, cap_r.begin(), cap_r.end() )
507 int res = invokeOnEachSupportedLocale( *cit, fnc_r );
509 return -cnt + res; // negative on abort.
516 // Functor returning false if a Locale is in the set.
519 NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
521 bool operator()( const Locale & locale_r ) const
523 return _locales.find( locale_r ) == _locales.end();
526 const LocaleSet & _locales;
529 } /////////////////////////////////////////////////////////////////
531 bool Solvable::supportsLocales() const
533 // false_c stops on 1st Locale.
534 return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
537 bool Solvable::supportsLocale( const Locale & locale_r ) const
539 // not_equal_to stops on == Locale.
540 return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
543 bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
545 if ( locales_r.empty() )
547 // NoMatchIn stops if Locale is included.
548 return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
551 bool Solvable::supportsRequestedLocales() const
552 { return supportsLocale( myPool().getRequestedLocales() ); }
554 void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
556 invokeOnEachSupportedLocale( supplements(),
557 functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
560 /******************************************************************
562 ** FUNCTION NAME : operator<<
563 ** FUNCTION TYPE : std::ostream &
565 std::ostream & operator<<( std::ostream & str, const Solvable & obj )
568 return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
570 return str << "(" << obj.id() << ")"
571 << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
572 << '-' << obj.edition() << '.' << obj.arch() << "("
573 << obj.repository().alias() << ")";
576 /******************************************************************
578 ** FUNCTION NAME : dumpOn
579 ** FUNCTION TYPE : std::ostream &
581 std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
586 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
601 /////////////////////////////////////////////////////////////////
603 ///////////////////////////////////////////////////////////////////
604 /////////////////////////////////////////////////////////////////
606 ///////////////////////////////////////////////////////////////////