Imported Upstream version 17.0.0
[platform/upstream/libzypp.git] / zypp / sat / Solvable.cc
index 7a92d04..60352a9 100644 (file)
 #include "zypp/base/Exception.h"
 #include "zypp/base/Functional.h"
 #include "zypp/base/Collector.h"
+#include "zypp/base/Xml.h"
 
 #include "zypp/sat/detail/PoolImpl.h"
 #include "zypp/sat/Solvable.h"
+#include "zypp/sat/Pool.h"
+#include "zypp/sat/LookupAttr.h"
+
 #include "zypp/Repository.h"
+#include "zypp/OnMediaLocation.h"
+#include "zypp/ZConfig.h"
+
+#include "zypp/ui/Selectable.h"
 
 using std::endl;
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
   ///////////////////////////////////////////////////////////////////
   namespace sat
-  { /////////////////////////////////////////////////////////////////
+  {
+    ///////////////////////////////////////////////////////////////////
+    namespace
+    {
+      void _doSplit( IdString & _ident, ResKind & _kind, IdString & _name )
+      {
+        if ( ! _ident )
+          return;
+
+       ResKind explicitKind = ResKind::explicitBuiltin( _ident.c_str() );
+       // NOTE: kind package and srcpackage do not have namespaced ident!
+       if ( ! explicitKind  )
+       {
+          _name = _ident;
+         // No kind defaults to package
+         if ( !_kind )
+           _kind = ResKind::package;
+         else if ( ! ( _kind == ResKind::package || _kind == ResKind::srcpackage ) )
+           _ident = IdString( str::form( "%s:%s", _kind.c_str(), _ident.c_str() ) );
+       }
+       else
+       {
+         // strip kind spec from name
+         _name = IdString( ::strchr( _ident.c_str(), ':' )+1 );
+         _kind = explicitKind;
+         if ( _kind == ResKind::package || _kind == ResKind::srcpackage )
+           _ident = _name;
+       }
+       return;
+      }
+    } // namespace
+    ///////////////////////////////////////////////////////////////////
+
+    Solvable::SplitIdent::SplitIdent( IdString ident_r )
+    : _ident( ident_r )
+    { _doSplit( _ident, _kind, _name ); }
+
+    Solvable::SplitIdent::SplitIdent( const char * ident_r )
+    : _ident( ident_r )
+    { _doSplit( _ident, _kind, _name ); }
+
+    Solvable::SplitIdent::SplitIdent( const std::string & ident_r )
+    : _ident( ident_r )
+    { _doSplit( _ident, _kind, _name ); }
+
+    Solvable::SplitIdent::SplitIdent( ResKind kind_r, IdString name_r )
+    : _ident( name_r )
+    , _kind( kind_r )
+    { _doSplit( _ident, _kind, _name ); }
+
+    Solvable::SplitIdent::SplitIdent( ResKind kind_r, const C_Str & name_r )
+    : _ident( name_r )
+    , _kind( kind_r )
+    { _doSplit( _ident, _kind, _name ); }
 
-    const Solvable Solvable::nosolvable;
+    /////////////////////////////////////////////////////////////////
+    // class Solvable
+    /////////////////////////////////////////////////////////////////
+
+    const Solvable Solvable::noSolvable;
 
     /////////////////////////////////////////////////////////////////
 
-    ::_Solvable * Solvable::get() const
+    detail::CSolvable * Solvable::get() const
     { return myPool().getSolvable( _id ); }
 
 #define NO_SOLVABLE_RETURN( VAL ) \
-    ::_Solvable * _solvable( get() ); \
+    detail::CSolvable * _solvable( get() ); \
     if ( ! _solvable ) return VAL
 
     Solvable Solvable::nextInPool() const
@@ -46,144 +111,164 @@ 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 ) );
+        detail::CSolvable * nextS( myPool().getSolvable( next ) );
         if ( nextS && nextS->repo == _solvable->repo )
         {
           return Solvable( next );
         }
       }
-      return nosolvable;
+      return noSolvable;
     }
 
-    Repository Solvable::repository() const
+    std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
     {
-      NO_SOLVABLE_RETURN( Repository::noRepository );
-      return Repository( _solvable->repo );
+      NO_SOLVABLE_RETURN( std::string() );
+      const char * s = ::solvable_lookup_str( _solvable, attr.id() );
+      return s ? s : std::string();
     }
 
