Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / sat / detail / PoolImpl.cc
index 2d0cbbb..eb77b4e 100644 (file)
@@ -10,6 +10,7 @@
  *
 */
 #include <iostream>
+#include <fstream>
 #include <boost/mpl/int.hpp>
 
 #include "zypp/base/Easy.h"
@@ -17,6 +18,9 @@
 #include "zypp/base/Gettext.h"
 #include "zypp/base/Exception.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/Pool.h"
 #include "zypp/Capability.h"
 #include "zypp/Locale.h"
+#include "zypp/PoolItem.h"
+
+#include "zypp/target/modalias/Modalias.h"
+#include "zypp/media/MediaPriority.h"
+
+extern "C"
+{
+// Workaround libsolv project not providing a common include
+// directory. (the -devel package does, but the git repo doesn't).
+// #include <solv/repo_helix.h>
+int repo_add_helix( ::Repo *repo, FILE *fp, int flags );
+}
 
 using std::endl;
 
@@ -32,10 +48,21 @@ 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
   { /////////////////////////////////////////////////////////////////
+
     ///////////////////////////////////////////////////////////////////
     namespace detail
     { /////////////////////////////////////////////////////////////////
@@ -55,27 +82,81 @@ namespace zypp
       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_OR,        ==, REL_OR );
       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_WITH,      ==, REL_WITH );
       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_NAMESPACE, ==, REL_NAMESPACE );
+      BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_ARCH,      ==, REL_ARCH );
 
      /////////////////////////////////////////////////////////////////
 
+      const std::string & PoolImpl::systemRepoAlias()
+      {
+        static const std::string _val( "@System" );
+        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;
+         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;
          }
       }
 
-      detail::IdType PoolImpl::nsCallback( struct _Pool *, void *data, detail::IdType lhs, detail::IdType rhs )
+      detail::IdType PoolImpl::nsCallback( struct _Pool *, void * data, detail::IdType lhs, detail::IdType rhs )
       {
-        if ( lhs == NAMESPACE_LANGUAGE )
+        // lhs:    the namespace identifier, e.g. NAMESPACE:MODALIAS
+        // rhs:    the value, e.g. pci:v0000104Cd0000840[01]sv*sd*bc*sc*i*
+        // return: 0 if not supportded
+        //         1 if supported by the system
+        //        -1  AFAIK it's also possible to return a list of solvables that support it, but don't know how.
+
+        static const detail::IdType RET_unsupported    = 0;
+        static const detail::IdType RET_systemProperty = 1;
+        switch ( lhs )
         {
-          const std::tr1::unordered_set<IdString> & locale2Solver( reinterpret_cast<PoolImpl*>(data)->_locale2Solver );
-          return locale2Solver.find( IdString(rhs) ) == locale2Solver.end() ? 0 : 1;
+          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;
+          }
+          break;
+
+          case NAMESPACE_MODALIAS:
+          {
+            // modalias strings in capability may be hexencoded because rpm does not allow
+            // ',', ' ' or other special chars.
+            return target::Modalias::instance().query( str::hexdecode( IdString(rhs).c_str() ) )
+                ? RET_systemProperty
+              : RET_unsupported;
+          }
+          break;
+
+          case NAMESPACE_FILESYSTEM:
+          {
+           const std::set<std::string> & requiredFilesystems( reinterpret_cast<PoolImpl*>(data)->requiredFilesystems() );
+            return requiredFilesystems.find( IdString(rhs).asString() ) != requiredFilesystems.end() ? RET_systemProperty : RET_unsupported;
+          }
+          break;
+
         }
-        DBG << Capability( lhs ) << " vs. " << Capability( rhs ) << endl;
-        return 0;
+
+        WAR << "Unhandled " << Capability( lhs ) << " vs. " << Capability( rhs ) << endl;
+        return RET_unsupported;
       }
 
       ///////////////////////////////////////////////////////////////////
