*
*/
#include <iostream>
+#include <fstream>
#include <boost/mpl/int.hpp>
#include "zypp/base/Easy.h"
#include "zypp/base/Measure.h"
#include "zypp/base/WatchFile.h"
#include "zypp/base/Sysconfig.h"
+#include "zypp/base/IOStream.h"
#include "zypp/ZConfig.h"
#include "zypp/sat/detail/PoolImpl.h"
+#include "zypp/sat/SolvableSet.h"
#include "zypp/sat/Pool.h"
#include "zypp/Capability.h"
#include "zypp/Locale.h"
extern "C"
{
-// Workaround satsolver project not providing a common include
+// Workaround libsolv project not providing a common include
// directory. (the -devel package does, but the git repo doesn't).
-// #include <satsolver/repo_helix.h>
-void repo_add_helix( ::Repo *repo, FILE *fp, int flags );
+// #include <solv/repo_helix.h>
+int repo_add_helix( ::Repo *repo, FILE *fp, int flags );
}
using std::endl;
// ///////////////////////////////////////////////////////////////////
namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
+ /////////////////////////////////////////////////////////////////
+ namespace env
+ {
+ /** */
+ inline int LIBSOLV_DEBUGMASK()
+ {
+ const char * envp = getenv("LIBSOLV_DEBUGMASK");
+ return envp ? str::strtonum<int>( envp ) : 0;
+ }
+ } // namespace env
///////////////////////////////////////////////////////////////////
namespace sat
{ /////////////////////////////////////////////////////////////////
BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_NAMESPACE, ==, REL_NAMESPACE );
BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_ARCH, ==, REL_ARCH );
- /////////////////////////////////////////////////////////////////
+ BOOST_MPL_ASSERT_RELATION( namespaceModalias, ==, NAMESPACE_MODALIAS );
+ BOOST_MPL_ASSERT_RELATION( namespaceLanguage, ==, NAMESPACE_LANGUAGE );
+ BOOST_MPL_ASSERT_RELATION( namespaceFilesystem, ==, NAMESPACE_FILESYSTEM );
+
+ /////////////////////////////////////////////////////////////////
const std::string & PoolImpl::systemRepoAlias()
{
return _val;
}
+ const Pathname & sysconfigStoragePath()
+ {
+ static const Pathname _val( "/etc/sysconfig/storage" );
+ return _val;
+ }
+
+
/////////////////////////////////////////////////////////////////
static void logSat( struct _Pool *, void *data, int type, const char *logString )
{
- if ( type & (SAT_FATAL|SAT_ERROR) ) {
- _ERR("satsolver") << logString;
- } else if ( type & SAT_DEBUG_STATS ) {
- _DBG("satsolver") << logString;
+ if ( type & (SOLV_FATAL|SOLV_ERROR) ) {
+ _ERR("libsolv") << logString;
+ } else if ( type & SOLV_DEBUG_STATS ) {
+ _DBG("libsolv") << logString;
} else {
- _MIL("satsolver") << logString;
+ _MIL("libsolv") << logString;
}
}
{
case NAMESPACE_LANGUAGE:
{
- static IdString en( "en" );
- const std::tr1::unordered_set<IdString> & locale2Solver( reinterpret_cast<PoolImpl*>(data)->_locale2Solver );
- if ( locale2Solver.empty() )
- {
- return rhs == en.id() ? RET_systemProperty : RET_unsupported;
- }
- return locale2Solver.find( IdString(rhs) ) != locale2Solver.end() ? RET_systemProperty : RET_unsupported;
+ const TrackedLocaleIds & localeIds( reinterpret_cast<PoolImpl*>(data)->trackedLocaleIds() );
+ return localeIds.contains( IdString(rhs) ) ? RET_systemProperty : RET_unsupported;
}
break;
case NAMESPACE_FILESYSTEM:
{
- static const Pathname sysconfigStoragePath( "/etc/sysconfig/storage" );
- static WatchFile sysconfigFile( sysconfigStoragePath, WatchFile::NO_INIT );
- static std::set<std::string> requiredFilesystems;
- if ( sysconfigFile.hasChanged() )
- {
- requiredFilesystems.clear();
- str::split( base::sysconfig::read( sysconfigStoragePath )["USED_FS_LIST"],
- std::inserter( requiredFilesystems, requiredFilesystems.end() ) );
- }
+ const std::set<std::string> & requiredFilesystems( reinterpret_cast<PoolImpl*>(data)->requiredFilesystems() );
return requiredFilesystems.find( IdString(rhs).asString() ) != requiredFilesystems.end() ? RET_systemProperty : RET_unsupported;
}
break;
- case NAMESPACE_PRODUCTBUDDY:
- {
- PoolItem pi( (Solvable(rhs)) );
- return( pi ? pi.buddy().id() : noId );
- }
-
- break;
}
WAR << "Unhandled " << Capability( lhs ) << " vs. " << Capability( rhs ) << endl;
{
ZYPP_THROW( Exception( _("Can not create sat-pool.") ) );
}
+ // by now we support only a RPM backend
+ ::pool_setdisttype(_pool, DISTTYPE_RPM );
+
// initialialize logging
- bool verbose = ( getenv("ZYPP_FULLLOG") || getenv("ZYPP_LIBSAT_FULLLOG") );
- if (verbose)
- ::pool_setdebuglevel( _pool, 2 );
+ if ( env::LIBSOLV_DEBUGMASK() )
+ {
+ ::pool_setdebugmask(_pool, env::LIBSOLV_DEBUGMASK() );
+ }
else
- ::pool_setdebugmask(_pool, SAT_DEBUG_JOB|SAT_DEBUG_STATS);
+ {
+ if ( getenv("ZYPP_LIBSOLV_FULLLOG") || getenv("ZYPP_LIBSAT_FULLLOG") )
+ ::pool_setdebuglevel( _pool, 3 );
+ else if ( getenv("ZYPP_FULLLOG") )
+ ::pool_setdebuglevel( _pool, 2 );
+ else
+ ::pool_setdebugmask(_pool, SOLV_DEBUG_JOB|SOLV_DEBUG_STATS );
+ }
::pool_setdebugcallback( _pool, logSat, NULL );
}
_serial.setDirty(); // pool content change
_availableLocalesPtr.reset(); // available locales may change
+ _multiversionListPtr.reset(); // re-evaluate ZConfig::multiversionSpec.
- // invaldate dependency/namespace related indices:
- depSetDirty();
+ depSetDirty(); // invaldate dependency/namespace related indices
+ }
+
+ void PoolImpl::localeSetDirty( const char * a1, const char * a2, const char * a3 )
+ {
+ if ( a1 )
+ {
+ if ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
+ else if ( a2 ) MIL << a1 << " " << a2 << endl;
+ else MIL << a1 << endl;
+ }
+ _trackedLocaleIdsPtr.reset(); // requested locales changed
+ depSetDirty(); // invaldate dependency/namespace related indices
}
void PoolImpl::depSetDirty( const char * a1, const char * a2, const char * a3 )
::pool_freewhatprovides( _pool );
}
+
void PoolImpl::prepare() const
{
- if ( _watcher.remember( _serial ) )
+ if ( _watcher.remember( _serial ) )
{
// After repo/solvable add/remove:
// set pool architecture
if ( ! _pool->whatprovides )
{
MIL << "pool_createwhatprovides..." << endl;
+
::pool_addfileprovides( _pool );
::pool_createwhatprovides( _pool );
}
if ( ! _pool->languages )
{
- std::vector<std::string> fallbacklist;
- for ( Locale l( ZConfig::instance().textLocale() ); l != Locale::noCode; l = l.fallback() )
- {
- fallbacklist.push_back( l.code() );
- }
- dumpRangeLine( MIL << "pool_set_languages: ", fallbacklist.begin(), fallbacklist.end() ) << endl;
-
- std::vector<const char *> fallbacklist_cstr;
- for_( it, fallbacklist.begin(), fallbacklist.end() )
- {
- fallbacklist_cstr.push_back( it->c_str() );
- }
- ::pool_set_languages( _pool, &fallbacklist_cstr.front(), fallbacklist_cstr.size() );
+ // initial seting
+ const_cast<PoolImpl*>(this)->setTextLocale( ZConfig::instance().textLocale() );
}
}
+ void PoolImpl::prepareForSolving() const
+ {
+ // additional /etc/sysconfig/storage check:
+ static WatchFile sysconfigFile( sysconfigStoragePath(), WatchFile::NO_INIT );
+ if ( sysconfigFile.hasChanged() )
+ {
+ _requiredFilesystemsPtr.reset(); // recreated on demand
+ const_cast<PoolImpl*>(this)->depSetDirty( "/etc/sysconfig/storage change" );
+ }
+ // finally prepare as usual:
+ prepare();
+ }
+
///////////////////////////////////////////////////////////////////
::_Repo * PoolImpl::_createRepo( const std::string & name_r )
void PoolImpl::_deleteRepo( ::_Repo * repo_r )
{
setDirty(__FUNCTION__, repo_r->name );
- ::repo_free( repo_r, /*reuseids*/false );
+ if ( isSystemRepo( repo_r ) )
+ _autoinstalled.clear();
eraseRepoInfo( repo_r );
+ ::repo_free( repo_r, /*reuseids*/false );
}
int PoolImpl::_addSolv( ::_Repo * repo_r, FILE * file_r )
{
setDirty(__FUNCTION__, repo_r->name );
- int ret = ::repo_add_solv( repo_r , file_r );
+ int ret = ::repo_add_solv( repo_r, file_r, 0 );
if ( ret == 0 )
_postRepoAdd( repo_r );
return ret;
int PoolImpl::_addHelix( ::_Repo * repo_r, FILE * file_r )
{
setDirty(__FUNCTION__, repo_r->name );
- ::repo_add_helix( repo_r , file_r, 0 ); // unfortunately void
- _postRepoAdd( repo_r );
+ int ret = ::repo_add_helix( repo_r, file_r, 0 );
+ if ( ret == 0 )
+ _postRepoAdd( repo_r );
return 0;
}
for_( it, sysarchs.begin(), sysarchs.end() )
sysids.insert( it->id() );
- // unfortunately satsolver treats src/nosrc as architecture:
+ // unfortunately libsolv treats src/nosrc as architecture:
sysids.insert( ARCH_SRC );
sysids.insert( ARCH_NOSRC );
}
{
bool dirty = false;
- // satsolver priority is based on '<', while yum's repoinfo
+ // libsolv priority is based on '<', while yum's repoinfo
// uses 1(highest)->99(lowest). Thus we use -info_r.priority.
if ( repo->priority != int(-info_r.priority()) )
{
///////////////////////////////////////////////////////////////////
- // need on demand and id based Locale
- void _locale_hack( const LocaleSet & locales_r,
- std::tr1::unordered_set<IdString> & locale2Solver )
+ void PoolImpl::setTextLocale( const Locale & locale_r )
{
- std::tr1::unordered_set<IdString>( 2*locales_r.size() ).swap( locale2Solver );
- for_( it, locales_r.begin(),locales_r.end() )
- {
- for ( Locale l( *it ); l != Locale::noCode; l = l.fallback() )
- locale2Solver.insert( IdString( l.code() ) );
- }
- MIL << "New Solver Locales: " << locale2Solver << endl;
+ std::vector<std::string> fallbacklist;
+ for ( Locale l( locale_r ); l; l = l.fallback() )
+ {
+ fallbacklist.push_back( l.code() );
+ }
+ dumpRangeLine( MIL << "pool_set_languages: ", fallbacklist.begin(), fallbacklist.end() ) << endl;
+
+ std::vector<const char *> fallbacklist_cstr;
+ for_( it, fallbacklist.begin(), fallbacklist.end() )
+ {
+ fallbacklist_cstr.push_back( it->c_str() );
+ }
+ ::pool_set_languages( _pool, &fallbacklist_cstr.front(), fallbacklist_cstr.size() );
+ }
+
+ void PoolImpl::initRequestedLocales( const LocaleSet & locales_r )
+ {
+ if ( _requestedLocalesTracker.setInitial( locales_r ) )
+ {
+ localeSetDirty( "initRequestedLocales" );
+ MIL << "Init RequestedLocales: " << _requestedLocalesTracker << " =" << locales_r << endl;
+ }
}
void PoolImpl::setRequestedLocales( const LocaleSet & locales_r )
{
- depSetDirty( "setRequestedLocales" );
- _requestedLocales = locales_r;
- MIL << "New RequestedLocales: " << locales_r << endl;
- _locale_hack( _requestedLocales, _locale2Solver );
+ if ( _requestedLocalesTracker.set( locales_r ) )
+ {
+ localeSetDirty( "setRequestedLocales" );
+ MIL << "New RequestedLocales: " << _requestedLocalesTracker << " =" << locales_r << endl;
+ }
}
bool PoolImpl::addRequestedLocale( const Locale & locale_r )
{
- if ( _requestedLocales.insert( locale_r ).second )
+ bool done = _requestedLocalesTracker.add( locale_r );
+ if ( done )
{
- depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
- _locale_hack( _requestedLocales, _locale2Solver );
- return true;
+ localeSetDirty( "addRequestedLocale", locale_r.code().c_str() );
+ MIL << "New RequestedLocales: " << _requestedLocalesTracker << " +" << locale_r << endl;
}
- return false;
+ return done;
}
bool PoolImpl::eraseRequestedLocale( const Locale & locale_r )
{
- if ( _requestedLocales.erase( locale_r ) )
+ bool done = _requestedLocalesTracker.remove( locale_r );
+ if ( done )
{
- depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
- _locale_hack( _requestedLocales, _locale2Solver );
- return true;
+ localeSetDirty( "addRequestedLocale", locale_r.code().c_str() );
+ MIL << "New RequestedLocales: " << _requestedLocalesTracker << " -" << locale_r << endl;
}
- return false;
+ return done;
+ }
+
+
+ const PoolImpl::TrackedLocaleIds & PoolImpl::trackedLocaleIds() const
+ {
+ if ( ! _trackedLocaleIdsPtr )
+ {
+ _trackedLocaleIdsPtr.reset( new TrackedLocaleIds );
+
+ const base::SetTracker<LocaleSet> & localesTracker( _requestedLocalesTracker );
+ TrackedLocaleIds & localeIds( *_trackedLocaleIdsPtr );
+
+ // Add current locales+fallback except for added ones
+ for ( Locale lang: localesTracker.current() )
+ {
+ if ( localesTracker.wasAdded( lang ) )
+ continue;
+ for ( ; lang; lang = lang.fallback() )
+ { localeIds.current().insert( IdString(lang) ); }
+ }
+
+ // Add added locales+fallback except they are already in current
+ for ( Locale lang: localesTracker.added() )
+ {
+ for ( ; lang && localeIds.current().insert( IdString(lang) ).second; lang = lang.fallback() )
+ { localeIds.added().insert( IdString(lang) ); }
+ }
+
+ // Add removed locales+fallback except they are still in current
+ for ( Locale lang: localesTracker.removed() )
+ {
+ for ( ; lang && ! localeIds.current().count( IdString(lang) ); lang = lang.fallback() )
+ { localeIds.removed().insert( IdString(lang) ); }
+ }
+
+ // Assert that TrackedLocaleIds::current is not empty.
+ // If, so fill in LanguageCode::enCode as last resort.
+ if ( localeIds.current().empty() )
+ { localeIds.current().insert( IdString(Locale::enCode) ); }
+ }
+ return *_trackedLocaleIdsPtr;
}
- static void _getLocaleDeps( Capability cap_r, std::tr1::unordered_set<sat::detail::IdType> & store_r )
+
+ static void _getLocaleDeps( const Capability & cap_r, LocaleSet & store_r )
{
// Collect locales from any 'namespace:language(lang)' dependency
CapDetail detail( cap_r );
case CapDetail::CAP_NAMESPACE:
if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
{
- store_r.insert( detail.rhs().id() );
+ store_r.insert( Locale( IdString(detail.rhs().id()) ) );
}
break;
{
if ( !_availableLocalesPtr )
{
- // Collect any 'namespace:language(ja)' dependencies
- std::tr1::unordered_set<sat::detail::IdType> tmp;
- Pool pool( Pool::instance() );
- for_( it, pool.solvablesBegin(), pool.solvablesEnd() )
- {
- Capabilities cap( it->supplements() );
- for_( cit, cap.begin(), cap.end() )
- {
- _getLocaleDeps( *cit, tmp );
+ _availableLocalesPtr.reset( new LocaleSet );
+ LocaleSet & localeSet( *_availableLocalesPtr );
+
+ for ( const Solvable & pi : Pool::instance().solvables() )
+ {
+ for ( const Capability & cap : pi.supplements() )
+ {
+ _getLocaleDeps( cap, localeSet );
}
- }
-#warning immediately build LocaleSet as soon as Loale is an Id based type
- _availableLocalesPtr.reset( new LocaleSet(tmp.size()) );
- for_( it, tmp.begin(), tmp.end() )
- {
- _availableLocalesPtr->insert( Locale( IdString(*it) ) );
- }
+ }
}
return *_availableLocalesPtr;
}
+ ///////////////////////////////////////////////////////////////////
+
+ void PoolImpl::multiversionListInit() const
+ {
+ _multiversionListPtr.reset( new MultiversionList );
+ MultiversionList & multiversionList( *_multiversionListPtr );
+
+ MultiversionList::size_type size = 0;
+ for ( const std::string & spec : ZConfig::instance().multiversionSpec() )
+ {
+ static const std::string prefix( "provides:" );
+ bool provides = str::hasPrefix( spec, prefix );
+
+ for ( Solvable solv : WhatProvides( Capability( provides ? spec.c_str() + prefix.size() : spec.c_str() ) ) )
+ {
+ if ( provides || solv.ident() == spec )
+ multiversionList.insert( solv );
+ }
+
+ MultiversionList::size_type nsize = multiversionList.size();
+ MIL << "Multiversion install " << spec << ": " << (nsize-size) << " matches" << endl;
+ size = nsize;
+ }
+ }
+
+ void PoolImpl::multiversionSpecChanged()
+ { _multiversionListPtr.reset(); }
+
+ const PoolImpl::MultiversionList & PoolImpl::multiversionList() const
+ {
+ if ( ! _multiversionListPtr )
+ multiversionListInit();
+ return *_multiversionListPtr;
+ }
+
+ bool PoolImpl::isMultiversion( const Solvable & solv_r ) const
+ { return multiversionList().contains( solv_r ); }
+
+ ///////////////////////////////////////////////////////////////////
+
+ const std::set<std::string> & PoolImpl::requiredFilesystems() const
+ {
+ if ( ! _requiredFilesystemsPtr )
+ {
+ _requiredFilesystemsPtr.reset( new std::set<std::string> );
+ std::set<std::string> & requiredFilesystems( *_requiredFilesystemsPtr );
+ str::split( base::sysconfig::read( sysconfigStoragePath() )["USED_FS_LIST"],
+ std::inserter( requiredFilesystems, requiredFilesystems.end() ) );
+ }
+ return *_requiredFilesystemsPtr;
+ }
+
/////////////////////////////////////////////////////////////////
} // namespace detail
///////////////////////////////////////////////////////////////////