-    bool Solvable::isSystem() const
-    { return repository().isSystemRepo(); }
-
-    IdString Solvable::ident() const
+    std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
     {
-      NO_SOLVABLE_RETURN( IdString() );
-      return IdString( _solvable->name );
-    }
+      NO_SOLVABLE_RETURN( std::string() );
+      const char * s = 0;
+      if ( !lang_r )
+      {
+        s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
+      }
+      else
+      {
+       for ( Locale l( lang_r ); l; l = l.fallback() )
+       {
+         if ( (s = ::solvable_lookup_str_lang( _solvable, attr.id(), l.c_str(), 0 )) )
+           return s;
+       }
+       // here: no matching locale, so use default
+       s = ::solvable_lookup_str_lang( _solvable, attr.id(), 0, 0 );
+      }
+      return s ? s : std::string();
+   }
 
-    std::string Solvable::lookupStrAttribute( const SolvAttr &attr ) const
+    unsigned long long Solvable::lookupNumAttribute( const SolvAttr & attr ) const
     {
-      const char *s = repo_lookup_str(this->get(), attr.idStr().id());
-      return s ? s : std::string();
+      NO_SOLVABLE_RETURN( 0 );
+      return ::solvable_lookup_num( _solvable, attr.id(), 0 );
     }
 
-    unsigned Solvable::lookupNumAttribute( const SolvAttr &attr ) const
+    unsigned long long Solvable::lookupNumAttribute( const SolvAttr & attr, unsigned long long notfound_r ) const
     {
-      return repo_lookup_num(this->get(), attr.idStr().id());
+      NO_SOLVABLE_RETURN( notfound_r );
+      return ::solvable_lookup_num( _solvable, attr.id(), notfound_r );
     }
 
-    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 REPOKEY_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 REPOKEY_TYPE_STR:
-          if (key->name == SolvAttr::mediafile.idStr().id())
-            lc->mediafile = kv->str;
-          break;
-        case REPOKEY_TYPE_VOID:
-          if (key->name == SolvAttr::mediafile.idStr().id())
-            lc->trivial = 1;
-          break;
-        case REPOKEY_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_SHA224: return CheckSum::sha224( s );
+        case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
+        case REPOKEY_TYPE_SHA384: return CheckSum::sha384( s );
+        case REPOKEY_TYPE_SHA512: return CheckSum::sha512( s );
       }
-      /* continue walking */
-      return 0;
+      return CheckSum( std::string(), s ); // try to autodetect
     }
 
-    std::string Solvable::lookupLocation(unsigned &medianr) const
+    ///////////////////////////////////////////////////////////////////
+    namespace
     {
-      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++)
+      inline Pathname lookupDatadirIn( Repository repor_r )
       {
-        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);
+        static const SolvAttr susetagsDatadir( "susetags:datadir" );
+        Pathname ret;
+        // First look for repo attribute "susetags:datadir". If not found,
+        // look into the solvables as Code11 libsolv placed it there.
+        LookupRepoAttr datadir( susetagsDatadir, repor_r );
+        if ( ! datadir.empty() )
+          ret = datadir.begin().asString();
+        else
+        {
+          LookupAttr datadir( susetagsDatadir, repor_r );
+          if ( ! datadir.empty() )
+            ret = datadir.begin().asString();
+        }
+        return ret;
       }
-      medianr = lc.medianr;
-      std::string ret;
+    } // namespace
+    ///////////////////////////////////////////////////////////////////
 
