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"
30 #include "zypp/ui/Selectable.h"
34 ///////////////////////////////////////////////////////////////////
37 ///////////////////////////////////////////////////////////////////
40 ///////////////////////////////////////////////////////////////////
43 void _doSplit( IdString & _ident, ResKind & _kind, IdString & _name )
48 ResKind explicitKind = ResKind::explicitBuiltin( _ident.c_str() );
49 // NOTE: kind package and srcpackage do not have namespaced ident!
53 // No kind defaults to package
55 _kind = ResKind::package;
56 else if ( ! ( _kind == ResKind::package || _kind == ResKind::srcpackage ) )
57 _ident = IdString( str::form( "%s:%s", _kind.c_str(), _ident.c_str() ) );
61 // strip kind spec from name
62 _name = IdString( ::strchr( _ident.c_str(), ':' )+1 );
64 if ( _kind == ResKind::package || _kind == ResKind::srcpackage )
70 ///////////////////////////////////////////////////////////////////
72 Solvable::SplitIdent::SplitIdent( IdString ident_r )
74 { _doSplit( _ident, _kind, _name ); }
76 Solvable::SplitIdent::SplitIdent( const char * ident_r )
78 { _doSplit( _ident, _kind, _name ); }
80 Solvable::SplitIdent::SplitIdent( const std::string & ident_r )
82 { _doSplit( _ident, _kind, _name ); }
84 Solvable::SplitIdent::SplitIdent( ResKind kind_r, IdString name_r )
87 { _doSplit( _ident, _kind, _name ); }
89 Solvable::SplitIdent::SplitIdent( ResKind kind_r, const C_Str & name_r )
92 { _doSplit( _ident, _kind, _name ); }
94 /////////////////////////////////////////////////////////////////
96 /////////////////////////////////////////////////////////////////
98 const Solvable Solvable::noSolvable;
100 /////////////////////////////////////////////////////////////////
102 detail::CSolvable * Solvable::get() const
103 { return myPool().getSolvable( _id ); }
105 #define NO_SOLVABLE_RETURN( VAL ) \
106 detail::CSolvable * _solvable( get() ); \
107 if ( ! _solvable ) return VAL
109 Solvable Solvable::nextInPool() const
110 { return Solvable( myPool().getNextId( _id ) ); }
112 Solvable Solvable::nextInRepo() const
114 NO_SOLVABLE_RETURN( noSolvable );
115 for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
117 detail::CSolvable * nextS( myPool().getSolvable( next ) );
118 if ( nextS && nextS->repo == _solvable->repo )
120 return Solvable( next );
126 std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
128 NO_SOLVABLE_RETURN( std::string() );
129 const char * s = ::solvable_lookup_str( _solvable, attr.id() );
130 return s ? s : std::string();
133 std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
135 NO_SOLVABLE_RETURN( std::string() );
139 s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
143 for ( Locale l( lang_r ); l; l = l.fallback() )
145 if ( (s = ::solvable_lookup_str_lang( _solvable, attr.id(), l.c_str(), 0 )) )
148 // here: no matching locale, so use default
149 s = ::solvable_lookup_str_lang( _solvable, attr.id(), 0, 0 );
151 return s ? s : std::string();
154 unsigned long long Solvable::lookupNumAttribute( const SolvAttr & attr ) const
156 NO_SOLVABLE_RETURN( 0 );
157 return ::solvable_lookup_num( _solvable, attr.id(), 0 );
160 unsigned long long Solvable::lookupNumAttribute( const SolvAttr & attr, unsigned long long notfound_r ) const
162 NO_SOLVABLE_RETURN( notfound_r );
163 return ::solvable_lookup_num( _solvable, attr.id(), notfound_r );
166 bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
168 NO_SOLVABLE_RETURN( false );
169 return ::solvable_lookup_bool( _solvable, attr.id() );
172 detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
174 NO_SOLVABLE_RETURN( detail::noId );
175 return ::solvable_lookup_id( _solvable, attr.id() );
178 CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
180 NO_SOLVABLE_RETURN( CheckSum() );
181 detail::IdType chksumtype = 0;
182 const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
185 switch ( chksumtype )
187 case REPOKEY_TYPE_MD5: return CheckSum::md5( s );
188 case REPOKEY_TYPE_SHA1: return CheckSum::sha1( s );
189 case REPOKEY_TYPE_SHA224: return CheckSum::sha224( s );
190 case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
191 case REPOKEY_TYPE_SHA384: return CheckSum::sha384( s );
192 case REPOKEY_TYPE_SHA512: return CheckSum::sha512( s );
194 return CheckSum( std::string(), s ); // try to autodetect
197 ///////////////////////////////////////////////////////////////////
200 inline Pathname lookupDatadirIn( Repository repor_r )
202 static const SolvAttr susetagsDatadir( "susetags:datadir" );
204 // First look for repo attribute "susetags:datadir". If not found,
205 // look into the solvables as Code11 libsolv placed it there.
206 LookupRepoAttr datadir( susetagsDatadir, repor_r );
207 if ( ! datadir.empty() )
208 ret = datadir.begin().asString();
211 LookupAttr datadir( susetagsDatadir, repor_r );
212 if ( ! datadir.empty() )
213 ret = datadir.begin().asString();
218 ///////////////////////////////////////////////////////////////////
220 OnMediaLocation Solvable::lookupLocation() const
222 NO_SOLVABLE_RETURN( OnMediaLocation() );
223 // medianumber and path
225 const char * file = ::solvable_lookup_location( _solvable, &medianr );
227 return OnMediaLocation();
234 switch ( repository().info().type().toEnum() )
236 case repo::RepoType::NONE_e:
238 path = lookupDatadirIn( repository() );
239 if ( ! path.empty() )
240 repository().info().setProbedType( repo::RepoType::YAST2_e );
244 case repo::RepoType::YAST2_e:
246 path = lookupDatadirIn( repository() );
255 ret.setLocation ( path/file, medianr );
256 ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ) ) );
257 ret.setChecksum ( lookupCheckSumAttribute( SolvAttr::checksum ) );
258 // Not needed/available for solvables?
259 //ret.setOpenSize ( ByteCount( lookupNumAttribute( SolvAttr::opensize ) ) );
260 //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
265 IdString Solvable::ident() const
267 NO_SOLVABLE_RETURN( IdString() );
268 return IdString( _solvable->name );
271 ResKind Solvable::kind() const
273 NO_SOLVABLE_RETURN( ResKind() );
274 // detect srcpackages by 'arch'
275 switch ( _solvable->arch )
279 return ResKind::srcpackage;
283 // either explicitly prefixed...
284 const char * ident = IdString( _solvable->name ).c_str();
285 ResKind knownKind( ResKind::explicitBuiltin( ident ) );
289 // ...or no ':' in package names (hopefully)...
290 const char * sep = ::strchr( ident, ':' );
292 return ResKind::package;
294 // ...or something unknown.
295 return ResKind( std::string( ident, sep-ident ) );
298 bool Solvable::isKind( const ResKind & kind_r ) const
300 NO_SOLVABLE_RETURN( false );
302 // detect srcpackages by 'arch'
303 switch ( _solvable->arch )
307 return( kind_r == ResKind::srcpackage );
311 // no ':' in package names (hopefully)
312 const char * ident = IdString( _solvable->name ).c_str();
313 if ( kind_r == ResKind::package )
315 return( ::strchr( ident, ':' ) == 0 );
318 // look for a 'kind:' prefix
319 const char * kind = kind_r.c_str();
320 unsigned ksize = ::strlen( kind );
321 return( ::strncmp( ident, kind, ksize ) == 0
322 && ident[ksize] == ':' );
325 std::string Solvable::name() const
327 NO_SOLVABLE_RETURN( std::string() );
328 const char * ident = IdString( _solvable->name ).c_str();
329 const char * sep = ::strchr( ident, ':' );
330 return( sep ? sep+1 : ident );
333 Edition Solvable::edition() const
335 NO_SOLVABLE_RETURN( Edition() );
336 return Edition( _solvable->evr );
339 Arch Solvable::arch() const
341 NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
342 switch ( _solvable->arch )
346 return Arch_noarch; //ArchId( ARCH_NOARCH );
349 return Arch( IdString(_solvable->arch).asString() );
350 //return ArchId( _solvable->arch );
353 IdString Solvable::vendor() const
355 NO_SOLVABLE_RETURN( IdString() );
356 return IdString( _solvable->vendor );
359 Repository Solvable::repository() const
361 NO_SOLVABLE_RETURN( Repository::noRepository );
362 return Repository( _solvable->repo );
365 RepoInfo Solvable::repoInfo() const
366 { return repository().info(); }
369 bool Solvable::isSystem() const
371 NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
372 return myPool().isSystemRepo( _solvable->repo );
375 bool Solvable::onSystemByUser() const
377 return isSystem() && myPool().isOnSystemByUser( ident() );
380 bool Solvable::onSystemByAuto() const
382 return isSystem() && myPool().isOnSystemByAuto( ident() );
385 bool Solvable::identIsAutoInstalled( const IdString & ident_r )
387 return myPool().isOnSystemByAuto( ident_r );
390 bool Solvable::isNeedreboot() const
392 NO_SOLVABLE_RETURN( false );
393 return myPool().isNeedreboot( *this );
396 bool Solvable::multiversionInstall() const
398 NO_SOLVABLE_RETURN( false );
399 return myPool().isMultiversion( *this );
402 Date Solvable::buildtime() const
404 NO_SOLVABLE_RETURN( Date() );
405 return Date( lookupNumAttribute( SolvAttr::buildtime ) );
408 Date Solvable::installtime() const
410 NO_SOLVABLE_RETURN( Date() );
411 return Date( lookupNumAttribute( SolvAttr::installtime ) );
414 std::string Solvable::asString() const
416 NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
417 return str::form( "%s-%s.%s",
418 IdString( _solvable->name ).c_str(),
419 IdString( _solvable->evr ).c_str(),
420 IdString( _solvable->arch ).c_str() );
423 std::string Solvable::asUserString() const\
425 NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
426 return str::form( "%s-%s.%s (%s)",
427 IdString( _solvable->name ).c_str(),
428 IdString( _solvable->evr ).c_str(),
429 IdString( _solvable->arch ).c_str(),
430 repository().asUserString().c_str() );
433 bool Solvable::identical( const Solvable & rhs ) const
435 NO_SOLVABLE_RETURN( ! rhs.get() );
436 detail::CSolvable * rhssolvable( rhs.get() );
437 return rhssolvable && ( _solvable == rhssolvable || ::solvable_identical( _solvable, rhssolvable ) );
440 ///////////////////////////////////////////////////////////////////
443 inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
445 return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
448 ///////////////////////////////////////////////////////////////////
450 Capabilities Solvable::provides() const
452 NO_SOLVABLE_RETURN( Capabilities() );
453 return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
455 Capabilities Solvable::requires() const
457 NO_SOLVABLE_RETURN( Capabilities() );
458 return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
460 Capabilities Solvable::conflicts() const
462 NO_SOLVABLE_RETURN( Capabilities() );
463 return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
465 Capabilities Solvable::obsoletes() const
467 NO_SOLVABLE_RETURN( Capabilities() );
468 return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
470 Capabilities Solvable::recommends() const
472 NO_SOLVABLE_RETURN( Capabilities() );
473 return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
475 Capabilities Solvable::suggests() const
477 NO_SOLVABLE_RETURN( Capabilities() );
478 return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
480 Capabilities Solvable::enhances() const
482 NO_SOLVABLE_RETURN( Capabilities() );
483 return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
485 Capabilities Solvable::supplements() const
487 NO_SOLVABLE_RETURN( Capabilities() );
488 return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
490 Capabilities Solvable::prerequires() const
492 NO_SOLVABLE_RETURN( Capabilities() );
493 // prerequires are a subset of requires
494 ::Offset offs = _solvable->requires;
495 return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
499 CapabilitySet Solvable::providesNamespace( const std::string & namespace_r ) const
501 NO_SOLVABLE_RETURN( CapabilitySet() );
503 Capabilities caps( provides() );
504 for_( it, caps.begin(), caps.end() )
506 CapDetail caprep( it->detail() );
507 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
513 CapabilitySet Solvable::valuesOfNamespace( const std::string & namespace_r ) const
515 NO_SOLVABLE_RETURN( CapabilitySet() );
517 Capabilities caps( provides() );
518 for_( it, caps.begin(), caps.end() )
520 CapDetail caprep( it->detail() );
521 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
523 std::string value( caprep.name().c_str()+namespace_r.size()+1 );
524 value[value.size()-1] = '\0'; // erase the trailing ')'
525 ret.insert( Capability( value, caprep.op(), caprep.ed() ) );
531 std::pair<bool, CapabilitySet> Solvable::matchesSolvable(const SolvAttr &attr, const Solvable &solv) const
534 int res = solvable_matchessolvable( get(), attr.id(), static_cast<Id>( solv.id() ), capQueue, 0 );
537 if ( capQueue.size() )
538 std::for_each( capQueue.begin(), capQueue.end(), [ &caps ]( auto cap ){ caps.insert( Capability(cap) );});
540 return std::make_pair( res == 1, std::move(caps) );
543 ///////////////////////////////////////////////////////////////////
546 /** Expand \ref Capability and call \c fnc_r for each namespace:language
547 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
548 * false to indicate abort.
550 int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
552 CapDetail detail( cap_r );
553 if ( detail.kind() == CapDetail::EXPRESSION )
555 switch ( detail.capRel() )
557 case CapDetail::CAP_AND:
558 case CapDetail::CAP_OR:
561 int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
563 return res; // negative on abort.
564 int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
566 return -res + res2; // negative on abort.
571 case CapDetail::CAP_NAMESPACE:
572 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
574 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
578 case CapDetail::REL_NONE:
579 case CapDetail::CAP_WITH:
580 case CapDetail::CAP_ARCH:
587 /** Expand \ref Capability and call \c fnc_r for each namespace:language
588 * dependency. Return #invocations of fnc_r, negative if fnc_r returned
589 * false to indicate abort.
591 inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (Locale)> fnc_r )
594 for_( cit, cap_r.begin(), cap_r.end() )
596 int res = invokeOnEachSupportedLocale( *cit, fnc_r );
598 return -cnt + res; // negative on abort.
605 // Functor returning false if a Locale is in the set.
608 NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
610 bool operator()( const Locale & locale_r ) const
612 return _locales.find( locale_r ) == _locales.end();
615 const LocaleSet & _locales;
618 ///////////////////////////////////////////////////////////////////
620 bool Solvable::supportsLocales() const
622 // false_c stops on 1st Locale.
623 return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
626 bool Solvable::supportsLocale( const Locale & locale_r ) const
628 // not_equal_to stops on == Locale.
629 return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
632 bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
634 if ( locales_r.empty() )
636 // NoMatchIn stops if Locale is included.
637 return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
640 bool Solvable::supportsRequestedLocales() const
641 { return supportsLocale( myPool().getRequestedLocales() ); }
643 LocaleSet Solvable::getSupportedLocales() const
646 invokeOnEachSupportedLocale( supplements(), functor::collector( std::inserter( ret, ret.begin() ) ) );
650 CpeId Solvable::cpeId() const
652 NO_SOLVABLE_RETURN( CpeId() );
653 return CpeId( lookupStrAttribute( SolvAttr::cpeid ), CpeId::noThrow );
656 unsigned Solvable::mediaNr() const
658 NO_SOLVABLE_RETURN( 0U );
659 // medianumber and path
660 unsigned medianr = 0U;
661 const char * file = ::solvable_lookup_location( _solvable, &medianr );
664 else if ( ! medianr )
669 ByteCount Solvable::installSize() const
671 NO_SOLVABLE_RETURN( ByteCount() );
672 return ByteCount( lookupNumAttribute( SolvAttr::installsize ) );
675 ByteCount Solvable::downloadSize() const
677 NO_SOLVABLE_RETURN( ByteCount() );
678 return ByteCount( lookupNumAttribute( SolvAttr::downloadsize ) );
681 std::string Solvable::distribution() const
683 NO_SOLVABLE_RETURN( std::string() );
684 return lookupStrAttribute( SolvAttr::distribution );
687 std::string Solvable::summary( const Locale & lang_r ) const
689 NO_SOLVABLE_RETURN( std::string() );
690 return lookupStrAttribute( SolvAttr::summary, lang_r );
693 std::string Solvable::description( const Locale & lang_r ) const
695 NO_SOLVABLE_RETURN( std::string() );
696 return lookupStrAttribute( SolvAttr::description, lang_r );
699 std::string Solvable::insnotify( const Locale & lang_r ) const
701 NO_SOLVABLE_RETURN( std::string() );
702 return lookupStrAttribute( SolvAttr::insnotify, lang_r );
705 std::string Solvable::delnotify( const Locale & lang_r ) const
707 NO_SOLVABLE_RETURN( std::string() );
708 return lookupStrAttribute( SolvAttr::delnotify, lang_r );
711 std::string Solvable::licenseToConfirm( const Locale & lang_r ) const
713 NO_SOLVABLE_RETURN( std::string() );
714 std::string ret = lookupStrAttribute( SolvAttr::eula, lang_r );
715 if ( ret.empty() && isKind<Product>() )
717 const RepoInfo & ri( repoInfo() );
718 std::string riname( name() ); // "license-"+name with fallback "license"
719 if ( ! ri.hasLicense( riname ) )
722 if ( ri.needToAcceptLicense( riname ) || ! ui::Selectable::get( *this )->hasInstalledObj() )
723 ret = ri.getLicense( riname, lang_r ); // bnc#908976: suppress informal license upon update
728 bool Solvable::needToAcceptLicense() const
730 NO_SOLVABLE_RETURN( false );
731 if ( isKind<Product>() )
733 const RepoInfo & ri( repoInfo() );
734 std::string riname( name() ); // "license-"+name with fallback "license"
735 if ( ! ri.hasLicense( riname ) )
738 return ri.needToAcceptLicense( riname );
744 std::ostream & operator<<( std::ostream & str, const Solvable & obj )
747 return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
749 return str << "(" << obj.id() << ")"
750 << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
751 << '-' << obj.edition() << '.' << obj.arch() << "("
752 << obj.repository().alias() << ")";
755 std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
760 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
775 std::ostream & dumpAsXmlOn( std::ostream & str, const Solvable & obj )
777 xmlout::Node guard( str, "solvable" );
779 dumpAsXmlOn( *guard, obj.kind() );
780 *xmlout::Node( *guard, "name" ) << obj.name();
781 dumpAsXmlOn( *guard, obj.edition() );
782 dumpAsXmlOn( *guard, obj.arch() );
783 dumpAsXmlOn( *guard, obj.repository() );
788 ///////////////////////////////////////////////////////////////////
790 ///////////////////////////////////////////////////////////////////