00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013
00014 #include "zypp/base/Logger.h"
00015 #include "zypp/base/Gettext.h"
00016 #include "zypp/base/Exception.h"
00017 #include "zypp/base/Functional.h"
00018 #include "zypp/base/Collector.h"
00019
00020 #include "zypp/sat/detail/PoolImpl.h"
00021 #include "zypp/sat/Solvable.h"
00022 #include "zypp/sat/Pool.h"
00023 #include "zypp/sat/LookupAttr.h"
00024
00025 #include "zypp/Repository.h"
00026 #include "zypp/OnMediaLocation.h"
00027 #include "zypp/ZConfig.h"
00028
00029 using std::endl;
00030
00032 namespace zypp
00033 {
00034
00035 namespace sat
00036 {
00037
00038 namespace
00039 {
00040 void _doSplit( IdString & _ident, ResKind & _kind, IdString & _name )
00041 {
00042 if ( ! _ident )
00043 return;
00044
00045 ResKind explicitKind = Solvable::SplitIdent::explicitKind( _ident.c_str() );
00046
00047 if ( ! explicitKind )
00048 {
00049 _name = _ident;
00050
00051 if ( !_kind )
00052 _kind = ResKind::package;
00053 if ( ! ( _kind == ResKind::package || _kind == ResKind::srcpackage ) )
00054 _ident = IdString( str::form( "%s:%s", _kind.c_str(), _ident.c_str() ) );
00055 }
00056 else
00057 {
00058
00059 _name = IdString( ::strchr( _ident.c_str(), ':' )+1 );
00060 _kind = explicitKind;
00061 if ( _kind == ResKind::package || _kind == ResKind::srcpackage )
00062 _ident = _name;
00063 }
00064 return;
00065 }
00066 }
00067
00068 Solvable::SplitIdent::SplitIdent( IdString ident_r )
00069 : _ident( ident_r )
00070 { _doSplit( _ident, _kind, _name ); }
00071
00072 Solvable::SplitIdent::SplitIdent( const char * ident_r )
00073 : _ident( ident_r )
00074 { _doSplit( _ident, _kind, _name ); }
00075
00076 Solvable::SplitIdent::SplitIdent( const std::string & ident_r )
00077 : _ident( ident_r )
00078 { _doSplit( _ident, _kind, _name ); }
00079
00080 Solvable::SplitIdent::SplitIdent( ResKind kind_r, IdString name_r )
00081 : _ident( name_r )
00082 , _kind( kind_r )
00083 { _doSplit( _ident, _kind, _name ); }
00084
00085 Solvable::SplitIdent::SplitIdent( ResKind kind_r, const C_Str & name_r )
00086 : _ident( name_r )
00087 , _kind( kind_r )
00088 { _doSplit( _ident, _kind, _name ); }
00089
00090 ResKind Solvable::SplitIdent::explicitKind( const char * ident_r )
00091 {
00092 if ( ! ident_r )
00093 return ResKind();
00094
00095 const char * sep = ::strchr( ident_r, ':' );
00096 if ( ! sep )
00097 return ResKind();
00098
00099 ResKind ret;
00100 if ( sep-ident_r >= 4 )
00101 {
00102 switch ( ident_r[3] )
00103 {
00104 #define OUTS(K,S) if ( !::strncmp( ident_r, ResKind::K.c_str(), S ) && ident_r[S] == ':' ) ret = ResKind::K
00105
00106 case 'c': OUTS( patch, 5 ); break;
00107 case 'd': OUTS( product, 7 ); break;
00108 case 'k': OUTS( package, 7 ); break;
00109 case 'p': OUTS( srcpackage, 10 ); break;
00110 case 't': OUTS( pattern, 7 ); break;
00111 #undef OUTS
00112 }
00113 }
00114 return ret;
00115 }
00116
00118
00119 const Solvable Solvable::noSolvable;
00120
00122
00123 ::_Solvable * Solvable::get() const
00124 { return myPool().getSolvable( _id ); }
00125
00126 #define NO_SOLVABLE_RETURN( VAL ) \
00127 ::_Solvable * _solvable( get() ); \
00128 if ( ! _solvable ) return VAL
00129
00130 Solvable Solvable::nextInPool() const
00131 { return Solvable( myPool().getNextId( _id ) ); }
00132
00133 Solvable Solvable::nextInRepo() const
00134 {
00135 NO_SOLVABLE_RETURN( noSolvable );
00136 for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
00137 {
00138 ::_Solvable * nextS( myPool().getSolvable( next ) );
00139 if ( nextS && nextS->repo == _solvable->repo )
00140 {
00141 return Solvable( next );
00142 }
00143 }
00144 return noSolvable;
00145 }
00146
00147 Repository Solvable::repository() const
00148 {
00149 NO_SOLVABLE_RETURN( Repository::noRepository );
00150 return Repository( _solvable->repo );
00151 }
00152
00153 bool Solvable::isSystem() const
00154 {
00155 NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
00156 return myPool().isSystemRepo( _solvable->repo );
00157 }
00158
00159 bool Solvable::onSystemByUser() const
00160 {
00161 return isSystem() && myPool().isOnSystemByUser( ident() );
00162 }
00163
00164 IdString Solvable::ident() const
00165 {
00166 NO_SOLVABLE_RETURN( IdString() );
00167 return IdString( _solvable->name );
00168 }
00169
00170 std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
00171 {
00172 NO_SOLVABLE_RETURN( std::string() );
00173 const char * s = ::solvable_lookup_str( _solvable, attr.id() );
00174 return s ? s : std::string();
00175 }
00176
00177 std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
00178 {
00179 NO_SOLVABLE_RETURN( std::string() );
00180 const char * s = 0;
00181 if ( lang_r == Locale::noCode )
00182 {
00183 s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
00184 }
00185 else
00186 {
00187 for ( Locale l( lang_r ); l != Locale::noCode; l = l.fallback() )
00188 if ( (s = ::solvable_lookup_str_lang( _solvable, attr.id(), l.code().c_str(), 0 )) )
00189 return s;
00190
00191 s = ::solvable_lookup_str_lang( _solvable, attr.id(), 0, 0 );
00192 }
00193 return s ? s : std::string();
00194 }
00195
00196 unsigned Solvable::lookupNumAttribute( const SolvAttr & attr ) const
00197 {
00198 NO_SOLVABLE_RETURN( 0 );
00199 return ::solvable_lookup_num( _solvable, attr.id(), 0 );
00200 }
00201
00202 bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
00203 {
00204 NO_SOLVABLE_RETURN( false );
00205 return ::solvable_lookup_bool( _solvable, attr.id() );
00206 }
00207
00208 detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
00209 {
00210 NO_SOLVABLE_RETURN( detail::noId );
00211 return ::solvable_lookup_id( _solvable, attr.id() );
00212 }
00213
00214 CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
00215 {
00216 NO_SOLVABLE_RETURN( CheckSum() );
00217 detail::IdType chksumtype = 0;
00218 const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
00219 if ( ! s )
00220 return CheckSum();
00221 switch ( chksumtype )
00222 {
00223 case REPOKEY_TYPE_MD5: return CheckSum::md5( s );
00224 case REPOKEY_TYPE_SHA1: return CheckSum::sha1( s );
00225 case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
00226 }
00227 return CheckSum( std::string(), s );
00228 }
00229
00231 namespace
00232 {
00233 inline Pathname lookupDatadirIn( Repository repor_r )
00234 {
00235 static const sat::SolvAttr susetagsDatadir( "susetags:datadir" );
00236 Pathname ret;
00237
00238
00239 sat::LookupRepoAttr datadir( susetagsDatadir, repor_r );
00240 if ( ! datadir.empty() )
00241 ret = datadir.begin().asString();
00242 else
00243 {
00244 sat::LookupAttr datadir( susetagsDatadir, repor_r );
00245 if ( ! datadir.empty() )
00246 ret = datadir.begin().asString();
00247 }
00248 return ret;
00249 }
00250 }
00252
00253 OnMediaLocation Solvable::lookupLocation() const
00254 {
00255 NO_SOLVABLE_RETURN( OnMediaLocation() );
00256
00257 unsigned medianr;
00258 char * file = ::solvable_get_location( _solvable, &medianr );
00259 if ( ! file )
00260 return OnMediaLocation();
00261
00262 OnMediaLocation ret;
00263
00264 Pathname path;
00265 switch ( repository().info().type().toEnum() )
00266 {
00267 case repo::RepoType::NONE_e:
00268 {
00269 path = lookupDatadirIn( repository() );
00270 if ( ! path.empty() )
00271 repository().info().setProbedType( repo::RepoType::YAST2_e );
00272 }
00273 break;
00274
00275 case repo::RepoType::YAST2_e:
00276 {
00277 path = lookupDatadirIn( repository() );
00278 if ( path.empty() )
00279 path = "suse";
00280 }
00281 break;
00282
00283 default:
00284 break;
00285 }
00286 ret.setLocation ( path/file, medianr );
00287 ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ), ByteCount::K ) );
00288 ret.setChecksum ( lookupCheckSumAttribute( SolvAttr::checksum ) );
00289
00290
00291
00292 return ret;
00293 }
00294
00295 ResKind Solvable::kind() const
00296 {
00297 NO_SOLVABLE_RETURN( ResKind() );
00298
00299 switch ( _solvable->arch )
00300 {
00301 case ARCH_SRC:
00302 case ARCH_NOSRC:
00303 return ResKind::srcpackage;
00304 break;
00305 }
00306
00307 const char * ident = IdString( _solvable->name ).c_str();
00308 const char * sep = ::strchr( ident, ':' );
00309
00310
00311 if ( ! sep )
00312 return ResKind::package;
00313
00314
00315 if ( sep-ident >= 4 )
00316 {
00317 switch ( ident[3] )
00318 {
00319 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
00320
00321 case 'c': OUTS( patch, 5 ); break;
00322 case 'd': OUTS( product, 7 ); break;
00323 case 'k': OUTS( package, 7 ); break;
00324 case 'p': OUTS( srcpackage, 10 ); break;
00325 case 't': OUTS( pattern, 7 ); break;
00326 #undef OUTS
00327 }
00328 }
00329
00330
00331 return ResKind( std::string( ident, sep-ident ) );
00332 }
00333
00334 bool Solvable::isKind( const ResKind & kind_r ) const
00335 {
00336 NO_SOLVABLE_RETURN( false );
00337
00338
00339 switch ( _solvable->arch )
00340 {
00341 case ARCH_SRC:
00342 case ARCH_NOSRC:
00343 return( kind_r == ResKind::srcpackage );
00344 break;
00345 }
00346
00347
00348 const char * ident = IdString( _solvable->name ).c_str();
00349 if ( kind_r == ResKind::package )
00350 {
00351 return( ::strchr( ident, ':' ) == 0 );
00352 }
00353
00354
00355 const char * kind = kind_r.c_str();
00356 unsigned ksize = ::strlen( kind );
00357 return( ::strncmp( ident, kind, ksize ) == 0
00358 && ident[ksize] == ':' );
00359 }
00360
00361 std::string Solvable::name() const
00362 {
00363 NO_SOLVABLE_RETURN( std::string() );
00364 const char * ident = IdString( _solvable->name ).c_str();
00365 const char * sep = ::strchr( ident, ':' );
00366 return( sep ? sep+1 : ident );
00367 }
00368
00369 Edition Solvable::edition() const
00370 {
00371 NO_SOLVABLE_RETURN( Edition() );
00372 return Edition( _solvable->evr );
00373 }
00374
00375 Arch Solvable::arch() const
00376 {
00377 NO_SOLVABLE_RETURN( Arch_noarch );
00378 switch ( _solvable->arch )
00379 {
00380 case ARCH_SRC:
00381 case ARCH_NOSRC:
00382 return Arch_noarch;
00383 break;
00384 }
00385 return Arch( IdString(_solvable->arch).asString() );
00386
00387 }
00388
00389 bool Solvable::multiversionInstall() const
00390 {
00391 return myPool().isMultiversion( ident() );
00392 }
00393
00394 IdString Solvable::vendor() const
00395 {
00396 NO_SOLVABLE_RETURN( IdString() );
00397 return IdString( _solvable->vendor );
00398 }
00399
00400 Capabilities Solvable::operator[]( Dep which_r ) const
00401 {
00402 switch( which_r.inSwitch() )
00403 {
00404 case Dep::PROVIDES_e: return provides(); break;
00405 case Dep::REQUIRES_e: return requires(); break;
00406 case Dep::CONFLICTS_e: return conflicts(); break;
00407 case Dep::OBSOLETES_e: return obsoletes(); break;
00408 case Dep::RECOMMENDS_e: return recommends(); break;
00409 case Dep::SUGGESTS_e: return suggests(); break;
00410 case Dep::ENHANCES_e: return enhances(); break;
00411 case Dep::SUPPLEMENTS_e: return supplements(); break;
00412 case Dep::PREREQUIRES_e: return prerequires(); break;
00413 }
00414 return Capabilities();
00415 }
00416
00417 inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
00418 {
00419 return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
00420 }
00421 Capabilities Solvable::provides() const
00422 {
00423 NO_SOLVABLE_RETURN( Capabilities() );
00424 return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
00425 }
00426 Capabilities Solvable::requires() const
00427 {
00428 NO_SOLVABLE_RETURN( Capabilities() );
00429 return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
00430 }
00431 Capabilities Solvable::conflicts() const
00432 {
00433 NO_SOLVABLE_RETURN( Capabilities() );
00434 return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
00435 }
00436 Capabilities Solvable::obsoletes() const
00437 {
00438 NO_SOLVABLE_RETURN( Capabilities() );
00439 return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
00440 }
00441 Capabilities Solvable::recommends() const
00442 {
00443 NO_SOLVABLE_RETURN( Capabilities() );
00444 return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
00445 }
00446 Capabilities Solvable::suggests() const
00447 {
00448 NO_SOLVABLE_RETURN( Capabilities() );
00449 return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
00450 }
00451 Capabilities Solvable::enhances() const
00452 {
00453 NO_SOLVABLE_RETURN( Capabilities() );
00454 return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
00455 }
00456 Capabilities Solvable::supplements() const
00457 {
00458 NO_SOLVABLE_RETURN( Capabilities() );
00459 return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
00460 }
00461 Capabilities Solvable::prerequires() const
00462 {
00463 NO_SOLVABLE_RETURN( Capabilities() );
00464
00465 ::Offset offs = _solvable->requires;
00466 return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
00467 : Capabilities();
00468 }
00469
00470 CapabilitySet Solvable::providesNamespace( const std::string & namespace_r ) const
00471 {
00472 NO_SOLVABLE_RETURN( CapabilitySet() );
00473 CapabilitySet ret;
00474 Capabilities caps( provides() );
00475 for_( it, caps.begin(), caps.end() )
00476 {
00477 CapDetail caprep( it->detail() );
00478 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
00479 ret.insert( *it );
00480 }
00481 return ret;
00482 }
00483
00484 CapabilitySet Solvable::valuesOfNamespace( const std::string & namespace_r ) const
00485 {
00486 NO_SOLVABLE_RETURN( CapabilitySet() );
00487 CapabilitySet ret;
00488 Capabilities caps( provides() );
00489 for_( it, caps.begin(), caps.end() )
00490 {
00491 CapDetail caprep( it->detail() );
00492 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
00493 {
00494 std::string value( caprep.name().c_str()+namespace_r.size()+1 );
00495 value[value.size()-1] = '\0';
00496 ret.insert( Capability( value, caprep.op(), caprep.ed() ) );
00497 }
00498 }
00499 return ret;
00500 }
00501
00502
00503 std::string Solvable::asString() const
00504 {
00505 NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
00506 return str::form( "%s-%s.%s",
00507 IdString( _solvable->name ).c_str(),
00508 IdString( _solvable->evr ).c_str(),
00509 IdString( _solvable->arch ).c_str() );
00510 }
00511
00512 bool Solvable::identical( Solvable rhs ) const
00513 {
00514 NO_SOLVABLE_RETURN( ! rhs.get() );
00515 ::_Solvable * rhssolvable( rhs.get() );
00516 return rhssolvable && ( _solvable == rhssolvable || ::solvable_identical( _solvable, rhssolvable ) );
00517 }
00518
00520 namespace
00521 {
00522
00526 int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
00527 {
00528 CapDetail detail( cap_r );
00529 if ( detail.kind() == CapDetail::EXPRESSION )
00530 {
00531 switch ( detail.capRel() )
00532 {
00533 case CapDetail::CAP_AND:
00534 case CapDetail::CAP_OR:
00535
00536 {
00537 int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
00538 if ( res < 0 )
00539 return res;
00540 int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
00541 if ( res2 < 0 )
00542 return -res + res2;
00543 return res + res2;
00544 }
00545 break;
00546
00547 case CapDetail::CAP_NAMESPACE:
00548 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
00549 {
00550 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1;
00551 }
00552 break;
00553
00554 case CapDetail::REL_NONE:
00555 case CapDetail::CAP_WITH:
00556 case CapDetail::CAP_ARCH:
00557 break;
00558 }
00559 }
00560 return 0;
00561 }
00562
00567 inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
00568 {
00569 int cnt = 0;
00570 for_( cit, cap_r.begin(), cap_r.end() )
00571 {
00572 int res = invokeOnEachSupportedLocale( *cit, fnc_r );
00573 if ( res < 0 )
00574 return -cnt + res;
00575 cnt += res;
00576 }
00577 return cnt;
00578 }
00580
00581
00582 struct NoMatchIn
00583 {
00584 NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
00585
00586 bool operator()( const Locale & locale_r ) const
00587 {
00588 return _locales.find( locale_r ) == _locales.end();
00589 }
00590
00591 const LocaleSet & _locales;
00592 };
00593
00594 }
00595
00596 bool Solvable::supportsLocales() const
00597 {
00598
00599 return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
00600 }
00601
00602 bool Solvable::supportsLocale( const Locale & locale_r ) const
00603 {
00604
00605 return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
00606 }
00607
00608 bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
00609 {
00610 if ( locales_r.empty() )
00611 return false;
00612
00613 return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
00614 }
00615
00616 bool Solvable::supportsRequestedLocales() const
00617 { return supportsLocale( myPool().getRequestedLocales() ); }
00618
00619 void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
00620 {
00621 invokeOnEachSupportedLocale( supplements(),
00622 functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
00623 }
00624
00625
00626
00627
00628
00629
00630 std::ostream & operator<<( std::ostream & str, const Solvable & obj )
00631 {
00632 if ( ! obj )
00633 return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
00634
00635 return str << "(" << obj.id() << ")"
00636 << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
00637 << '-' << obj.edition() << '.' << obj.arch() << "("
00638 << obj.repository().alias() << ")";
00639 }
00640
00641
00642
00643
00644
00645
00646 std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
00647 {
00648 str << obj;
00649 if ( obj )
00650 {
00651 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
00652 OUTS(PROVIDES);
00653 OUTS(PREREQUIRES);
00654 OUTS(REQUIRES);
00655 OUTS(CONFLICTS);
00656 OUTS(OBSOLETES);
00657 OUTS(RECOMMENDS);
00658 OUTS(SUGGESTS);
00659 OUTS(ENHANCES);
00660 OUTS(SUPPLEMENTS);
00661 #undef OUTS
00662 }
00663 return str;
00664 }
00665
00667 }
00670 }