-      if (lc.mediadir)
-      {
-        ret += std::string( lc.mediadir ) + "/";
-      }
-      else
-      {
-        /* If we haven't seen an explicit dirname, then prepend the arch as
-           directory.  */
-        ret += "suse/";
-        ret += IdString(_solvable->arch).asString() + "/";
-      }
+    OnMediaLocation Solvable::lookupLocation() const
+    {
+      NO_SOLVABLE_RETURN( OnMediaLocation() );
+      // medianumber and path
+      unsigned medianr;
+      const char * file = ::solvable_lookup_location( _solvable, &medianr );
+      if ( ! file )
+        return OnMediaLocation();
+      if ( ! medianr )
+       medianr = 1;
+
+      OnMediaLocation ret;
 
-      if (!lc.trivial)
+      Pathname path;
+      switch ( repository().info().type().toEnum() )
       {
-        if (lc.mediafile)
-          ret += lc.mediafile;
-        return ret;
-      }
+        case repo::RepoType::NONE_e:
+        {
+          path = lookupDatadirIn( repository() );
+          if ( ! path.empty() )
+            repository().info().setProbedType( repo::RepoType::YAST2_e );
+        }
+        break;
+
+        case repo::RepoType::YAST2_e:
+        {
+          path = lookupDatadirIn( repository() );
+          if ( path.empty() )
+            path = "suse";
+        }
+        break;
 
-      /* 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";
+        default:
+          break;
+      }
+      ret.setLocation    ( path/file, medianr );
+      ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ) ) );
+      ret.setChecksum    ( lookupCheckSumAttribute( SolvAttr::checksum ) );
+      // Not needed/available for solvables?
+      //ret.setOpenSize    ( ByteCount( lookupNumAttribute( SolvAttr::opensize ) ) );
+      //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
       return ret;
     }
 
-    ResKind Solvable::kind() const
+
+    IdString Solvable::ident() const
+    {
+      NO_SOLVABLE_RETURN( IdString() );
+      return IdString( _solvable->name );
+    }
+
+     ResKind Solvable::kind() const
     {
       NO_SOLVABLE_RETURN( ResKind() );
       // detect srcpackages by 'arch'
@@ -195,33 +280,18 @@ namespace zypp
           break;
       }
 
+      // either explicitly prefixed...
       const char * ident = IdString( _solvable->name ).c_str();
-      const char * sep = ::strchr( ident, ':' );
+      ResKind knownKind( ResKind::explicitBuiltin( ident ) );
+      if ( knownKind )
+       return knownKind;
 
-      // no ':' in package names (hopefully)
+      // ...or no ':' in package names (hopefully)...
+      const char * sep = ::strchr( ident, ':' );
       if ( ! sep )
-        return ResKind::package;
-
-      // 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 ) ) return ResKind::K
-          //             ----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
-        }
-      }
+       return ResKind::package;
 
-      // an unknown kind
+      // ...or something unknown.
       return ResKind( std::string( ident, sep-ident ) );
     }
 
@@ -230,9 +300,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)
@@ -283,28 +356,91 @@ namespace zypp
       return IdString( _solvable->vendor );
     }
 
-    Capabilities Solvable::operator[]( Dep which_r ) const
+   Repository Solvable::repository() const
     {
-      switch( which_r.inSwitch() )
-      {
-        case Dep::PROVIDES_e:    return provides();    break;
-        case Dep::REQUIRES_e:    return requires();    break;
-        case Dep::CONFLICTS_e:   return conflicts();   break;
-        case Dep::OBSOLETES_e:   return obsoletes();   break;
-        case Dep::RECOMMENDS_e:  return recommends();  break;
-        case Dep::SUGGESTS_e:    return suggests();    break;
-        case Dep::FRESHENS_e:    return freshens();    break;
-        case Dep::ENHANCES_e:    return enhances();    break;
-        case Dep::SUPPLEMENTS_e: return supplements(); break;
-        case Dep::PREREQUIRES_e: return prerequires(); break;
-      }
-      return Capabilities();
+      NO_SOLVABLE_RETURN( Repository::noRepository );
+      return Repository( _solvable->repo );
+    }
+
+    RepoInfo Solvable::repoInfo() const
+    { return repository().info(); }
+
+
+    bool Solvable::isSystem() const
+    {
+      NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
+      return myPool().isSystemRepo( _solvable->repo );
+    }
+
+    bool Solvable::onSystemByUser() const
+    {
+      return isSystem() && myPool().isOnSystemByUser( ident() );
+    }
+
+    bool Solvable::onSystemByAuto() const
+    {
+      return isSystem() && myPool().isOnSystemByAuto( ident() );
+    }
+
+    bool Solvable::identIsAutoInstalled( const IdString & ident_r )
+    {
+      return myPool().isOnSystemByAuto( ident_r );
+    }
+
+    bool Solvable::multiversionInstall() const
+    {
+      NO_SOLVABLE_RETURN( false );
+      return myPool().isMultiversion( *this );
+    }
+
+    Date Solvable::buildtime() const
+    {
+      NO_SOLVABLE_RETURN( Date() );
+      return Date( lookupNumAttribute( SolvAttr::buildtime ) );
+    }
+
+    Date Solvable::installtime() const
+    {
+      NO_SOLVABLE_RETURN( Date() );
+      return Date( lookupNumAttribute( SolvAttr::installtime ) );
+    }
+
+    std::string Solvable::asString() const
+    {
+      NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
+      return str::form( "%s-%s.%s",
+                        IdString( _solvable->name ).c_str(),
+                        IdString( _solvable->evr ).c_str(),
+                        IdString( _solvable->arch ).c_str() );
     }
 
-    inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
+    std::string Solvable::asUserString() const\
     {
-      return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
+      NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
+      return str::form( "%s-%s.%s (%s)",
+                        IdString( _solvable->name ).c_str(),
+                        IdString( _solvable->evr ).c_str(),
+                        IdString( _solvable->arch ).c_str(),
+                        repository().asUserString().c_str() );
     }
+
+    bool Solvable::identical( const Solvable & rhs ) const
+    {
+      NO_SOLVABLE_RETURN( ! rhs.get() );
+      detail::CSolvable * rhssolvable( rhs.get() );
+      return rhssolvable && ( _solvable == rhssolvable || ::solvable_identical( _solvable, rhssolvable ) );
+    }
+
+    ///////////////////////////////////////////////////////////////////
+    namespace
+    {
+      inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
+      {
+       return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
+      }
+    } // namespace
+    ///////////////////////////////////////////////////////////////////
+
     Capabilities Solvable::provides() const
     {
       NO_SOLVABLE_RETURN( Capabilities() );
@@ -335,11 +471,6 @@ namespace zypp
       NO_SOLVABLE_RETURN( Capabilities() );
       return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
     }
-    Capabilities Solvable::freshens() const
-    {
-      NO_SOLVABLE_RETURN( Capabilities() );
-      return _getCapabilities( _solvable->repo->idarraydata, _solvable->freshens );
-    }
     Capabilities Solvable::enhances() const
     {
       NO_SOLVABLE_RETURN( Capabilities() );
@@ -359,10 +490,42 @@ namespace zypp
                    : Capabilities();
     }
 
+    CapabilitySet Solvable::providesNamespace( const std::string & namespace_r ) const
+    {
+      NO_SOLVABLE_RETURN( CapabilitySet() );
+      CapabilitySet ret;
+      Capabilities caps( provides() );
+      for_( it, caps.begin(), caps.end() )
+      {
+        CapDetail caprep( it->detail() );
+        if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
+          ret.insert( *it );
+      }
+      return ret;
+    }
+
+    CapabilitySet Solvable::valuesOfNamespace( const std::string & namespace_r ) const
+    {
+      NO_SOLVABLE_RETURN( CapabilitySet() );
+      CapabilitySet ret;
+      Capabilities caps( provides() );
+      for_( it, caps.begin(), caps.end() )
+      {
+        CapDetail caprep( it->detail() );
+        if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
+        {
+          std::string value( caprep.name().c_str()+namespace_r.size()+1 );
+          value[value.size()-1] = '\0'; // erase the trailing ')'
+          ret.insert( Capability( value, caprep.op(), caprep.ed() ) );
+        }
+      }
+      return ret;
+    }
+
     ///////////////////////////////////////////////////////////////////
     namespace
-    { /////////////////////////////////////////////////////////////////
-      /** Expand \ref Capability and call \c fnc_r for each namescpace:language
+    {
+      /** Expand \ref Capability and call \c fnc_r for each namespace:language
        * dependency. Return #invocations of fnc_r, negative if fnc_r returned
        * false to indicate abort.
        */
@@ -376,16 +539,16 @@ namespace zypp
             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;
+              {
+                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 )
@@ -396,17 +559,18 @@ namespace zypp
 
             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
+       /** Expand \ref Capability and call \c fnc_r for each namespace: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 )
+      inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (Locale)> fnc_r )
       {
         int cnt = 0;
         for_( cit, cap_r.begin(), cap_r.end() )
@@ -432,8 +596,8 @@ namespace zypp
 
         const LocaleSet & _locales;
       };
-
-    /////////////////////////////////////////////////////////////////
+    } // namespace
+    ///////////////////////////////////////////////////////////////////
 
     bool Solvable::supportsLocales() const
     {
@@ -458,33 +622,111 @@ namespace zypp
     bool Solvable::supportsRequestedLocales() const
     { return supportsLocale( myPool().getRequestedLocales() ); }
 
-    void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
+    LocaleSet Solvable::getSupportedLocales() const
+    {
+      LocaleSet ret;
+      invokeOnEachSupportedLocale( supplements(), functor::collector( std::inserter( ret, ret.begin() ) ) );
+      return ret;
+    }
+
+    CpeId Solvable::cpeId() const
+    {
+      NO_SOLVABLE_RETURN( CpeId() );
+      return CpeId( lookupStrAttribute( SolvAttr::cpeid ), CpeId::noThrow );
+    }
+
+    unsigned Solvable::mediaNr() const
+    {
+      NO_SOLVABLE_RETURN( 0U );
+      return lookupNumAttribute( SolvAttr::medianr );
+    }
+
+    ByteCount Solvable::installSize() const
+    {
+      NO_SOLVABLE_RETURN( ByteCount() );
+      return ByteCount( lookupNumAttribute( SolvAttr::installsize ) );
+    }
+
+    ByteCount Solvable::downloadSize() const
+    {
+      NO_SOLVABLE_RETURN( ByteCount() );
+      return ByteCount( lookupNumAttribute( SolvAttr::downloadsize ) );
+    }
+
+    std::string Solvable::distribution() const
+    {
+      NO_SOLVABLE_RETURN( std::string() );
+      return lookupStrAttribute( SolvAttr::distribution );
+    }
+
+    std::string        Solvable::summary( const Locale & lang_r ) const
+    {
+      NO_SOLVABLE_RETURN( std::string() );
+      return lookupStrAttribute( SolvAttr::summary, lang_r );
+    }
+
+    std::string        Solvable::description( const Locale & lang_r ) const
+    {
+      NO_SOLVABLE_RETURN( std::string() );
+      return lookupStrAttribute( SolvAttr::description, lang_r );
+    }
+
+    std::string        Solvable::insnotify( const Locale & lang_r ) const
+    {
+      NO_SOLVABLE_RETURN( std::string() );
+      return lookupStrAttribute( SolvAttr::insnotify, lang_r );
+    }
+
+    std::string        Solvable::delnotify( const Locale & lang_r ) const
+    {
+      NO_SOLVABLE_RETURN( std::string() );
+      return lookupStrAttribute( SolvAttr::delnotify, lang_r );
+    }
+
+    std::string        Solvable::licenseToConfirm( const Locale & lang_r ) const
+    {
+      NO_SOLVABLE_RETURN( std::string() );
+      std::string ret = lookupStrAttribute( SolvAttr::eula, lang_r );
+      if ( ret.empty() && isKind<Product>() )
+      {
+       const RepoInfo & ri( repoInfo() );
+       std::string riname( name() );   // "license-"+name with fallback "license"
+       if ( ! ri.hasLicense( riname ) )
+         riname.clear();
+
+       if ( ri.needToAcceptLicense( riname ) || ! ui::Selectable::get( *this )->hasInstalledObj() )
+         ret = ri.getLicense( riname, lang_r ); // bnc#908976: suppress informal license upon update
+      }
+      return ret;
+    }
+
+    bool Solvable::needToAcceptLicense() const
     {
-      invokeOnEachSupportedLocale( supplements(),
-                                   functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
+      NO_SOLVABLE_RETURN( false );
+      if ( isKind<Product>() )
+      {
+       const RepoInfo & ri( repoInfo() );
+       std::string riname( name() );   // "license-"+name with fallback "license"
+       if ( ! ri.hasLicense( riname ) )
+         riname.clear();
+
+       return ri.needToAcceptLicense( riname );
+      }
+      return true;
     }
 
-    /******************************************************************
-    **
-    ** FUNCTION NAME : operator<<
-    ** FUNCTION TYPE : std::ostream &
-    */
+
     std::ostream & operator<<( std::ostream & str, const Solvable & obj )
     {
       if ( ! obj )
-        return str << "sat::solvable()";
+        return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
 
       return str << "(" << obj.id() << ")"
           << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
           << '-' << obj.edition() << '.' << obj.arch() << "("
-          << obj.repository().name() << ")";
+          << obj.repository().alias() << ")";
     }
 
-    /******************************************************************
-    **
-    ** FUNCTION NAME : dumpOn
-    ** FUNCTION TYPE : std::ostream &
-    */
     std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
     {
       str << obj;
@@ -498,7 +740,6 @@ namespace zypp
         OUTS(OBSOLETES);
         OUTS(RECOMMENDS);
         OUTS(SUGGESTS);
-        OUTS(FRESHENS);
         OUTS(ENHANCES);
         OUTS(SUPPLEMENTS);
 #undef OUTS
@@ -506,9 +747,19 @@ namespace zypp
       return str;
     }
 
-    /////////////////////////////////////////////////////////////////
+    std::ostream & dumpAsXmlOn( std::ostream & str, const Solvable & obj )
+    {
+      xmlout::Node guard( str, "solvable" );
+
+      dumpAsXmlOn( *guard, obj.kind() );
+      *xmlout::Node( *guard, "name" ) << obj.name();
+      dumpAsXmlOn( *guard, obj.edition() );
+      dumpAsXmlOn( *guard, obj.arch() );
+      dumpAsXmlOn( *guard, obj.repository() );
+      return str;
+    }
+
   } // namespace sat
   ///////////////////////////////////////////////////////////////////
-  /////////////////////////////////////////////////////////////////
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////