00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013 #include <boost/mpl/int.hpp>
00014
00015 #include "zypp/base/Easy.h"
00016 #include "zypp/base/LogTools.h"
00017 #include "zypp/base/Gettext.h"
00018 #include "zypp/base/Exception.h"
00019 #include "zypp/base/Measure.h"
00020 #include "zypp/base/WatchFile.h"
00021 #include "zypp/base/Sysconfig.h"
00022
00023 #include "zypp/ZConfig.h"
00024
00025 #include "zypp/sat/detail/PoolImpl.h"
00026 #include "zypp/sat/Pool.h"
00027 #include "zypp/Capability.h"
00028 #include "zypp/Locale.h"
00029 #include "zypp/PoolItem.h"
00030
00031 #include "zypp/target/modalias/Modalias.h"
00032 #include "zypp/media/MediaPriority.h"
00033
00034 extern "C"
00035 {
00036
00037
00038
00039 void repo_add_helix( ::Repo *repo, FILE *fp, int flags );
00040 }
00041
00042 using std::endl;
00043
00044 #undef ZYPP_BASE_LOGGER_LOGGROUP
00045 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::satpool"
00046
00047
00048 namespace zypp
00049 {
00050
00051 namespace sat
00052 {
00053
00055 namespace detail
00056 {
00057
00058
00059
00060 BOOST_MPL_ASSERT_RELATION( noId, ==, STRID_NULL );
00061 BOOST_MPL_ASSERT_RELATION( emptyId, ==, STRID_EMPTY );
00062
00063 BOOST_MPL_ASSERT_RELATION( noSolvableId, ==, ID_NULL );
00064 BOOST_MPL_ASSERT_RELATION( systemSolvableId, ==, SYSTEMSOLVABLE );
00065
00066 BOOST_MPL_ASSERT_RELATION( solvablePrereqMarker, ==, SOLVABLE_PREREQMARKER );
00067 BOOST_MPL_ASSERT_RELATION( solvableFileMarker, ==, SOLVABLE_FILEMARKER );
00068
00069 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_AND, ==, REL_AND );
00070 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_OR, ==, REL_OR );
00071 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_WITH, ==, REL_WITH );
00072 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_NAMESPACE, ==, REL_NAMESPACE );
00073 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_ARCH, ==, REL_ARCH );
00074
00076
00077 const std::string & PoolImpl::systemRepoAlias()
00078 {
00079 static const std::string _val( "@System" );
00080 return _val;
00081 }
00082
00084
00085 static void logSat( struct _Pool *, void *data, int type, const char *logString )
00086 {
00087 if ( type & (SAT_FATAL|SAT_ERROR) ) {
00088 _ERR("satsolver") << logString;
00089 } else if ( type & SAT_DEBUG_STATS ) {
00090 _DBG("satsolver") << logString;
00091 } else {
00092 _MIL("satsolver") << logString;
00093 }
00094 }
00095
00096 detail::IdType PoolImpl::nsCallback( struct _Pool *, void * data, detail::IdType lhs, detail::IdType rhs )
00097 {
00098
00099
00100
00101
00102
00103
00104 static const detail::IdType RET_unsupported = 0;
00105 static const detail::IdType RET_systemProperty = 1;
00106 switch ( lhs )
00107 {
00108 case NAMESPACE_LANGUAGE:
00109 {
00110 static IdString en( "en" );
00111 const std::tr1::unordered_set<IdString> & locale2Solver( reinterpret_cast<PoolImpl*>(data)->_locale2Solver );
00112 if ( locale2Solver.empty() )
00113 {
00114 return rhs == en.id() ? RET_systemProperty : RET_unsupported;
00115 }
00116 return locale2Solver.find( IdString(rhs) ) != locale2Solver.end() ? RET_systemProperty : RET_unsupported;
00117 }
00118 break;
00119
00120 case NAMESPACE_MODALIAS:
00121 {
00122
00123
00124 return target::Modalias::instance().query( str::hexdecode( IdString(rhs).c_str() ) )
00125 ? RET_systemProperty
00126 : RET_unsupported;
00127 }
00128 break;
00129
00130 case NAMESPACE_FILESYSTEM:
00131 {
00132 static const Pathname sysconfigStoragePath( "/etc/sysconfig/storage" );
00133 static WatchFile sysconfigFile( sysconfigStoragePath, WatchFile::NO_INIT );
00134 static std::set<std::string> requiredFilesystems;
00135 if ( sysconfigFile.hasChanged() )
00136 {
00137 requiredFilesystems.clear();
00138 str::split( base::sysconfig::read( sysconfigStoragePath )["USED_FS_LIST"],
00139 std::inserter( requiredFilesystems, requiredFilesystems.end() ) );
00140 }
00141 return requiredFilesystems.find( IdString(rhs).asString() ) != requiredFilesystems.end() ? RET_systemProperty : RET_unsupported;
00142 }
00143 break;
00144
00145 case NAMESPACE_PRODUCTBUDDY:
00146 {
00147 PoolItem pi( (Solvable(rhs)) );
00148 return( pi ? pi.buddy().id() : noId );
00149 }
00150
00151 break;
00152 }
00153
00154 WAR << "Unhandled " << Capability( lhs ) << " vs. " << Capability( rhs ) << endl;
00155 return RET_unsupported;
00156 }
00157
00159
00160
00161
00162
00163 PoolImpl & PoolMember::myPool()
00164 {
00165 static PoolImpl _global;
00166 return _global;
00167 }
00168
00170
00171
00172
00173
00174 PoolImpl::PoolImpl()
00175 : _pool( ::pool_create() )
00176 {
00177 MIL << "Creating sat-pool." << endl;
00178 if ( ! _pool )
00179 {
00180 ZYPP_THROW( Exception( _("Can not create sat-pool.") ) );
00181 }
00182
00183 if ( getenv("ZYPP_LIBSAT_FULLLOG") )
00184 ::pool_setdebuglevel( _pool, 4 );
00185 else if ( getenv("ZYPP_FULLLOG") )
00186 ::pool_setdebuglevel( _pool, 2 );
00187 else
00188 ::pool_setdebugmask(_pool, SAT_DEBUG_JOB|SAT_DEBUG_STATS);
00189
00190 ::pool_setdebugcallback( _pool, logSat, NULL );
00191
00192
00193 _pool->nscallback = &nsCallback;
00194 _pool->nscallbackdata = (void*)this;
00195 }
00196
00198
00199
00200
00201
00202 PoolImpl::~PoolImpl()
00203 {
00204 ::pool_free( _pool );
00205 }
00206
00208
00209 void PoolImpl::setDirty( const char * a1, const char * a2, const char * a3 )
00210 {
00211 if ( a1 )
00212 {
00213 if ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
00214 else if ( a2 ) MIL << a1 << " " << a2 << endl;
00215 else MIL << a1 << endl;
00216 }
00217 _serial.setDirty();
00218 _availableLocalesPtr.reset();
00219 _multiversionListPtr.reset();
00220
00221
00222 depSetDirty();
00223 }
00224
00225 void PoolImpl::depSetDirty( const char * a1, const char * a2, const char * a3 )
00226 {
00227 if ( a1 )
00228 {
00229 if ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
00230 else if ( a2 ) MIL << a1 << " " << a2 << endl;
00231 else MIL << a1 << endl;
00232 }
00233 ::pool_freewhatprovides( _pool );
00234 }
00235
00236 void PoolImpl::prepare() const
00237 {
00238 if ( _watcher.remember( _serial ) )
00239 {
00240
00241
00242 ::pool_setarch( _pool, ZConfig::instance().systemArchitecture().asString().c_str() );
00243 }
00244 if ( ! _pool->whatprovides )
00245 {
00246 MIL << "pool_createwhatprovides..." << endl;
00247 ::pool_addfileprovides( _pool );
00248 ::pool_createwhatprovides( _pool );
00249 }
00250 if ( ! _pool->languages )
00251 {
00252
00253 const_cast<PoolImpl*>(this)->setTextLocale( ZConfig::instance().textLocale() );
00254 }
00255 }
00256
00258
00259 ::_Repo * PoolImpl::_createRepo( const std::string & name_r )
00260 {
00261 setDirty(__FUNCTION__, name_r.c_str() );
00262 ::_Repo * ret = ::repo_create( _pool, name_r.c_str() );
00263 if ( ret && name_r == systemRepoAlias() )
00264 ::pool_set_installed( _pool, ret );
00265 return ret;
00266 }
00267
00268 void PoolImpl::_deleteRepo( ::_Repo * repo_r )
00269 {
00270 setDirty(__FUNCTION__, repo_r->name );
00271 ::repo_free( repo_r, false );
00272 eraseRepoInfo( repo_r );
00273 }
00274
00275 int PoolImpl::_addSolv( ::_Repo * repo_r, FILE * file_r )
00276 {
00277 setDirty(__FUNCTION__, repo_r->name );
00278 int ret = ::repo_add_solv( repo_r , file_r );
00279 if ( ret == 0 )
00280 _postRepoAdd( repo_r );
00281 return ret;
00282 }
00283
00284 int PoolImpl::_addHelix( ::_Repo * repo_r, FILE * file_r )
00285 {
00286 setDirty(__FUNCTION__, repo_r->name );
00287 ::repo_add_helix( repo_r , file_r, 0 );
00288 _postRepoAdd( repo_r );
00289 return 0;
00290 }
00291
00292 void PoolImpl::_postRepoAdd( ::_Repo * repo_r )
00293 {
00294 if ( ! isSystemRepo( repo_r ) )
00295 {
00296
00297 std::set<detail::IdType> sysids;
00298 {
00299 Arch::CompatSet sysarchs( Arch::compatSet( ZConfig::instance().systemArchitecture() ) );
00300 for_( it, sysarchs.begin(), sysarchs.end() )
00301 sysids.insert( it->id() );
00302
00303
00304 sysids.insert( ARCH_SRC );
00305 sysids.insert( ARCH_NOSRC );
00306 }
00307
00308 detail::IdType blockBegin = 0;
00309 unsigned blockSize = 0;
00310 for ( detail::IdType i = repo_r->start; i < repo_r->end; ++i )
00311 {
00312 ::_Solvable * s( _pool->solvables + i );
00313 if ( s->repo == repo_r && sysids.find( s->arch ) == sysids.end() )
00314 {
00315
00316 if ( ! blockBegin )
00317 blockBegin = i;
00318 ++blockSize;
00319 }
00320 else if ( blockSize )
00321 {
00322
00323 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, false );
00324 blockBegin = blockSize = 0;
00325 }
00326 }
00327 if ( blockSize )
00328 {
00329
00330 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, false );
00331 blockBegin = blockSize = 0;
00332 }
00333 }
00334 }
00335
00336 detail::SolvableIdType PoolImpl::_addSolvables( ::_Repo * repo_r, unsigned count_r )
00337 {
00338 setDirty(__FUNCTION__, repo_r->name );
00339 return ::repo_add_solvable_block( repo_r, count_r );
00340 }
00341
00342 void PoolImpl::setRepoInfo( RepoIdType id_r, const RepoInfo & info_r )
00343 {
00344 ::_Repo * repo( getRepo( id_r ) );
00345 if ( repo )
00346 {
00347 bool dirty = false;
00348
00349
00350
00351 if ( repo->priority != int(-info_r.priority()) )
00352 {
00353 repo->priority = -info_r.priority();
00354 dirty = true;
00355 }
00356
00357
00358
00359 int mediaPriority( media::MediaPriority( info_r.url() ) );
00360 if ( repo->subpriority != mediaPriority )
00361 {
00362 repo->subpriority = mediaPriority;
00363 dirty = true;
00364 }
00365
00366 if ( dirty )
00367 setDirty(__FUNCTION__, info_r.alias().c_str() );
00368 }
00369 _repoinfos[id_r] = info_r;
00370 }
00371
00373
00374
00375 void _locale_hack( const LocaleSet & locales_r,
00376 std::tr1::unordered_set<IdString> & locale2Solver )
00377 {
00378 std::tr1::unordered_set<IdString>( 2*locales_r.size() ).swap( locale2Solver );
00379 for_( it, locales_r.begin(),locales_r.end() )
00380 {
00381 for ( Locale l( *it ); l != Locale::noCode; l = l.fallback() )
00382 locale2Solver.insert( IdString( l.code() ) );
00383 }
00384 MIL << "New Solver Locales: " << locale2Solver << endl;
00385 }
00386
00387 void PoolImpl::setTextLocale( const Locale & locale_r )
00388 {
00389 std::vector<std::string> fallbacklist;
00390 for ( Locale l( locale_r ); l != Locale::noCode; l = l.fallback() )
00391 {
00392 fallbacklist.push_back( l.code() );
00393 }
00394 dumpRangeLine( MIL << "pool_set_languages: ", fallbacklist.begin(), fallbacklist.end() ) << endl;
00395
00396 std::vector<const char *> fallbacklist_cstr;
00397 for_( it, fallbacklist.begin(), fallbacklist.end() )
00398 {
00399 fallbacklist_cstr.push_back( it->c_str() );
00400 }
00401 ::pool_set_languages( _pool, &fallbacklist_cstr.front(), fallbacklist_cstr.size() );
00402 }
00403
00404 void PoolImpl::setRequestedLocales( const LocaleSet & locales_r )
00405 {
00406 depSetDirty( "setRequestedLocales" );
00407 _requestedLocales = locales_r;
00408 MIL << "New RequestedLocales: " << locales_r << endl;
00409 _locale_hack( _requestedLocales, _locale2Solver );
00410 }
00411
00412 bool PoolImpl::addRequestedLocale( const Locale & locale_r )
00413 {
00414 if ( _requestedLocales.insert( locale_r ).second )
00415 {
00416 depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
00417 _locale_hack( _requestedLocales, _locale2Solver );
00418 return true;
00419 }
00420 return false;
00421 }
00422
00423 bool PoolImpl::eraseRequestedLocale( const Locale & locale_r )
00424 {
00425 if ( _requestedLocales.erase( locale_r ) )
00426 {
00427 depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
00428 _locale_hack( _requestedLocales, _locale2Solver );
00429 return true;
00430 }
00431 return false;
00432 }
00433
00434 static void _getLocaleDeps( Capability cap_r, std::tr1::unordered_set<sat::detail::IdType> & store_r )
00435 {
00436
00437 CapDetail detail( cap_r );
00438 if ( detail.kind() == CapDetail::EXPRESSION )
00439 {
00440 switch ( detail.capRel() )
00441 {
00442 case CapDetail::CAP_AND:
00443 case CapDetail::CAP_OR:
00444
00445 _getLocaleDeps( detail.lhs(), store_r );
00446 _getLocaleDeps( detail.rhs(), store_r );
00447 break;
00448
00449 case CapDetail::CAP_NAMESPACE:
00450 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
00451 {
00452 store_r.insert( detail.rhs().id() );
00453 }
00454 break;
00455
00456 case CapDetail::REL_NONE:
00457 case CapDetail::CAP_WITH:
00458 case CapDetail::CAP_ARCH:
00459 break;
00460 }
00461 }
00462 }
00463
00464 const LocaleSet & PoolImpl::getAvailableLocales() const
00465 {
00466 if ( !_availableLocalesPtr )
00467 {
00468
00469 std::tr1::unordered_set<sat::detail::IdType> tmp;
00470 Pool pool( Pool::instance() );
00471 for_( it, pool.solvablesBegin(), pool.solvablesEnd() )
00472 {
00473 Capabilities cap( it->supplements() );
00474 for_( cit, cap.begin(), cap.end() )
00475 {
00476 _getLocaleDeps( *cit, tmp );
00477 }
00478 }
00479 #warning immediately build LocaleSet as soon as Loale is an Id based type
00480 _availableLocalesPtr.reset( new LocaleSet(tmp.size()) );
00481 for_( it, tmp.begin(), tmp.end() )
00482 {
00483 _availableLocalesPtr->insert( Locale( IdString(*it) ) );
00484 }
00485 }
00486 return *_availableLocalesPtr;
00487 }
00488
00489 void PoolImpl::multiversionListInit() const
00490 {
00491 _multiversionListPtr.reset( new MultiversionList );
00492 MultiversionList & multiversionList( *_multiversionListPtr );
00493
00494 const std::set<std::string> & multiversionSpec( ZConfig::instance().multiversionSpec() );
00495 for_( it, multiversionSpec.begin(), multiversionSpec.end() )
00496 {
00497 static const std::string prefix( "provides:" );
00498 if ( str::hasPrefix( *it, prefix ) )
00499 {
00500 WhatProvides provides( Capability( it->c_str() + prefix.size() ) );
00501 if ( provides.empty() )
00502 {
00503 MIL << "Multiversion install not provided (" << *it << ")" << endl;
00504 }
00505 else
00506 {
00507 for_( pit, provides.begin(), provides.end() )
00508 {
00509 if ( multiversionList.insert( pit->ident() ).second )
00510 MIL << "Multiversion install " << pit->ident() << " (" << *it << ")" << endl;
00511 }
00512 }
00513 }
00514 else
00515 {
00516 MIL << "Multiversion install " << *it << endl;
00517 multiversionList.insert( IdString( *it ) );
00518 }
00519 }
00520 }
00521
00523 }
00526 }
00529 }