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 satsolver project not providing a common include
39 // directory. (the -devel package does, but the git repo doesn't).
40 // #include <satsolver/repo_helix.h>
41 void repo_add_helix( ::Repo *repo, FILE *fp, int flags );
46 #undef ZYPP_BASE_LOGGER_LOGGROUP
47 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::satpool"
49 // ///////////////////////////////////////////////////////////////////
51 { /////////////////////////////////////////////////////////////////
52 ///////////////////////////////////////////////////////////////////
54 { /////////////////////////////////////////////////////////////////
56 ///////////////////////////////////////////////////////////////////
58 { /////////////////////////////////////////////////////////////////
60 // MPL checks for satlib constants we redefine to avoid
61 // includes and defines.
62 BOOST_MPL_ASSERT_RELATION( noId, ==, STRID_NULL );
63 BOOST_MPL_ASSERT_RELATION( emptyId, ==, STRID_EMPTY );
65 BOOST_MPL_ASSERT_RELATION( noSolvableId, ==, ID_NULL );
66 BOOST_MPL_ASSERT_RELATION( systemSolvableId, ==, SYSTEMSOLVABLE );
68 BOOST_MPL_ASSERT_RELATION( solvablePrereqMarker, ==, SOLVABLE_PREREQMARKER );
69 BOOST_MPL_ASSERT_RELATION( solvableFileMarker, ==, SOLVABLE_FILEMARKER );
71 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_AND, ==, REL_AND );
72 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_OR, ==, REL_OR );
73 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_WITH, ==, REL_WITH );
74 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_NAMESPACE, ==, REL_NAMESPACE );
75 BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_ARCH, ==, REL_ARCH );
77 /////////////////////////////////////////////////////////////////
79 const std::string & PoolImpl::systemRepoAlias()
81 static const std::string _val( "@System" );
85 const Pathname & sysconfigStoragePath()
87 static const Pathname _val( "/etc/sysconfig/storage" );
92 /////////////////////////////////////////////////////////////////
94 static void logSat( struct _Pool *, void *data, int type, const char *logString )
96 if ( type & (SAT_FATAL|SAT_ERROR) ) {
97 _ERR("satsolver") << logString;
98 } else if ( type & SAT_DEBUG_STATS ) {
99 _DBG("satsolver") << logString;
101 _MIL("satsolver") << logString;
105 detail::IdType PoolImpl::nsCallback( struct _Pool *, void * data, detail::IdType lhs, detail::IdType rhs )
107 // lhs: the namespace identifier, e.g. NAMESPACE:MODALIAS
108 // rhs: the value, e.g. pci:v0000104Cd0000840[01]sv*sd*bc*sc*i*
109 // return: 0 if not supportded
110 // 1 if supported by the system
111 // -1 AFAIK it's also possible to return a list of solvables that support it, but don't know how.
113 static const detail::IdType RET_unsupported = 0;
114 static const detail::IdType RET_systemProperty = 1;
117 case NAMESPACE_LANGUAGE:
119 static IdString en( "en" );
120 const std::tr1::unordered_set<IdString> & locale2Solver( reinterpret_cast<PoolImpl*>(data)->_locale2Solver );
121 if ( locale2Solver.empty() )
123 return rhs == en.id() ? RET_systemProperty : RET_unsupported;
125 return locale2Solver.find( IdString(rhs) ) != locale2Solver.end() ? RET_systemProperty : RET_unsupported;
129 case NAMESPACE_MODALIAS:
131 // modalias strings in capability may be hexencoded because rpm does not allow
132 // ',', ' ' or other special chars.
133 return target::Modalias::instance().query( str::hexdecode( IdString(rhs).c_str() ) )
139 case NAMESPACE_FILESYSTEM:
141 const std::set<std::string> & requiredFilesystems( reinterpret_cast<PoolImpl*>(data)->requiredFilesystems() );
142 return requiredFilesystems.find( IdString(rhs).asString() ) != requiredFilesystems.end() ? RET_systemProperty : RET_unsupported;
146 case NAMESPACE_PRODUCTBUDDY:
148 PoolItem pi( (Solvable(rhs)) );
149 return( pi ? pi.buddy().id() : noId );
155 WAR << "Unhandled " << Capability( lhs ) << " vs. " << Capability( rhs ) << endl;
156 return RET_unsupported;
159 ///////////////////////////////////////////////////////////////////
161 // METHOD NAME : PoolMember::myPool
162 // METHOD TYPE : PoolImpl
164 PoolImpl & PoolMember::myPool()
166 static PoolImpl _global;
170 ///////////////////////////////////////////////////////////////////
172 // METHOD NAME : PoolImpl::PoolImpl
173 // METHOD TYPE : Ctor
176 : _pool( ::pool_create() )
178 MIL << "Creating sat-pool." << endl;
181 ZYPP_THROW( Exception( _("Can not create sat-pool.") ) );
183 // initialialize logging
184 if ( getenv("ZYPP_LIBSAT_FULLLOG") )
185 ::pool_setdebuglevel( _pool, 4 );
186 else if ( getenv("ZYPP_FULLLOG") )
187 ::pool_setdebuglevel( _pool, 2 );
189 ::pool_setdebugmask(_pool, SAT_DEBUG_JOB|SAT_DEBUG_STATS);
191 ::pool_setdebugcallback( _pool, logSat, NULL );
193 // set namespace callback
194 _pool->nscallback = &nsCallback;
195 _pool->nscallbackdata = (void*)this;
198 ///////////////////////////////////////////////////////////////////
200 // METHOD NAME : PoolImpl::~PoolImpl
201 // METHOD TYPE : Dtor
203 PoolImpl::~PoolImpl()
205 ::pool_free( _pool );
208 ///////////////////////////////////////////////////////////////////
210 void PoolImpl::setDirty( const char * a1, const char * a2, const char * a3 )
214 if ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
215 else if ( a2 ) MIL << a1 << " " << a2 << endl;
216 else MIL << a1 << endl;
218 _serial.setDirty(); // pool content change
219 _availableLocalesPtr.reset(); // available locales may change
220 _multiversionListPtr.reset(); // re-evaluate ZConfig::multiversionSpec.
222 // invaldate dependency/namespace related indices:
226 void PoolImpl::depSetDirty( const char * a1, const char * a2, const char * a3 )
230 if ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
231 else if ( a2 ) MIL << a1 << " " << a2 << endl;
232 else MIL << a1 << endl;
234 ::pool_freewhatprovides( _pool );
237 void PoolImpl::prepare() const
239 if ( _watcher.remember( _serial ) )
241 // After repo/solvable add/remove:
242 // set pool architecture
243 ::pool_setarch( _pool, ZConfig::instance().systemArchitecture().asString().c_str() );
245 if ( ! _pool->whatprovides )
247 MIL << "pool_createwhatprovides..." << endl;
249 ::pool_addfileprovides( _pool );
250 ::pool_createwhatprovides( _pool );
252 if ( ! _pool->languages )
255 const_cast<PoolImpl*>(this)->setTextLocale( ZConfig::instance().textLocale() );
259 void PoolImpl::prepareForSolving() const
261 // additional /etc/sysconfig/storage check:
262 static WatchFile sysconfigFile( sysconfigStoragePath(), WatchFile::NO_INIT );
263 if ( sysconfigFile.hasChanged() )
265 _requiredFilesystemsPtr.reset(); // recreated on demand
266 const_cast<PoolImpl*>(this)->depSetDirty( "/etc/sysconfig/storage change" );
268 // finally prepare as usual:
272 ///////////////////////////////////////////////////////////////////
274 ::_Repo * PoolImpl::_createRepo( const std::string & name_r )
276 setDirty(__FUNCTION__, name_r.c_str() );
277 ::_Repo * ret = ::repo_create( _pool, name_r.c_str() );
278 if ( ret && name_r == systemRepoAlias() )
279 ::pool_set_installed( _pool, ret );
283 void PoolImpl::_deleteRepo( ::_Repo * repo_r )
285 setDirty(__FUNCTION__, repo_r->name );
286 ::repo_free( repo_r, /*reuseids*/false );
287 eraseRepoInfo( repo_r );
288 if ( isSystemRepo( repo_r ) )
291 _onSystemByUserListPtr.reset(); // re-evaluate
295 int PoolImpl::_addSolv( ::_Repo * repo_r, FILE * file_r )
297 setDirty(__FUNCTION__, repo_r->name );
298 int ret = ::repo_add_solv( repo_r , file_r );
300 _postRepoAdd( repo_r );
304 int PoolImpl::_addHelix( ::_Repo * repo_r, FILE * file_r )
306 setDirty(__FUNCTION__, repo_r->name );
307 ::repo_add_helix( repo_r , file_r, 0 ); // unfortunately void
308 _postRepoAdd( repo_r );
312 void PoolImpl::_postRepoAdd( ::_Repo * repo_r )
314 if ( ! isSystemRepo( repo_r ) )
316 // Filter out unwanted archs
317 std::set<detail::IdType> sysids;
319 Arch::CompatSet sysarchs( Arch::compatSet( ZConfig::instance().systemArchitecture() ) );
320 for_( it, sysarchs.begin(), sysarchs.end() )
321 sysids.insert( it->id() );
323 // unfortunately satsolver treats src/nosrc as architecture:
324 sysids.insert( ARCH_SRC );
325 sysids.insert( ARCH_NOSRC );
328 detail::IdType blockBegin = 0;
329 unsigned blockSize = 0;
330 for ( detail::IdType i = repo_r->start; i < repo_r->end; ++i )
332 ::_Solvable * s( _pool->solvables + i );
333 if ( s->repo == repo_r && sysids.find( s->arch ) == sysids.end() )
335 // Remember an unwanted arch entry:
340 else if ( blockSize )
342 // Free remembered entries
343 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
344 blockBegin = blockSize = 0;
349 // Free remembered entries
350 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
351 blockBegin = blockSize = 0;
357 _onSystemByUserListPtr.reset(); // re-evaluate
361 detail::SolvableIdType PoolImpl::_addSolvables( ::_Repo * repo_r, unsigned count_r )
363 setDirty(__FUNCTION__, repo_r->name );
364 return ::repo_add_solvable_block( repo_r, count_r );
367 void PoolImpl::setRepoInfo( RepoIdType id_r, const RepoInfo & info_r )
369 ::_Repo * repo( getRepo( id_r ) );
374 // satsolver priority is based on '<', while yum's repoinfo
375 // uses 1(highest)->99(lowest). Thus we use -info_r.priority.
376 if ( repo->priority != int(-info_r.priority()) )
378 repo->priority = -info_r.priority();
382 // subpriority is used to e.g. prefer http over dvd iff
383 // both have same priority.
384 int mediaPriority( media::MediaPriority( info_r.url() ) );
385 if ( repo->subpriority != mediaPriority )
387 repo->subpriority = mediaPriority;
392 setDirty(__FUNCTION__, info_r.alias().c_str() );
394 _repoinfos[id_r] = info_r;
397 ///////////////////////////////////////////////////////////////////
399 // need on demand and id based Locale
400 void _locale_hack( const LocaleSet & locales_r,
401 std::tr1::unordered_set<IdString> & locale2Solver )
403 std::tr1::unordered_set<IdString>( 2*locales_r.size() ).swap( locale2Solver );
404 for_( it, locales_r.begin(),locales_r.end() )
406 for ( Locale l( *it ); l != Locale::noCode; l = l.fallback() )
407 locale2Solver.insert( IdString( l.code() ) );
409 MIL << "New Solver Locales: " << locale2Solver << endl;
412 void PoolImpl::setTextLocale( const Locale & locale_r )
414 std::vector<std::string> fallbacklist;
415 for ( Locale l( locale_r ); l != Locale::noCode; l = l.fallback() )
417 fallbacklist.push_back( l.code() );
419 dumpRangeLine( MIL << "pool_set_languages: ", fallbacklist.begin(), fallbacklist.end() ) << endl;
421 std::vector<const char *> fallbacklist_cstr;
422 for_( it, fallbacklist.begin(), fallbacklist.end() )
424 fallbacklist_cstr.push_back( it->c_str() );
426 ::pool_set_languages( _pool, &fallbacklist_cstr.front(), fallbacklist_cstr.size() );
429 void PoolImpl::setRequestedLocales( const LocaleSet & locales_r )
431 depSetDirty( "setRequestedLocales" );
432 _requestedLocales = locales_r;
433 MIL << "New RequestedLocales: " << locales_r << endl;
434 _locale_hack( _requestedLocales, _locale2Solver );
437 bool PoolImpl::addRequestedLocale( const Locale & locale_r )
439 if ( _requestedLocales.insert( locale_r ).second )
441 depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
442 _locale_hack( _requestedLocales, _locale2Solver );
448 bool PoolImpl::eraseRequestedLocale( const Locale & locale_r )
450 if ( _requestedLocales.erase( locale_r ) )
452 depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
453 _locale_hack( _requestedLocales, _locale2Solver );
459 static void _getLocaleDeps( Capability cap_r, std::tr1::unordered_set<sat::detail::IdType> & store_r )
461 // Collect locales from any 'namespace:language(lang)' dependency
462 CapDetail detail( cap_r );
463 if ( detail.kind() == CapDetail::EXPRESSION )
465 switch ( detail.capRel() )
467 case CapDetail::CAP_AND:
468 case CapDetail::CAP_OR:
470 _getLocaleDeps( detail.lhs(), store_r );
471 _getLocaleDeps( detail.rhs(), store_r );
474 case CapDetail::CAP_NAMESPACE:
475 if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
477 store_r.insert( detail.rhs().id() );
481 case CapDetail::REL_NONE:
482 case CapDetail::CAP_WITH:
483 case CapDetail::CAP_ARCH:
489 const LocaleSet & PoolImpl::getAvailableLocales() const
491 if ( !_availableLocalesPtr )
493 // Collect any 'namespace:language(ja)' dependencies
494 std::tr1::unordered_set<sat::detail::IdType> tmp;
495 Pool pool( Pool::instance() );
496 for_( it, pool.solvablesBegin(), pool.solvablesEnd() )
498 Capabilities cap( it->supplements() );
499 for_( cit, cap.begin(), cap.end() )
501 _getLocaleDeps( *cit, tmp );
504 #warning immediately build LocaleSet as soon as Loale is an Id based type
505 _availableLocalesPtr.reset( new LocaleSet(tmp.size()) );
506 for_( it, tmp.begin(), tmp.end() )
508 _availableLocalesPtr->insert( Locale( IdString(*it) ) );
511 return *_availableLocalesPtr;
514 void PoolImpl::multiversionListInit() const
516 _multiversionListPtr.reset( new MultiversionList );
517 MultiversionList & multiversionList( *_multiversionListPtr );
519 const std::set<std::string> & multiversionSpec( ZConfig::instance().multiversionSpec() );
520 for_( it, multiversionSpec.begin(), multiversionSpec.end() )
522 static const std::string prefix( "provides:" );
523 if ( str::hasPrefix( *it, prefix ) )
525 WhatProvides provides( Capability( it->c_str() + prefix.size() ) );
526 if ( provides.empty() )
528 MIL << "Multiversion install not provided (" << *it << ")" << endl;
532 for_( pit, provides.begin(), provides.end() )
534 if ( multiversionList.insert( pit->ident() ).second )
535 MIL << "Multiversion install " << pit->ident() << " (" << *it << ")" << endl;
541 MIL << "Multiversion install " << *it << endl;
542 multiversionList.insert( IdString( *it ) );
547 void PoolImpl::onSystemByUserListInit() const
549 _onSystemByUserListPtr.reset( new OnSystemByUserList );
550 OnSystemByUserList & onSystemByUserList( *_onSystemByUserListPtr );
552 Pathname root( ZConfig::instance().systemRoot() );
555 MIL << "Target not initialized." << endl;
558 PathInfo pi( root / ZConfig::instance().historyLogFile() );
559 MIL << "onSystemByUserList from history: " << pi << endl;
563 // go and parse it: 'who' must constain an '@', then it was installed by user request.
564 // 2009-09-29 07:25:19|install|lirc-remotes|0.8.5-3.2|x86_64|root@opensuse|InstallationImage|a204211eb0...
565 std::ifstream infile( pi.path().c_str() );
566 for( iostr::EachLine in( infile ); in; in.next() )
568 const char * ch( (*in).c_str() );
570 if ( *ch < '1' || '9' < *ch )
572 const char * sep1 = ::strchr( ch, '|' ); // | after date
576 // if logs an install or delete
577 bool installs = true;
578 if ( ::strncmp( sep1, "install|", 8 ) )
580 if ( ::strncmp( sep1, "remove |", 8 ) )
581 continue; // no install and no remove
583 installs = false; // remove
585 sep1 += 8; // | after what
586 // get the package name
587 const char * sep2 = ::strchr( sep1, '|' ); // | after name
588 if ( !sep2 || sep1 == sep2 )
590 (*in)[sep2-ch] = '\0';
591 IdString pkg( sep1 );
592 // we're done, if a delete
595 onSystemByUserList.erase( pkg );
598 // now guess whether user installed or not (3rd next field contains 'user@host')
599 if ( (sep1 = ::strchr( sep2+1, '|' )) // | after version
600 && (sep1 = ::strchr( sep1+1, '|' )) // | after arch
601 && (sep2 = ::strchr( sep1+1, '|' )) ) // | after who
603 (*in)[sep2-ch] = '\0';
604 if ( ::strchr( sep1+1, '@' ) )
607 onSystemByUserList.insert( pkg );
612 MIL << "onSystemByUserList found: " << onSystemByUserList.size() << endl;
615 const std::set<std::string> & PoolImpl::requiredFilesystems() const
617 if ( ! _requiredFilesystemsPtr )
619 _requiredFilesystemsPtr.reset( new std::set<std::string> );
620 std::set<std::string> & requiredFilesystems( *_requiredFilesystemsPtr );
621 str::split( base::sysconfig::read( sysconfigStoragePath() )["USED_FS_LIST"],
622 std::inserter( requiredFilesystems, requiredFilesystems.end() ) );
624 return *_requiredFilesystemsPtr;
627 /////////////////////////////////////////////////////////////////
628 } // namespace detail
629 ///////////////////////////////////////////////////////////////////
630 /////////////////////////////////////////////////////////////////
632 ///////////////////////////////////////////////////////////////////
633 /////////////////////////////////////////////////////////////////
635 ///////////////////////////////////////////////////////////////////