PoolImpl.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
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 // Workaround satsolver project not providing a common include
00037 // directory. (the -devel package does, but the git repo doesn't).
00038 // #include <satsolver/repo_helix.h>
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       // MPL checks for satlib constants we redefine to avoid
00059       // includes and defines.
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         // lhs:    the namespace identifier, e.g. NAMESPACE:MODALIAS
00099         // rhs:    the value, e.g. pci:v0000104Cd0000840[01]sv*sd*bc*sc*i*
00100         // return: 0 if not supportded
00101         //         1 if supported by the system
00102         //        -1  AFAIK it's also possible to return a list of solvables that support it, but don't know how.
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             // modalias strings in capability may be hexencoded because rpm does not allow
00123             // ',', ' ' or other special chars.
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       //        METHOD NAME : PoolMember::myPool
00161       //        METHOD TYPE : PoolImpl
00162       //
00163       PoolImpl & PoolMember::myPool()
00164       {
00165         static PoolImpl _global;
00166         return _global;
00167       }
00168 
00170       //
00171       //        METHOD NAME : PoolImpl::PoolImpl
00172       //        METHOD TYPE : Ctor
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         // initialialize logging
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         // set namespace callback
00193         _pool->nscallback = &nsCallback;
00194         _pool->nscallbackdata = (void*)this;
00195       }
00196 
00198       //
00199       //        METHOD NAME : PoolImpl::~PoolImpl
00200       //        METHOD TYPE : Dtor
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();           // pool content change
00218         _availableLocalesPtr.reset(); // available locales may change
00219         _multiversionListPtr.reset(); // re-evaluate ZConfig::multiversionSpec.
00220 
00221         // invaldate dependency/namespace related indices:
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           // After repo/solvable add/remove:
00241           // set pool architecture
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           // initial seting
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, /*reuseids*/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 ); // unfortunately void
00288         _postRepoAdd( repo_r );
00289         return 0;
00290       }
00291 
00292       void PoolImpl::_postRepoAdd( ::_Repo * repo_r )
00293       {
00294         if ( ! isSystemRepo( repo_r ) )
00295         {
00296             // Filter out unwanted archs
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               // unfortunately satsolver treats src/nosrc as architecture:
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                 // Remember an unwanted arch entry:
00316                 if ( ! blockBegin )
00317                   blockBegin = i;
00318                 ++blockSize;
00319               }
00320               else if ( blockSize )
00321               {
00322                 // Free remembered entries
00323                   ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
00324                   blockBegin = blockSize = 0;
00325               }
00326           }
00327           if ( blockSize )
00328           {
00329               // Free remembered entries
00330               ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/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           // satsolver priority is based on '<', while yum's repoinfo
00350           // uses 1(highest)->99(lowest). Thus we use -info_r.priority.
00351           if ( repo->priority != int(-info_r.priority()) )
00352           {
00353             repo->priority = -info_r.priority();
00354             dirty = true;
00355           }
00356 
00357           // subpriority is used to e.g. prefer http over dvd iff
00358           // both have same priority.
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       // need on demand and id based Locale
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         // Collect locales from any 'namespace:language(lang)' dependency
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               // expand
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; // unwanted
00460           }
00461         }
00462       }
00463 
00464       const LocaleSet & PoolImpl::getAvailableLocales() const
00465       {
00466         if ( !_availableLocalesPtr )
00467         {
00468           // Collect any 'namespace:language(ja)' dependencies
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     } // namespace detail
00526   } // namespace sat
00529 } // namespace zypp

doxygen