@@ -102,9 +183,24 @@ namespace zypp
         {
           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") );
-        ::pool_setdebuglevel( _pool, verbose ? 5 : 1 );
+       if ( env::LIBSOLV_DEBUGMASK() )
+       {
+         ::pool_setdebugmask(_pool, env::LIBSOLV_DEBUGMASK() );
+       }
+       else
+       {
+         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 );
 
         // set namespace callback
@@ -134,6 +230,7 @@ namespace zypp
         }
         _serial.setDirty();           // pool content change
         _availableLocalesPtr.reset(); // available locales may change
+        _multiversionListPtr.reset(); // re-evaluate ZConfig::multiversionSpec.
 
         // invaldate dependency/namespace related indices:
         depSetDirty();
@@ -152,7 +249,7 @@ namespace zypp
 
       void PoolImpl::prepare() const
       {
-        if ( _watcher.remember( _serial ) )
+       if ( _watcher.remember( _serial ) )
         {
           // After repo/solvable add/remove:
           // set pool architecture
@@ -161,43 +258,80 @@ namespace zypp
         if ( ! _pool->whatprovides )
         {
           MIL << "pool_createwhatprovides..." << endl;
-          ::pool_addfileprovides( _pool, sat::Pool::instance().systemRepo().get() );
+
+          ::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();
+      }
+
       ///////////////////////////////////////////////////////////////////
 
-      int PoolImpl::_addSolv( ::_Repo * repo_r, FILE * file_r, bool isSystemRepo_r )
+      ::_Repo * PoolImpl::_createRepo( const std::string & name_r )
+      {
+        setDirty(__FUNCTION__, name_r.c_str() );
+        ::_Repo * ret = ::repo_create( _pool, name_r.c_str() );
+        if ( ret && name_r == systemRepoAlias() )
+          ::pool_set_installed( _pool, ret );
+        return ret;
+      }
+
+      void PoolImpl::_deleteRepo( ::_Repo * repo_r )
       {
         setDirty(__FUNCTION__, repo_r->name );
-        int ret = ::repo_add_solv( repo_r , file_r  );
-        if ( ret == 0 && ! isSystemRepo_r )
+       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, 0 );
+        if ( ret == 0 )
+          _postRepoAdd( repo_r );
+        return ret;
+      }
+
+      int PoolImpl::_addHelix( ::_Repo * repo_r, FILE * file_r )
+      {
+        setDirty(__FUNCTION__, repo_r->name );
+        int ret = ::repo_add_helix( repo_r, file_r, 0 );
+        if ( ret == 0 )
+          _postRepoAdd( repo_r );
+        return 0;
+      }
+
+      void PoolImpl::_postRepoAdd( ::_Repo * repo_r )
+      {
+        if ( ! isSystemRepo( repo_r ) )
         {
-          // Filter out unwanted archs
+            // Filter out unwanted archs
           std::set<detail::IdType> sysids;
           {
             Arch::CompatSet sysarchs( Arch::compatSet( ZConfig::instance().systemArchitecture() ) );
             for_( it, sysarchs.begin(), sysarchs.end() )
-              sysids.insert( it->id() );
+              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 );
           }
@@ -206,29 +340,64 @@ namespace zypp
           unsigned       blockSize  = 0;
           for ( detail::IdType i = repo_r->start; i < repo_r->end; ++i )
           {
-            ::_Solvable * s( _pool->solvables + i );
-            if ( s->repo == repo_r && sysids.find( s->arch ) == sysids.end() )
-            {
-              // Remember an unwanted arch entry:
-              if ( ! blockBegin )
-                blockBegin = i;
-              ++blockSize;
-            }
-            else if ( blockSize )
-            {
+              ::_Solvable * s( _pool->solvables + i );
+              if ( s->repo == repo_r && sysids.find( s->arch ) == sysids.end() )
+              {
+                // Remember an unwanted arch entry:
+                if ( ! blockBegin )
+                  blockBegin = i;
+                ++blockSize;
+              }
+              else if ( blockSize )
+              {
+                // Free remembered entries
+                  ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
+                  blockBegin = blockSize = 0;
+              }
+          }
+          if ( blockSize )
+          {
               // Free remembered entries
               ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
               blockBegin = blockSize = 0;
-            }
           }
-          if ( blockSize )
+        }
+      }
+
+      detail::SolvableIdType PoolImpl::_addSolvables( ::_Repo * repo_r, unsigned count_r )
+      {
+        setDirty(__FUNCTION__, repo_r->name );
+        return ::repo_add_solvable_block( repo_r, count_r );
+      }
+
+      void PoolImpl::setRepoInfo( RepoIdType id_r, const RepoInfo & info_r )
+      {
+        ::_Repo * repo( getRepo( id_r ) );
+        if ( repo )
+        {
+          bool dirty = false;
+
+          // 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()) )
           {
-            // Free remembered entries
-            ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
-            blockBegin = blockSize = 0;
+            repo->priority = -info_r.priority();
+            dirty = true;
           }
+
+         // subpriority is used to e.g. prefer http over dvd iff
+         // both have same priority.
+          int mediaPriority( media::MediaPriority( info_r.url() ) );
+          if ( repo->subpriority != mediaPriority )
+          {
+            repo->subpriority = mediaPriority;
+            dirty = true;
+          }
+
+          if ( dirty )
+            setDirty(__FUNCTION__, info_r.alias().c_str() );
         }
-        return ret;
+        _repoinfos[id_r] = info_r;
       }
 
       ///////////////////////////////////////////////////////////////////
