Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / Pattern.cc
index 9d748a8..fb0049f 100644 (file)
@@ -20,11 +20,19 @@ using std::endl;
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
-{ /////////////////////////////////////////////////////////////////
-
+{
   ///////////////////////////////////////////////////////////////////
   namespace
-  { /////////////////////////////////////////////////////////////////
+  {
+    inline Capability autoCapability( const Capabilities & provides_r )
+    {
+      static const Capability autopattern( "autopattern()" );
+      for ( const auto & cap : provides_r )
+       if ( cap.matches( autopattern ) == CapMatch::yes )
+         return cap;
+      return Capability();
+    }
+
     ///////////////////////////////////////////////////////////////////
     //
     // CLASS NAME : PatternExpander
@@ -153,78 +161,118 @@ namespace zypp
       private:
         PatternMap _patternMap;
     };
-    /////////////////////////////////////////////////////////////////
   } // namespace
   ///////////////////////////////////////////////////////////////////
-  IMPL_PTR_TYPE(Pattern);
 
   ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Pattern::Pattern
-  //   METHOD TYPE : Ctor
-  //
+  //   Pattern
+  ///////////////////////////////////////////////////////////////////
+
+  IMPL_PTR_TYPE(Pattern);
+
   Pattern::Pattern( const sat::Solvable & solvable_r )
   : ResObject( solvable_r )
   {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Pattern::~Pattern
-  //   METHOD TYPE : Dtor
-  //
   Pattern::~Pattern()
   {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   Pattern interface forwarded to implementation
-  //
-  ///////////////////////////////////////////////////////////////////
-  /** */
   bool Pattern::isDefault() const
   { return lookupBoolAttribute( sat::SolvAttr::isdefault ); }
-  /** */
+
   bool Pattern::userVisible() const
-  { return lookupBoolAttribute( sat::SolvAttr::isvisible ); }
-  /** */
+  {
+    // bsc#900769: If visibility is a string(solvable ident) the pattern
+    // is visible IFF ident is available in the pool.
+    IdString ident( lookupStrAttribute( sat::SolvAttr::isvisible ) );
+    return( ident.empty() ? lookupBoolAttribute( sat::SolvAttr::isvisible )
+                         : ! ResPool::instance().byIdent( ident ).empty() );
+  }
+
   std::string Pattern::category( const Locale & lang_r ) const
   { return lookupStrAttribute( sat::SolvAttr::category, lang_r ); }
-  /** */
+
   Pathname Pattern::icon() const
   { return lookupStrAttribute( sat::SolvAttr::icon ); }
-  /** */
+
   Pathname Pattern::script() const
   { return lookupStrAttribute( sat::SolvAttr::script ); }
 
   std::string Pattern::order() const
   { return lookupStrAttribute( sat::SolvAttr::order ); }
 
+  bool Pattern::isAutoPattern() const
+  { return bool(autoCapability( provides() )); }
+
+  sat::Solvable Pattern::autoPackage() const
+  {
+    Capability autocap( autoCapability( provides() ) );
+    if ( autocap )
+    {
+      Capability pkgCap( arch(), autocap.detail().ed().asString(), Rel::EQ, edition() );
+      for ( const auto & solv: sat::WhatProvides( pkgCap ) )
+       if ( solv.repository() == repository() )
+         return solv;
+    }
+    return sat::Solvable();
+  }
+
   Pattern::NameList Pattern::includes() const
   { return NameList( sat::SolvAttr::includes, satSolvable() ); }
 
   Pattern::NameList Pattern::extends() const
   { return NameList( sat::SolvAttr::extends, satSolvable() ); }
 
+  ///////////////////////////////////////////////////////////////////
+  namespace
+  {
+    inline void addCaps( CapabilitySet & caps_r, sat::Solvable solv_r, Dep dep_r )
+    {
+      Capabilities c( solv_r[dep_r] );
+      if ( ! c.empty() )
+      {
+       caps_r.insert( c.begin(),c.end() );
+      }
+    }
+  } //namespace
+  ///////////////////////////////////////////////////////////////////
+
   Pattern::Contents Pattern::core() const
   {
+    // Content dependencies are either associated with
+    // the autoPackage or the (oldstype) pattern itself.
+    // load requires
+    CapabilitySet caps;
+    addCaps( caps, *this, Dep::REQUIRES );
+
+    sat::Solvable depKeeper( autoPackage() );
+    if ( depKeeper )
+      addCaps( caps, depKeeper, Dep::REQUIRES );
     // get items providing the requirements
-    sat::WhatProvides prv( requires() );
+    sat::WhatProvides prv( caps );
     // return packages only.
     return Pattern::Contents( make_filter_begin( filter::byKind<Package>(), prv ),
                               make_filter_end( filter::byKind<Package>(), prv ) );
   }
 
-  Pattern::Contents Pattern::depends() const
+  Pattern::Contents Pattern::depends( bool includeSuggests_r ) const
   {
-    // load requires, recommends, suggests
+    // Content dependencies are either associated with
+    // the autoPackage or the (oldstype) pattern itself.
+    // load requires, recommends[, suggests]
     CapabilitySet caps;
+    addCaps( caps, *this, Dep::REQUIRES );
+    addCaps( caps, *this, Dep::RECOMMENDS );
+    if ( includeSuggests_r )
+      addCaps( caps, *this, Dep::SUGGESTS );
+
+    sat::Solvable depKeeper( autoPackage() );
+    if ( depKeeper )
     {
-      Capabilities c( requires() );
-      caps.insert( c.begin(),c.end() );
-      c = recommends();
-      caps.insert( c.begin(),c.end() );
-      c = suggests();
-      caps.insert( c.begin(),c.end() );
+      addCaps( caps, depKeeper, Dep::REQUIRES );
+      addCaps( caps, depKeeper, Dep::RECOMMENDS );
+      if ( includeSuggests_r )
+       addCaps( caps, depKeeper, Dep::SUGGESTS );
     }
     // get items providing the above
     sat::WhatProvides prv( caps );
@@ -233,7 +281,7 @@ namespace zypp
                               make_filter_end( filter::byKind<Package>(), prv ) );
   }
 
-  Pattern::Contents Pattern::contents() const
+  Pattern::Contents Pattern::contents( bool includeSuggests_r ) const
   {
     PatternExpander expander;
     if ( ! expander.doExpand( this ) )
@@ -242,12 +290,123 @@ namespace zypp
     Contents result;
     for_( it, expander.begin(), expander.end() )
     {
-      Contents c( (*it)->depends() );
+      Contents c( (*it)->depends( includeSuggests_r ) );
       result.get().insert( c.begin(), c.end() );
     }
     return result;
   }
 
+  ///////////////////////////////////////////////////////////////////
+  namespace
+  {
+    // Get packages referenced by depKeeper dependency.
+    inline void dependsSetDoCollect( sat::Solvable depKeeper_r, Dep dep_r, Pattern::Contents & set_r )
+    {
+      CapabilitySet caps;
+      addCaps( caps, depKeeper_r, dep_r );
+      sat::WhatProvides prv( caps );
+      for ( ui::Selectable::Ptr sel : prv.selectable() )
+      {
+       const PoolItem & pi( sel->theObj() );
+       if ( pi.isKind<Package>() )
+         set_r.insert( pi );
+      }
+    }
+
+    // Get packages referenced by depKeeper.
+    inline void dependsSet( sat::Solvable depKeeper_r, Pattern::ContentsSet & collect_r )
+    {
+      dependsSetDoCollect( depKeeper_r, Dep::REQUIRES,  collect_r.req );
+      dependsSetDoCollect( depKeeper_r, Dep::RECOMMENDS, collect_r.rec ),
+      dependsSetDoCollect( depKeeper_r, Dep::SUGGESTS,  collect_r.sug );
+    }
+
+    // Whether this is a patterns depkeeper.
+    inline bool isPatternsPackage( sat::Solvable depKeeper_r )
+    {
+      static const Capability indicator( "pattern()" );
+      return depKeeper_r.provides().matches( indicator );
+    }
+  } // namespace
+  ///////////////////////////////////////////////////////////////////
+  void Pattern::contentsSet( ContentsSet & collect_r, bool recursively_r ) const
+  {
+    sat::Solvable depKeeper( autoPackage() );  // (my required) patterns-package
+    if ( ! depKeeper )
+      return;
+
+    // step 2 data
+    std::set<sat::Solvable> recTodo;   // recommended patterns-packages to process
+    std::set<sat::Solvable> allDone;   // patterns-packages already expanded
+    {
+      // step 1: Expand requirements, remember recommends....
+      // step 1 data (scoped to step1)
+      std::set<sat::Solvable> reqTodo; // required patterns-packages to process
+
+      collect_r.req.insert( depKeeper );// collect the depKeeper
+      reqTodo.insert( depKeeper );     // and expand it...
+
+      while ( ! reqTodo.empty() )
+      {
+       // pop one patterns-package from todo
+       depKeeper = ( *reqTodo.begin() );
+       reqTodo.erase( reqTodo.begin() );
+       allDone.insert( depKeeper );
+
+       // collects stats
+       ContentsSet result;
+       dependsSet( depKeeper, result );
+
+       // evaluate result....
+       for ( sat::Solvable solv : result.req ) // remember unprocessed required patterns-packages...
+       {
+         if ( collect_r.req.insert( solv ) && recursively_r && isPatternsPackage( solv ) )
+           reqTodo.insert( solv );
+       }
+       for ( sat::Solvable solv : result.rec ) // remember unprocessed recommended patterns-packages...
+       {
+         if ( collect_r.rec.insert( solv ) && recursively_r && isPatternsPackage( solv ) )
+           recTodo.insert( solv );
+       }
+       for ( sat::Solvable solv : result.sug ) // NOTE: We don't expand suggested patterns!
+       {
+         collect_r.sug.insert( solv );
+       }
+      }
+    }
+    // step 2: All requirements are expanded, now check remaining recommends....
+    while ( ! recTodo.empty() )
+    {
+      // pop one patterns-package from todo
+      depKeeper = ( *recTodo.begin() );
+      recTodo.erase( recTodo.begin() );
+      if ( ! allDone.insert( depKeeper ).second )
+       continue;       // allready expanded (in requires)
+
+      // collects stats
+      ContentsSet result;
+      dependsSet( depKeeper, result );
+
+      // evaluate result....
+      for ( sat::Solvable solv : result.req )  // remember unprocessed required patterns-packages...
+      {
+       // NOTE: Requirements of recommended patterns count as 'recommended'
+       if ( collect_r.rec.insert( solv ) && recursively_r && isPatternsPackage( solv ) )
+         recTodo.insert( solv );
+      }
+      for ( sat::Solvable solv : result.rec )  // remember unprocessed recommended patterns-packages...
+      {
+       if ( collect_r.rec.insert( solv ) && recursively_r && isPatternsPackage( solv ) )
+         recTodo.insert( solv );
+      }
+       for ( sat::Solvable solv : result.sug ) // NOTE: We don't expand suggested patterns!
+       {
+         collect_r.sug.insert( solv );
+       }
+    }
+  }
+
+
   /////////////////////////////////////////////////////////////////
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////