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 IdString Solvable::ident() const
00160 {
00161 NO_SOLVABLE_RETURN( IdString() );
00162 return IdString( _solvable->name );
00163 }
00164
00165 std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
00166 {
00167 NO_SOLVABLE_RETURN( std::string() );
00168 const char * s = ::solvable_lookup_str( _solvable, attr.id() );
00169 return s ? s : std::string();
00170 }
00171
00172 std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
00173 {
00174 NO_SOLVABLE_RETURN( std::string() );
00175 const char * s = 0;
00176 if ( lang_r == Locale::noCode )
00177 {
00178 s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
00179 }
00180 else
00181 {
00182 for ( Locale l( lang_r ); l != Locale::noCode; l = l.fallback() )
00183 if ( (s = ::solvable_lookup_str_lang( _solvable, attr.id(), l.code().c_str(), 0 )) )
00184 return s;
00185
00186 s = ::solvable_lookup_str_lang( _solvable, attr.id(), 0, 0 );
00187 }
00188 return s ? s : std::string();
00189 }
00190
00191 unsigned Solvable::lookupNumAttribute( const SolvAttr & attr ) const
00192 {
00193 NO_SOLVABLE_RETURN( 0 );
00194 return ::solvable_lookup_num( _solvable, attr.id(), 0 );
00195 }
00196
00197 bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
00198 {
00199 NO_SOLVABLE_RETURN( false );
00200 return ::solvable_lookup_bool( _solvable, attr.id() );
00201 }
00202
00203 detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
00204 {
00205 NO_SOLVABLE_RETURN( detail::noId );
00206 return ::solvable_lookup_id( _solvable, attr.id() );
00207 }
00208
00209 CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
00210 {
00211 NO_SOLVABLE_RETURN( CheckSum() );
00212 detail::IdType chksumtype = 0;
00213 const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
00214 if ( ! s )
00215 return CheckSum();
00216 switch ( chksumtype )
00217 {
00218 case REPOKEY_TYPE_MD5: return CheckSum::md5( s );
00219 case REPOKEY_TYPE_SHA1: return CheckSum::sha1( s );
00220 case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
00221 }
00222 return CheckSum( std::string(), s );
00223 }
00224
00226 namespace
00227 {
00228 inline Pathname lookupDatadirIn( Repository repor_r )
00229 {
00230 static const sat::SolvAttr susetagsDatadir( "susetags:datadir" );
00231 Pathname ret;
00232
00233
00234 sat::LookupRepoAttr datadir( susetagsDatadir, repor_r );
00235 if ( ! datadir.empty() )
00236 ret = datadir.begin().asString();
00237 else
00238 {
00239 sat::LookupAttr datadir( susetagsDatadir, repor_r );
00240 if ( ! datadir.empty() )
00241 ret = datadir.begin().asString();
00242 }
00243 return ret;
00244 }
00245 }
00247
00248 OnMediaLocation Solvable::lookupLocation() const
00249 {
00250 NO_SOLVABLE_RETURN( OnMediaLocation() );
00251
00252 unsigned medianr;
00253 char * file = ::solvable_get_location( _solvable, &medianr );
00254 if ( ! file )
00255 return OnMediaLocation();
00256
00257 OnMediaLocation ret;
00258
00259 Pathname path;
00260 switch ( repository().info().type().toEnum() )
00261 {
00262 case repo::RepoType::NONE_e:
00263 {
00264 path = lookupDatadirIn( repository() );
00265 if ( ! path.empty() )
00266 repository().info().setProbedType( repo::RepoType::YAST2_e );
00267 }
00268 break;
00269
00270 case repo::RepoType::YAST2_e:
00271 {
00272 path = lookupDatadirIn( repository() );
00273 if ( path.empty() )
00274 path = "suse";
00275 }
00276 break;
00277
00278 default:
00279 break;
00280 }
00281 ret.setLocation ( path/file, medianr );
00282 ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ), ByteCount::K ) );
00283 ret.setChecksum ( lookupCheckSumAttribute( SolvAttr::checksum ) );
00284
00285
00286
00287 return ret;
00288 }
00289
00290 ResKind Solvable::kind() const
00291 {
00292 NO_SOLVABLE_RETURN( ResKind() );
00293
00294 switch ( _solvable->arch )
00295 {
00296 case ARCH_SRC:
00297 case ARCH_NOSRC:
00298 return ResKind::srcpackage;
00299 break;
00300 }
00301
00302 const char * ident = IdString( _solvable->name ).c_str();
00303 const char * sep = ::strchr( ident, ':' );
00304
00305
00306 if ( ! sep )
00307 return ResKind::package;
00308
00309
00310 if ( sep-ident >= 4 )
00311 {
00312 switch ( ident[3] )
00313 {
00314 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
00315
00316 case 'c': OUTS( patch, 5 ); break;
00317 case 'd': OUTS( product, 7 ); break;
00318 case 'k': OUTS( package, 7 ); break;
00319 case 'p': OUTS( srcpackage, 10 ); break;
00320 case 't': OUTS( pattern, 7 ); break;
00321 #undef OUTS
00322 }
00323 }
00324
00325
00326 return ResKind( std::string( ident, sep-ident ) );
00327 }
00328
00329 bool Solvable::isKind( const ResKind & kind_r ) const
00330 {
00331 NO_SOLVABLE_RETURN( false );
00332
00333
00334 switch ( _solvable->arch )
00335 {
00336 case ARCH_SRC:
00337 case ARCH_NOSRC:
00338 return( kind_r == ResKind::srcpackage );
00339 break;
00340 }
00341
00342
00343 const char * ident = IdString( _solvable->name ).c_str();
00344 if ( kind_r == ResKind::package )
00345 {
00346 return( ::strchr( ident, ':' ) == 0 );
00347 }
00348
00349
00350 const char * kind = kind_r.c_str();
00351 unsigned ksize = ::strlen( kind );
00352 return( ::strncmp( ident, kind, ksize ) == 0
00353 && ident[ksize] == ':' );
00354 }
00355
00356 std::string Solvable::name() const
00357 {
00358 NO_SOLVABLE_RETURN( std::string() );
00359 const char * ident = IdString( _solvable->name ).c_str();
00360 const char * sep = ::strchr( ident, ':' );
00361 return( sep ? sep+1 : ident );
00362 }
00363
00364 Edition Solvable::edition() const
00365 {
00366 NO_SOLVABLE_RETURN( Edition() );
00367 return Edition( _solvable->evr );
00368 }
00369
00370 Arch Solvable::arch() const
00371 {
00372 NO_SOLVABLE_RETURN( Arch_noarch );
00373 switch ( _solvable->arch )
00374 {
00375 case ARCH_SRC:
00376 case ARCH_NOSRC:
00377 return Arch_noarch;
00378 break;
00379 }
00380 return Arch( IdString(_solvable->arch).asString() );
00381
00382 }
00383
00384 bool Solvable::multiversionInstall() const
00385 {
00386 return myPool().isMultiversion( ident() );
00387 }
00388
00389 bool Solvable::installOnly() const { return multiversionInstall(); }
00390
00391 IdString Solvable::vendor() const
00392 {
00393 NO_SOLVABLE_RETURN( IdString() );
00394 return IdString( _solvable->vendor );
00395 }
00396
00397 Capabilities Solvable::operator[]( Dep which_r ) const
00398 {
00399 switch( which_r.inSwitch() )
00400 {
00401 case Dep::PROVIDES_e: return provides(); break;
00402 case Dep::REQUIRES_e: return requires(); break;
00403 case Dep::CONFLICTS_e: return conflicts(); break;
00404 case Dep::OBSOLETES_e: return obsoletes(); break;
00405 case Dep::RECOMMENDS_e: return recommends(); break;
00406 case Dep::SUGGESTS_e: return suggests(); break;
00407 case Dep::ENHANCES_e: return enhances(); break;
00408 case Dep::SUPPLEMENTS_e: return supplements(); break;
00409 case Dep::PREREQUIRES_e: return prerequires(); break;
00410 }
00411 return Capabilities();
00412 }
00413
00414 inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
00415 {
00416 return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
00417 }
00418 Capabilities Solvable::provides() const
00419 {
00420 NO_SOLVABLE_RETURN( Capabilities() );
00421 return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
00422 }
00423 Capabilities Solvable::requires() const
00424 {
00425 NO_SOLVABLE_RETURN( Capabilities() );
00426 return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
00427 }
00428 Capabilities Solvable::conflicts() const
00429 {
00430 NO_SOLVABLE_RETURN( Capabilities() );
00431 return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
00432 }
00433 Capabilities Solvable::obsoletes() const
00434 {
00435 NO_SOLVABLE_RETURN( Capabilities() );
00436 return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
00437 }
00438 Capabilities Solvable::recommends() const
00439 {
00440 NO_SOLVABLE_RETURN( Capabilities() );
00441 return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
00442 }
00443 Capabilities Solvable::suggests() const
00444 {
00445 NO_SOLVABLE_RETURN( Capabilities() );
00446 return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
00447 }
00448 Capabilities Solvable::enhances() const
00449 {
00450 NO_SOLVABLE_RETURN( Capabilities() );
00451 return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
00452 }
00453 Capabilities Solvable::supplements() const
00454 {
00455 NO_SOLVABLE_RETURN( Capabilities() );
00456 return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
00457 }
00458 Capabilities Solvable::prerequires() const
00459 {
00460 NO_SOLVABLE_RETURN( Capabilities() );
00461
00462 ::Offset offs = _solvable->requires;
00463 return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
00464 : Capabilities();
00465 }
00466
00467 CapabilitySet Solvable::providesNamespace( const std::string & namespace_r ) const
00468 {
00469 NO_SOLVABLE_RETURN( CapabilitySet() );
00470 CapabilitySet ret;
00471 Capabilities caps( provides() );
00472 for_( it, caps.begin(), caps.end() )
00473 {
00474 CapDetail caprep( it->detail() );
00475 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
00476 ret.insert( *it );
00477 }
00478 return ret;
00479 }
00480
00481 CapabilitySet Solvable::valuesOfNamespace( const std::string & namespace_r ) const
00482 {
00483 NO_SOLVABLE_RETURN( CapabilitySet() );
00484 CapabilitySet ret;
00485 Capabilities caps( provides() );
00486 for_( it, caps.begin(), caps.end() )
00487 {
00488 CapDetail caprep( it->detail() );
00489 if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
00490 {
00491 std::string value( caprep.name().c_str()+namespace_r.size()+1 );
00492 value[value.size()-1] = '\0';
00493 ret.insert( Capability( value, caprep.op(), caprep.ed() ) );
00494 }
00495 }
00496 return ret;
00497 }
00498
00499
00500 std::string Solvable::asString() const
00501 {
00502 NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
00503 return str::form( "%s-%s.%s",
00504 IdString( _solvable->name ).c_str(),
00505 IdString( _solvable->evr ).c_str(),
00506 IdString( _solvable->arch ).c_str() );
00507 }
00508
00509 bool Solvable::identical( Solvable rhs ) const
00510 {
00511 NO_SOLVABLE_RETURN( ! rhs.get() );
00512 ::_Solvable * rhssolvable( rhs.get() );
00513 return rhssolvable && ( _solvable == rhssolvable || ::solvable_identical( _solvable, rhssolvable ) );
00514 }
00515
00517 namespace
00518 {
00519
00523 int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
00524 {
00525 CapDetail detail( cap_r );
00526 if ( detail.kind() == CapDetail::EXPRESSION )
00527 {
00528 switch ( detail.capRel() )
00529 {
00530 case CapDetail::CAP_AND:
00531 case CapDetail::CAP_OR:
00532
00533 {
00534 int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
00535 if ( res < 0 )
00536 return res;
00537 int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
00538 if ( res2 < 0 )
00539 return -res + res2;
00540 return res + res2;
00541 }
00542 break;
00543
00544 case CapDetail::CAP_NAMESPACE:
00545 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
00546 {
00547 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1;
00548 }
00549 break;
00550
00551 case CapDetail::REL_NONE:
00552 case CapDetail::CAP_WITH:
00553 case CapDetail::CAP_ARCH:
00554 break;
00555 }
00556 }
00557 return 0;
00558 }
00559
00564 inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
00565 {
00566 int cnt = 0;
00567 for_( cit, cap_r.begin(), cap_r.end() )
00568 {
00569 int res = invokeOnEachSupportedLocale( *cit, fnc_r );
00570 if ( res < 0 )
00571 return -cnt + res;
00572 cnt += res;
00573 }
00574 return cnt;
00575 }
00577
00578
00579 struct NoMatchIn
00580 {
00581 NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
00582
00583 bool operator()( const Locale & locale_r ) const
00584 {
00585 return _locales.find( locale_r ) == _locales.end();
00586 }
00587
00588 const LocaleSet & _locales;
00589 };
00590
00591 }
00592
00593 bool Solvable::supportsLocales() const
00594 {
00595
00596 return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
00597 }
00598
00599 bool Solvable::supportsLocale( const Locale & locale_r ) const
00600 {
00601
00602 return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
00603 }
00604
00605 bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
00606 {
00607 if ( locales_r.empty() )
00608 return false;
00609
00610 return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
00611 }
00612
00613 bool Solvable::supportsRequestedLocales() const
00614 { return supportsLocale( myPool().getRequestedLocales() ); }
00615
00616 void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
00617 {
00618 invokeOnEachSupportedLocale( supplements(),
00619 functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
00620 }
00621
00622
00623
00624
00625
00626
00627 std::ostream & operator<<( std::ostream & str, const Solvable & obj )
00628 {
00629 if ( ! obj )
00630 return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
00631
00632 return str << "(" << obj.id() << ")"
00633 << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
00634 << '-' << obj.edition() << '.' << obj.arch() << "("
00635 << obj.repository().alias() << ")";
00636 }
00637
00638
00639
00640
00641
00642
00643 std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
00644 {
00645 str << obj;
00646 if ( obj )
00647 {
00648 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
00649 OUTS(PROVIDES);
00650 OUTS(PREREQUIRES);
00651 OUTS(REQUIRES);
00652 OUTS(CONFLICTS);
00653 OUTS(OBSOLETES);
00654 OUTS(RECOMMENDS);
00655 OUTS(SUGGESTS);
00656 OUTS(ENHANCES);
00657 OUTS(SUPPLEMENTS);
00658 #undef OUTS
00659 }
00660 return str;
00661 }
00662
00664 }
00667 }