Remove Atom, Script, Message and other obsolete classes
[platform/upstream/libzypp.git] / zypp / sat / Solvable.cc
index a0d2b51..f67083a 100644 (file)
 #include "zypp/base/Logger.h"
 #include "zypp/base/Gettext.h"
 #include "zypp/base/Exception.h"
+#include "zypp/base/Functional.h"
+#include "zypp/base/Collector.h"
 
 #include "zypp/sat/detail/PoolImpl.h"
 #include "zypp/sat/Solvable.h"
-#include "zypp/sat/Repo.h"
+#include "zypp/sat/Pool.h"
+#include "zypp/Repository.h"
+#include "zypp/OnMediaLocation.h"
 
 using std::endl;
 
@@ -28,7 +32,68 @@ namespace zypp
   namespace sat
   { /////////////////////////////////////////////////////////////////
 
-    const Solvable Solvable::nosolvable;
+    Solvable::SplitIdent::SplitIdent( IdString ident_r )
+    : _ident( ident_r )
+    {
+      if ( ! ident_r )
+        return;
+
+      const char * ident = ident_r.c_str();
+      const char * sep = ::strchr( ident, ':' );
+
+      // no ':' in package names (hopefully)
+      if ( ! sep )
+      {
+        _kind = ResKind::package;
+        _name = ident_r;
+        return;
+      }
+
+      // save name
+      _name = IdString( sep+1 );
+      // quick check for well known kinds
+      if ( sep-ident >= 4 )
+      {
+        switch ( ident[3] )
+        {
+#define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) _kind = ResKind::K
+          //             ----v
+          case 'c': OUTS( patch, 5 );       return; break;
+          case 'd': OUTS( product, 7 );     return; break;
+          case 'k': OUTS( package, 7 );     return; break;
+          case 'p': OUTS( srcpackage, 10 ); return; break;
+          case 't': OUTS( pattern, 7 );     return; break;
+#undef OUTS
+        }
+      }
+
+      // an unknown kind
+      _kind = ResKind( std::string( ident, sep-ident ) );
+    }
+
+    Solvable::SplitIdent::SplitIdent( ResKind kind_r, IdString name_r )
+    : _kind( kind_r )
+    , _name( name_r )
+    {
+      if ( kind_r == ResKind::package || kind_r == ResKind::srcpackage )
+        _ident = _name;
+      else
+        _ident = IdString( str::form( "%s:%s", kind_r.c_str(), name_r.c_str() ) );
+    }
+
+    Solvable::SplitIdent::SplitIdent( ResKind kind_r, const C_Str & name_r )
+    : _kind( kind_r )
+    , _name( name_r )
+    {
+      if ( kind_r == ResKind::package || kind_r == ResKind::srcpackage )
+        _ident = _name;
+      else
+        _ident = IdString( str::form( "%s:%s", kind_r.c_str(), name_r.c_str() ) );
+    }
+
+    /////////////////////////////////////////////////////////////////
+
+    const Solvable Solvable::noSolvable;
 
     /////////////////////////////////////////////////////////////////
 
@@ -44,7 +109,7 @@ namespace zypp
 
     Solvable Solvable::nextInRepo() const
     {
-      NO_SOLVABLE_RETURN( nosolvable );
+      NO_SOLVABLE_RETURN( noSolvable );
       for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
       {
         ::_Solvable * nextS( myPool().getSolvable( next ) );
@@ -53,17 +118,20 @@ namespace zypp
           return Solvable( next );
         }
       }
-      return nosolvable;
+      return noSolvable;
     }
 
-    Repo Solvable::repo() const
+    Repository Solvable::repository() const
     {
-      NO_SOLVABLE_RETURN( Repo::norepo );
-      return Repo( _solvable->repo );
+      NO_SOLVABLE_RETURN( Repository::noRepository );
+      return Repository( _solvable->repo );
     }
 
     bool Solvable::isSystem() const
-    { return repo().isSystemRepo(); }
+    {
+      NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
+      return Repository( _solvable->repo ).isSystemRepo();
+    }
 
     IdString Solvable::ident() const
     {
@@ -71,112 +139,88 @@ namespace zypp
       return IdString( _solvable->name );
     }
 
-    std::string Solvable::lookupStrAttribute( const SolvAttr &attr ) const
+    std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
     {
-      const char *s = repo_lookup_str(this->get(), attr.idStr().id());
+      NO_SOLVABLE_RETURN( std::string() );
+      const char * s = ::solvable_lookup_str( _solvable, attr.id() );
       return s ? s : std::string();
     }
 
-    unsigned Solvable::lookupNumAttribute( const SolvAttr &attr ) const
+    std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
     {
-      return repo_lookup_num(this->get(), attr.idStr().id());
+      NO_SOLVABLE_RETURN( std::string() );
+      const char * s = 0;
+      if ( lang_r == Locale::noCode )
+      {
+        s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
+      }
+      else
+      {
+        s = ::solvable_lookup_str_lang( _solvable, attr.id(), lang_r.code().c_str() );
+      }
+      return s ? s : std::string();
+   }
+
+    unsigned Solvable::lookupNumAttribute( const SolvAttr & attr ) const
+    {
+      NO_SOLVABLE_RETURN( 0 );
+      return ::solvable_lookup_num( _solvable, attr.id(), 0 );
     }