@@ -237,7 +406,7 @@ namespace zypp
       void _locale_hack( const LocaleSet & locales_r,
                          std::tr1::unordered_set<IdString> & locale2Solver )
       {
-        std::tr1::unordered_set<IdString>( 2*locales_r.size() ).swap( locale2Solver ) ;
+        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() )
@@ -246,6 +415,23 @@ namespace zypp
         MIL << "New Solver Locales: " << locale2Solver << endl;
       }
 
+      void PoolImpl::setTextLocale( const Locale & locale_r )
+      {
+       std::vector<std::string> fallbacklist;
+       for ( Locale l( locale_r ); 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() );
+      }
+
       void PoolImpl::setRequestedLocales( const LocaleSet & locales_r )
       {
         depSetDirty( "setRequestedLocales" );
@@ -300,6 +486,7 @@ namespace zypp
 
             case CapDetail::REL_NONE:
             case CapDetail::CAP_WITH:
+            case CapDetail::CAP_ARCH:
               break; // unwanted
           }
         }
@@ -330,6 +517,51 @@ namespace zypp
         return *_availableLocalesPtr;
       }
 
+      void PoolImpl::multiversionListInit() const
+      {
+        _multiversionListPtr.reset( new MultiversionList );
+        MultiversionList & multiversionList( *_multiversionListPtr );
+
+        const std::set<std::string> & multiversionSpec( ZConfig::instance().multiversionSpec() );
+        for_( it, multiversionSpec.begin(), multiversionSpec.end() )
+        {
+          static const std::string prefix( "provides:" );
+          if ( str::hasPrefix( *it, prefix ) )
+          {
+            WhatProvides provides( Capability( it->c_str() + prefix.size() ) );
+            if ( provides.empty() )
+            {
+              MIL << "Multiversion install not provided (" << *it << ")" << endl;
+            }
+            else
+            {
+              for_( pit, provides.begin(), provides.end() )
+              {
+                if ( multiversionList.insert( pit->ident() ).second )
+                  MIL << "Multiversion install " << pit->ident() << " (" << *it << ")" << endl;
+              }
+            }
+          }
+          else
+          {
+            MIL << "Multiversion install " << *it << endl;
+            multiversionList.insert( IdString( *it ) );
+          }
+        }
+      }
+
+      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
     ///////////////////////////////////////////////////////////////////