1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/sat/detail/PoolImpl.cc
14 #include <boost/mpl/int.hpp>
16 #include "zypp/base/Easy.h"
17 #include "zypp/base/LogTools.h"
18 #include "zypp/base/Gettext.h"
19 #include "zypp/base/Exception.h"
20 #include "zypp/base/Measure.h"
21 #include "zypp/base/WatchFile.h"
22 #include "zypp/base/Sysconfig.h"
23 #include "zypp/base/IOStream.h"
25 #include "zypp/ZConfig.h"
27 #include "zypp/sat/detail/PoolImpl.h"
28 #include "zypp/sat/Pool.h"
29 #include "zypp/Capability.h"
30 #include "zypp/Locale.h"
31 #include "zypp/PoolItem.h"
33 #include "zypp/target/modalias/Modalias.h"
34 #include "zypp/media/MediaPriority.h"
38 // Workaround libsolv project not providing a common include
39 // directory. (the -devel package does, but the git repo doesn't).
40 // #include <solv/repo_helix.h>
41 int repo_add_helix( ::Repo *repo, FILE *fp, int flags );
46 #undef ZYPP_BASE_LOGGER_LOGGROUP
47 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::satpool"
49 // ///////////////////////////////////////////////////////////////////
52 /////////////////////////////////////////////////////////////////
56 inline int LIBSOLV_DEBUGMASK()
58 const char * envp = getenv("LIBSOLV_DEBUGMASK");
59 return envp ? str::strtonum<int>( envp ) : 0;
62 ///////////////////////////////////////////////////////////////////
64 { /////////////////////////////////////////////////////////////////
66 ///////////////////////////////////////////////////////////////////
68 { /////////////////////////////////////////////////////////////////
70 // MPL checks for satlib constants we redefine to avoid
71 // includes and defines.
72 BOOST_MPL_ASSERT_RELATION( noId, ==, STRID_NULL );
73 BOOST_MPL_ASSERT_RELATION( emptyId, ==, STRID_EMPTY );
75 BOOST_MPL_ASSERT_RELATION( noSolvableId, ==, ID_NULL );
76 BOOST_MPL_ASSERT_RELATION( systemSolvableId, ==, SYSTEMSOLVABLE );
78 BOOST_MPL_ASSERT_RELATION( solvablePrereqMarker, ==, SOLVABLE_PREREQMARKER );
79 BOOST_MPL_ASSERT_RELATION( solvableFileMarker, ==, SOLVABLE_FILEMARKER );
81 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_AND, ==, REL_AND );
82 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_OR, ==, REL_OR );
83 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_WITH, ==, REL_WITH );
84 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_NAMESPACE, ==, REL_NAMESPACE );
85 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_ARCH, ==, REL_ARCH );
87 /////////////////////////////////////////////////////////////////
89 const std::string & PoolImpl::systemRepoAlias()
91 static const std::string _val( "@System" );
95 const Pathname & sysconfigStoragePath()
97 static const Pathname _val( "/etc/sysconfig/storage" );
102 /////////////////////////////////////////////////////////////////
104 static void logSat( struct _Pool *, void *data, int type, const char *logString )
106 if ( type & (SOLV_FATAL|SOLV_ERROR) ) {
107 _ERR("libsolv") << logString;
108 } else if ( type & SOLV_DEBUG_STATS ) {
109 _DBG("libsolv") << logString;
111 _MIL("libsolv") << logString;
115 detail::IdType PoolImpl::nsCallback( struct _Pool *, void * data, detail::IdType lhs, detail::IdType rhs )
117 // lhs: the namespace identifier, e.g. NAMESPACE:MODALIAS
118 // rhs: the value, e.g. pci:v0000104Cd0000840[01]sv*sd*bc*sc*i*
119 // return: 0 if not supportded
120 // 1 if supported by the system
121 // -1 AFAIK it's also possible to return a list of solvables that support it, but don't know how.
123 static const detail::IdType RET_unsupported = 0;
124 static const detail::IdType RET_systemProperty = 1;
127 case NAMESPACE_LANGUAGE:
129 static IdString en( "en" );
130 const std::tr1::unordered_set<IdString> & locale2Solver( reinterpret_cast<PoolImpl*>(data)->_locale2Solver );
131 if ( locale2Solver.empty() )
133 return rhs == en.id() ? RET_systemProperty : RET_unsupported;
135 return locale2Solver.find( IdString(rhs) ) != locale2Solver.end() ? RET_systemProperty : RET_unsupported;
139 case NAMESPACE_MODALIAS:
141 // modalias strings in capability may be hexencoded because rpm does not allow
142 // ',', ' ' or other special chars.
143 return target::Modalias::instance().query( str::hexdecode( IdString(rhs).c_str() ) )
149 case NAMESPACE_FILESYSTEM:
151 const std::set<std::string> & requiredFilesystems( reinterpret_cast<PoolImpl*>(data)->requiredFilesystems() );
152 return requiredFilesystems.find( IdString(rhs).asString() ) != requiredFilesystems.end() ? RET_systemProperty : RET_unsupported;
158 WAR << "Unhandled " << Capability( lhs ) << " vs. " << Capability( rhs ) << endl;
159 return RET_unsupported;
162 ///////////////////////////////////////////////////////////////////
164 // METHOD NAME : PoolMember::myPool
165 // METHOD TYPE : PoolImpl
167 PoolImpl & PoolMember::myPool()
169 static PoolImpl _global;
173 ///////////////////////////////////////////////////////////////////
175 // METHOD NAME : PoolImpl::PoolImpl
176 // METHOD TYPE : Ctor
179 : _pool( ::pool_create() )
181 MIL << "Creating sat-pool." << endl;
184 ZYPP_THROW( Exception( _("Can not create sat-pool.") ) );
186 // by now we support only a RPM backend
187 ::pool_setdisttype(_pool, DISTTYPE_RPM );
189 // initialialize logging
190 if ( env::LIBSOLV_DEBUGMASK() )
192 ::pool_setdebugmask(_pool, env::LIBSOLV_DEBUGMASK() );
196 if ( getenv("ZYPP_LIBSOLV_FULLLOG") || getenv("ZYPP_LIBSAT_FULLLOG") )
197 ::pool_setdebuglevel( _pool, 3 );
198 else if ( getenv("ZYPP_FULLLOG") )
199 ::pool_setdebuglevel( _pool, 2 );
201 ::pool_setdebugmask(_pool, SOLV_DEBUG_JOB|SOLV_DEBUG_STATS );
204 ::pool_setdebugcallback( _pool, logSat, NULL );
206 // set namespace callback
207 _pool->nscallback = &nsCallback;
208 _pool->nscallbackdata = (void*)this;
211 ///////////////////////////////////////////////////////////////////
213 // METHOD NAME : PoolImpl::~PoolImpl
214 // METHOD TYPE : Dtor
216 PoolImpl::~PoolImpl()
218 ::pool_free( _pool );
221 ///////////////////////////////////////////////////////////////////
223 void PoolImpl::setDirty( const char * a1, const char * a2, const char * a3 )
227 if ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
228 else if ( a2 ) MIL << a1 << " " << a2 << endl;
229 else MIL << a1 << endl;
231 _serial.setDirty(); // pool content change
232 _availableLocalesPtr.reset(); // available locales may change
233 _multiversionListPtr.reset(); // re-evaluate ZConfig::multiversionSpec.
235 // invaldate dependency/namespace related indices:
239 void PoolImpl::depSetDirty( const char * a1, const char * a2, const char * a3 )
243 if ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
244 else if ( a2 ) MIL << a1 << " " << a2 << endl;
245 else MIL << a1 << endl;
247 ::pool_freewhatprovides( _pool );
250 void PoolImpl::prepare() const
252 if ( _watcher.remember( _serial ) )
254 // After repo/solvable add/remove:
255 // set pool architecture
256 ::pool_setarch( _pool, ZConfig::instance().systemArchitecture().asString().c_str() );
258 if ( ! _pool->whatprovides )
260 MIL << "pool_createwhatprovides..." << endl;
262 ::pool_addfileprovides( _pool );
263 ::pool_createwhatprovides( _pool );
265 if ( ! _pool->languages )
268 const_cast<PoolImpl*>(this)->setTextLocale( ZConfig::instance().textLocale() );
272 void PoolImpl::prepareForSolving() const
274 // additional /etc/sysconfig/storage check:
275 static WatchFile sysconfigFile( sysconfigStoragePath(), WatchFile::NO_INIT );
276 if ( sysconfigFile.hasChanged() )
278 _requiredFilesystemsPtr.reset(); // recreated on demand
279 const_cast<PoolImpl*>(this)->depSetDirty( "/etc/sysconfig/storage change" );
281 // finally prepare as usual:
285 ///////////////////////////////////////////////////////////////////
287 ::_Repo * PoolImpl::_createRepo( const std::string & name_r )
289 setDirty(__FUNCTION__, name_r.c_str() );
290 ::_Repo * ret = ::repo_create( _pool, name_r.c_str() );
291 if ( ret && name_r == systemRepoAlias() )
292 ::pool_set_installed( _pool, ret );
296 void PoolImpl::_deleteRepo( ::_Repo * repo_r )
298 setDirty(__FUNCTION__, repo_r->name );
299 if ( isSystemRepo( repo_r ) )
300 _autoinstalled.clear();
301 eraseRepoInfo( repo_r );
302 ::repo_free( repo_r, /*reuseids*/false );
305 int PoolImpl::_addSolv( ::_Repo * repo_r, FILE * file_r )
307 setDirty(__FUNCTION__, repo_r->name );
308 int ret = ::repo_add_solv( repo_r, file_r, 0 );
310 _postRepoAdd( repo_r );
314 int PoolImpl::_addHelix( ::_Repo * repo_r, FILE * file_r )
316 setDirty(__FUNCTION__, repo_r->name );
317 int ret = ::repo_add_helix( repo_r, file_r, 0 );
319 _postRepoAdd( repo_r );
323 void PoolImpl::_postRepoAdd( ::_Repo * repo_r )
325 if ( ! isSystemRepo( repo_r ) )
327 // Filter out unwanted archs
328 std::set<detail::IdType> sysids;
330 Arch::CompatSet sysarchs( Arch::compatSet( ZConfig::instance().systemArchitecture() ) );
331 for_( it, sysarchs.begin(), sysarchs.end() )
332 sysids.insert( it->id() );
334 // unfortunately libsolv treats src/nosrc as architecture:
335 sysids.insert( ARCH_SRC );
336 sysids.insert( ARCH_NOSRC );
339 detail::IdType blockBegin = 0;
340 unsigned blockSize = 0;
341 for ( detail::IdType i = repo_r->start; i < repo_r->end; ++i )
343 ::_Solvable * s( _pool->solvables + i );
344 if ( s->repo == repo_r && sysids.find( s->arch ) == sysids.end() )
346 // Remember an unwanted arch entry:
351 else if ( blockSize )
353 // Free remembered entries
354 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
355 blockBegin = blockSize = 0;
360 // Free remembered entries
361 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
362 blockBegin = blockSize = 0;
367 detail::SolvableIdType PoolImpl::_addSolvables( ::_Repo * repo_r, unsigned count_r )
369 setDirty(__FUNCTION__, repo_r->name );
370 return ::repo_add_solvable_block( repo_r, count_r );
373 void PoolImpl::setRepoInfo( RepoIdType id_r, const RepoInfo & info_r )
375 ::_Repo * repo( getRepo( id_r ) );
380 // libsolv priority is based on '<', while yum's repoinfo
381 // uses 1(highest)->99(lowest). Thus we use -info_r.priority.
382 if ( repo->priority != int(-info_r.priority()) )
384 repo->priority = -info_r.priority();
388 // subpriority is used to e.g. prefer http over dvd iff
389 // both have same priority.
390 int mediaPriority( media::MediaPriority( info_r.url() ) );
391 if ( repo->subpriority != mediaPriority )
393 repo->subpriority = mediaPriority;
398 setDirty(__FUNCTION__, info_r.alias().c_str() );
400 _repoinfos[id_r] = info_r;
403 ///////////////////////////////////////////////////////////////////
405 // need on demand and id based Locale
406 void _locale_hack( const LocaleSet & locales_r,
407 std::tr1::unordered_set<IdString> & locale2Solver )
409 std::tr1::unordered_set<IdString>( 2*locales_r.size() ).swap( locale2Solver );
410 for_( it, locales_r.begin(),locales_r.end() )
412 for ( Locale l( *it ); l != Locale::noCode; l = l.fallback() )
413 locale2Solver.insert( IdString( l.code() ) );
415 MIL << "New Solver Locales: " << locale2Solver << endl;
418 void PoolImpl::setTextLocale( const Locale & locale_r )
420 std::vector<std::string> fallbacklist;
421 for ( Locale l( locale_r ); l != Locale::noCode; l = l.fallback() )
423 fallbacklist.push_back( l.code() );
425 dumpRangeLine( MIL << "pool_set_languages: ", fallbacklist.begin(), fallbacklist.end() ) << endl;
427 std::vector<const char *> fallbacklist_cstr;
428 for_( it, fallbacklist.begin(), fallbacklist.end() )
430 fallbacklist_cstr.push_back( it->c_str() );
432 ::pool_set_languages( _pool, &fallbacklist_cstr.front(), fallbacklist_cstr.size() );
435 void PoolImpl::setRequestedLocales( const LocaleSet & locales_r )
437 depSetDirty( "setRequestedLocales" );
438 _requestedLocales = locales_r;
439 MIL << "New RequestedLocales: " << locales_r << endl;
440 _locale_hack( _requestedLocales, _locale2Solver );
443 bool PoolImpl::addRequestedLocale( const Locale & locale_r )
445 if ( _requestedLocales.insert( locale_r ).second )
447 depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
448 _locale_hack( _requestedLocales, _locale2Solver );
454 bool PoolImpl::eraseRequestedLocale( const Locale & locale_r )
456 if ( _requestedLocales.erase( locale_r ) )
458 depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
459 _locale_hack( _requestedLocales, _locale2Solver );
465 static void _getLocaleDeps( Capability cap_r, std::tr1::unordered_set<sat::detail::IdType> & store_r )
467 // Collect locales from any 'namespace:language(lang)' dependency
468 CapDetail detail( cap_r );
469 if ( detail.kind() == CapDetail::EXPRESSION )
471 switch ( detail.capRel() )
473 case CapDetail::CAP_AND:
474 case CapDetail::CAP_OR:
476 _getLocaleDeps( detail.lhs(), store_r );
477 _getLocaleDeps( detail.rhs(), store_r );
480 case CapDetail::CAP_NAMESPACE:
481 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
483 store_r.insert( detail.rhs().id() );
487 case CapDetail::REL_NONE:
488 case CapDetail::CAP_WITH:
489 case CapDetail::CAP_ARCH:
495 const LocaleSet & PoolImpl::getAvailableLocales() const
497 if ( !_availableLocalesPtr )
499 // Collect any 'namespace:language(ja)' dependencies
500 std::tr1::unordered_set<sat::detail::IdType> tmp;
501 Pool pool( Pool::instance() );
502 for_( it, pool.solvablesBegin(), pool.solvablesEnd() )
504 Capabilities cap( it->supplements() );
505 for_( cit, cap.begin(), cap.end() )
507 _getLocaleDeps( *cit, tmp );
510 #warning immediately build LocaleSet as soon as Loale is an Id based type
511 _availableLocalesPtr.reset( new LocaleSet(tmp.size()) );
512 for_( it, tmp.begin(), tmp.end() )
514 _availableLocalesPtr->insert( Locale( IdString(*it) ) );
517 return *_availableLocalesPtr;
520 void PoolImpl::multiversionListInit() const
522 _multiversionListPtr.reset( new MultiversionList );
523 MultiversionList & multiversionList( *_multiversionListPtr );
525 const std::set<std::string> & multiversionSpec( ZConfig::instance().multiversionSpec() );
526 for_( it, multiversionSpec.begin(), multiversionSpec.end() )
528 static const std::string prefix( "provides:" );
529 if ( str::hasPrefix( *it, prefix ) )
531 WhatProvides provides( Capability( it->c_str() + prefix.size() ) );
532 if ( provides.empty() )
534 MIL << "Multiversion install not provided (" << *it << ")" << endl;
538 for_( pit, provides.begin(), provides.end() )
540 if ( multiversionList.insert( pit->ident() ).second )
541 MIL << "Multiversion install " << pit->ident() << " (" << *it << ")" << endl;
547 MIL << "Multiversion install " << *it << endl;
548 multiversionList.insert( IdString( *it ) );
553 const std::set<std::string> & PoolImpl::requiredFilesystems() const
555 if ( ! _requiredFilesystemsPtr )
557 _requiredFilesystemsPtr.reset( new std::set<std::string> );
558 std::set<std::string> & requiredFilesystems( *_requiredFilesystemsPtr );
559 str::split( base::sysconfig::read( sysconfigStoragePath() )["USED_FS_LIST"],
560 std::inserter( requiredFilesystems, requiredFilesystems.end() ) );
562 return *_requiredFilesystemsPtr;
565 /////////////////////////////////////////////////////////////////
566 } // namespace detail
567 ///////////////////////////////////////////////////////////////////
568 /////////////////////////////////////////////////////////////////
570 ///////////////////////////////////////////////////////////////////
571 /////////////////////////////////////////////////////////////////
573 ///////////////////////////////////////////////////////////////////