-    
-    bool Solvable::lookupBoolAttribute( const SolvAttr &attr ) const
+
+    bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
     {
-      return repo_lookup_num(this->get(), attr.idStr().id()) > 0;
+      NO_SOLVABLE_RETURN( false );
+      return ::solvable_lookup_bool( _solvable, attr.id() );
     }
 
-    struct LocCallback
+    detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
     {
-      unsigned medianr;
-      const char *mediadir;
-      const char *mediafile;
-      int trivial;
-    };
+      NO_SOLVABLE_RETURN( detail::noId );
+      return ::solvable_lookup_id( _solvable, attr.id() );
+    }
 
-    static int
-    location_cb (void *vcbdata, ::Solvable *s, ::Repodata *data, ::Repokey *key, ::KeyValue *kv)
+    CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
     {
-      LocCallback *lc = (LocCallback *)vcbdata;
-      switch (key->type)
+      NO_SOLVABLE_RETURN( CheckSum() );
+      detail::IdType chksumtype = 0;
+      const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
+      if ( ! s )
+        return CheckSum();
+      switch ( chksumtype )
       {
-        case TYPE_ID:
-        if (key->name == SolvAttr::mediadir.idStr().id())
-        {
-          if (data->localpool)
-            lc->mediadir = stringpool_id2str(&data->spool, kv->id);
-          else
-            lc->mediadir = id2str(data->repo->pool, kv->id);
-        }
-        break;
-        case TYPE_STR:
-        if (key->name == SolvAttr::mediafile.idStr().id())
-          lc->mediafile = kv->str;
-        break;
-          case TYPE_VOID:
-        if (key->name == SolvAttr::mediafile.idStr().id())
-          lc->trivial = 1;
-        break;
-          case TYPE_CONSTANT:
-        if (key->name == SolvAttr::medianr.idStr().id())
-          lc->medianr = kv->num;
-        break;
+        case REPOKEY_TYPE_MD5:    return CheckSum::md5( s );
+        case REPOKEY_TYPE_SHA1:   return CheckSum::sha1( s );
+        case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
       }
-      /* continue walking */
-      return 0;
+      return CheckSum( std::string(), s ); // try to autodetect
     }
 
-    std::string Solvable::lookupLocation(unsigned &medianr) const
+    OnMediaLocation Solvable::lookupLocation() const
+    //std::string Solvable::lookupLocation( unsigned & medianr ) const
     {
-      NO_SOLVABLE_RETURN( std::string() );
-      ::Repo *repo = _solvable->repo;
-      ::Pool *pool = repo->pool;
-      Id sid = _solvable - pool->solvables;
-      ::Repodata *data;
-      unsigned i;
-      LocCallback lc;
-      lc.medianr = 1;
-      lc.mediadir = 0;
-      lc.mediafile = 0;
-      lc.trivial = 0;
-      for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
-      {
-        if (data->state == REPODATA_STUB || data->state == REPODATA_ERROR)
-          continue;
-        if (sid < data->start || sid >= data->end)
-          continue;
-        repodata_search(data, sid - data->start, 0, location_cb, &lc);
-      }
-      medianr = lc.medianr;
-      std::string ret;
-      
-      if (!lc.trivial)
-      {
-        if (lc.mediafile)
-          ret += lc.mediafile;
-        return ret;
-      }
+      NO_SOLVABLE_RETURN( OnMediaLocation() );
+      // medianumber and path
+      unsigned medianr;
+      char * file = ::solvable_get_location( _solvable, &medianr );
+      if ( ! file )
+        return OnMediaLocation();
 
-      if (lc.mediadir)
-      {
-        ret += std::string( lc.mediadir ) + "/";
-      }
-      else
+      OnMediaLocation ret;
+
+      Pathname path;
+      if ( repository().info().type().toEnum() == repo::RepoType::YAST2_e )
       {
-        /* If we haven't seen an explicit dirname, then prepend the arch as
-           directory.  */
-        ret += "suse/";
-        ret += IdString(_solvable->arch).asString() + "/";
+#warning STILL HARDCODED /suse PREFIX in location
+        // (ma@) loading a susetags repo search for a solvable with attribute
+        // susetags:datadir. this is the prefix. store it in RepoInfo(?).
+        path = "suse";
       }
-      /* Trivial means that we can construct the rpm name from our
-         solvable data, as name-evr.arch.rpm .  */
-      ret += IdString(_solvable->name).asString();
-      ret += '-';
-      ret += IdString(_solvable->evr).asString();
-      ret += '.';
-      ret += IdString(_solvable->arch).asString();
-      ret += ".rpm";
+      ret.setLocation    ( path/file, medianr );
+      ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ), ByteCount::K ) );
+      ret.setChecksum    ( lookupCheckSumAttribute( SolvAttr::checksum ) );
+      // Not needed/available for solvables?
+      //ret.setOpenSize    ( ByteCount( lookupNumAttribute( SolvAttr::opensize ), ByteCount::K ) );
+      //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
       return ret;
     }
 
@@ -208,11 +252,8 @@ namespace zypp
           //             ----v
           case 'c': OUTS( patch, 5 );       break;
           case 'd': OUTS( product, 7 );     break;
-          case 'i': OUTS( script, 6 );      break;
           case 'k': OUTS( package, 7 );     break;
-          case 'm': OUTS( atom, 4 );        break;
           case 'p': OUTS( srcpackage, 10 ); break;
-          case 's': OUTS( message, 7 );     break;
           case 't': OUTS( pattern, 7 );     break;
 #undef OUTS
         }
@@ -227,9 +268,12 @@ namespace zypp
       NO_SOLVABLE_RETURN( false );
 
       // detect srcpackages by 'arch'
-      if ( kind_r == ResKind::srcpackage )
+      switch ( _solvable->arch )
       {
-        return( _solvable->arch == ARCH_SRC || _solvable->arch == ARCH_NOSRC );
+        case ARCH_SRC:
+        case ARCH_NOSRC:
+          return( kind_r == ResKind::srcpackage );
+          break;
       }
 
       // no ':' in package names (hopefully)
@@ -356,6 +400,112 @@ namespace zypp
                    : Capabilities();
     }
 
+    ///////////////////////////////////////////////////////////////////
+    namespace
+    { /////////////////////////////////////////////////////////////////
+      /** Expand \ref Capability and call \c fnc_r for each namescpace:language
+       * dependency. Return #invocations of fnc_r, negative if fnc_r returned
+       * false to indicate abort.
+       */
+      int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
+      {
+        CapDetail detail( cap_r );
+        if ( detail.kind() == CapDetail::EXPRESSION )
+        {
+          switch ( detail.capRel() )
+          {
+            case CapDetail::CAP_AND:
+            case CapDetail::CAP_OR:
+                // expand
+              {
+                int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
+                if ( res < 0 )
+                  return res; // negative on abort.
+                int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
+                if ( res2 < 0 )
+                  return -res + res2; // negative on abort.
+                return res + res2;
+              }
+              break;
+
+            case CapDetail::CAP_NAMESPACE:
+              if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
+              {
+                return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
+              }
+              break;
+
+            case CapDetail::REL_NONE:
+            case CapDetail::CAP_WITH:
+            case CapDetail::CAP_ARCH:
+              break; // unwanted
+          }
+        }
+        return 0;
+      }
+
+       /** Expand \ref Capability and call \c fnc_r for each namescpace:language
+       * dependency. Return #invocations of fnc_r, negative if fnc_r returned
+       * false to indicate abort.
+       */
+      inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
+      {
+        int cnt = 0;
+        for_( cit, cap_r.begin(), cap_r.end() )
+        {
+          int res = invokeOnEachSupportedLocale( *cit, fnc_r );
+          if ( res < 0 )
+            return -cnt + res; // negative on abort.
+          cnt += res;
+        }
+        return cnt;
+      }
+      //@}
+
+      // Functor returning false if a Locale is in the set.
+      struct NoMatchIn
+      {
+        NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
+
+        bool operator()( const Locale & locale_r ) const
+        {
+          return _locales.find( locale_r ) == _locales.end();
+        }
+
+        const LocaleSet & _locales;
+      };
+
+    } /////////////////////////////////////////////////////////////////
+
+    bool Solvable::supportsLocales() const
+    {
+      // false_c stops on 1st Locale.
+      return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
+    }
+
+    bool Solvable::supportsLocale( const Locale & locale_r ) const
+    {
+      // not_equal_to stops on == Locale.
+      return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
+    }
+
+    bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
+    {
+      if ( locales_r.empty() )
+        return false;
+      // NoMatchIn stops if Locale is included.
+      return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
+    }
+
+    bool Solvable::supportsRequestedLocales() const
+    { return supportsLocale( myPool().getRequestedLocales() ); }
+
+    void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
+    {
+      invokeOnEachSupportedLocale( supplements(),
+                                   functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
+    }
+
     /******************************************************************
     **
     ** FUNCTION NAME : operator<<
@@ -364,12 +514,12 @@ namespace zypp
     std::ostream & operator<<( std::ostream & str, const Solvable & obj )
     {
       if ( ! obj )
-        return str << "sat::solvable()";
+        return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
 
-      return str << "sat::solvable(" << obj.id() << "|"
+      return str << "(" << obj.id() << ")"
           << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
-          << '-' << obj.edition() << '.' << obj.arch() << "){"
-          << obj.repo().name() << "}";
+          << '-' << obj.edition() << '.' << obj.arch() << "("
+          << obj.repository().alias() << ")";
     }
 
     /******************************************************************