Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / PoolQuery.cc
index 628020f..5fe838e 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "zypp/sat/Pool.h"
 #include "zypp/sat/Solvable.h"
-#include "zypp/sat/AttrMatcher.h"
+#include "zypp/base/StrMatcher.h"
 
 #include "zypp/PoolQuery.h"
 
@@ -61,7 +61,7 @@ namespace zypp
       return false;
     }
 
-    /** Whether the current capabilities edition range ovelaps.
+    /** Whether the current capabilities edition range ovelaps and/or its solvables arch matches.
      * Query asserts \a iter_r points to a capability and we
      * have to check the range only.
      */
@@ -69,10 +69,18 @@ namespace zypp
     {
       EditionRangePredicate( const Rel & op, const Edition & edition )
         : _range( op, edition )
+        , _arch( Arch_empty )
+      {}
+      EditionRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
+        : _range( op, edition )
+        , _arch( arch )
       {}
 
       bool operator()( sat::LookupAttr::iterator iter_r )
       {
+       if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
+         return false;
+
         CapDetail cap( iter_r.id() );
         if ( ! cap.isSimple() )
           return false;
@@ -86,22 +94,32 @@ namespace zypp
         std::string ret( "EditionRange" );
         str::appendEscaped( ret, _range.op.asString() );
         str::appendEscaped( ret, _range.value.asString() );
+        str::appendEscaped( ret, _arch.asString() );
         return ret;
       }
 
       Edition::MatchRange _range;
-    };
+      Arch                _arch;
+   };
 
-    /** Whether the current Solvables edition is within a given range. */
+    /** Whether the current Solvables edition is within a given range and/or its arch matches. */
     struct SolvableRangePredicate
     {
       SolvableRangePredicate( const Rel & op, const Edition & edition )
         : _range( op, edition )
+        , _arch( Arch_empty )
+      {}
+
+      SolvableRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
+        : _range( op, edition )
+        , _arch( arch )
       {}
 
       bool operator()( sat::LookupAttr::iterator iter_r )
       {
-        return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
+       if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
+         return false;
+       return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
       }
 
       std::string serialize() const
@@ -109,10 +127,12 @@ namespace zypp
         std::string ret( "SolvableRange" );
         str::appendEscaped( ret, _range.op.asString() );
         str::appendEscaped( ret, _range.value.asString() );
+        str::appendEscaped( ret, _arch.asString() );
         return ret;
       }
 
       Edition::MatchRange _range;
+      Arch                _arch;
     };
 
     /** Whether the current capability matches a given one.
@@ -145,13 +165,13 @@ namespace zypp
     /////////////////////////////////////////////////////////////////
     /** Match data per attribtue.
      *
-     * This includes the attribute itself, an optional \ref sat::AttrMatcher
+     * This includes the attribute itself, an optional \ref StrMatcher
      * to restrict the query to certain string values, and an optional
      * boolean \ref Predicate that may apply further restrictions that can
-     * not be expressed by the \ref attrMatcher.
+     * not be expressed by the \ref strMatcher.
      *
      * Example for such a \ref predicate would be an additional edition range
-     * check whan looking for dependencies. The \ref attrMatcher would
+     * check whan looking for dependencies. The \ref strMatcher would
      * find potential matches by looking at the dependencies name, the
      * predicate will then check the edition ranges.
      *
@@ -171,15 +191,15 @@ namespace zypp
       AttrMatchData()
       {}
 
-      AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r )
+      AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r )
         : attr( attr_r )
-        , attrMatcher( attrMatcher_r )
+        , strMatcher( strMatcher_r )
       {}
 
-      AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r,
+      AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r,
                      const Predicate & predicate_r, const std::string & predicateStr_r )
         : attr( attr_r )
-        , attrMatcher( attrMatcher_r )
+        , strMatcher( strMatcher_r )
         , predicate( predicate_r )
         , predicateStr( predicateStr_r )
       {}
@@ -189,8 +209,8 @@ namespace zypp
        * string representation instead. If you add new predicated, check the
        * deserialization code in \ref deserialize.
        */
-      template<class _Predicate>
-      void addPredicate( const _Predicate & predicate_r )
+      template<class TPredicate>
+      void addPredicate( const TPredicate & predicate_r )
       {
         predicate    = predicate_r;
         predicateStr = predicate_r.serialize();
@@ -205,11 +225,11 @@ namespace zypp
       {
         std::string ret( "AttrMatchData" );
         str::appendEscaped( ret, attr.asString() );
-        str::appendEscaped( ret, attrMatcher.searchstring() );
+        str::appendEscaped( ret, strMatcher.searchstring() );
         // TODO: Actually the flag should be serialized too, but for PoolQuery
         // it's by now sufficient to differ between mode OTHER and others,
         // i.e. whether to compile or not compile.
-        str::appendEscaped( ret, attrMatcher.flags().mode() == Match::OTHER ? "C" : "X" );
+        str::appendEscaped( ret, strMatcher.flags().mode() == Match::OTHER ? "C" : "X" );
         str::appendEscaped( ret, predicateStr );
         return ret;
       }
@@ -228,9 +248,9 @@ namespace zypp
 
         AttrMatchData ret;
         ret.attr = sat::SolvAttr( words[1] );
-        ret.attrMatcher = sat::AttrMatcher( words[2] );
+        ret.strMatcher = StrMatcher( words[2] );
         if ( words[3] == "C" )
-          ret.attrMatcher.setFlags( Match::OTHER );
+          ret.strMatcher.setFlags( Match::OTHER );
         ret.predicateStr = words[4];
 
         // now the predicate
@@ -240,15 +260,33 @@ namespace zypp
         {
           if ( words[0] == "EditionRange" )
           {
-            if ( words.size() != 3 )
-              ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
-            ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
+           switch( words.size() )
+           {
+             case 3:
+               ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
+               break;
+             case 4:
+               ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
+               break;
+             default:
+               ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
+               break;
+           }
           }
           else if ( words[0] == "SolvableRange" )
           {
-            if ( words.size() != 3 )
-              ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
-            ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
+           switch( words.size() )
+           {
+             case 3:
+               ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
+               break;
+             case 4:
+               ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
+               break;
+             default:
+               ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
+               break;
+           }
           }
           else if ( words[0] == "CapabilityMatch" )
           {
@@ -263,7 +301,7 @@ namespace zypp
      }
 
       sat::SolvAttr    attr;
-      sat::AttrMatcher attrMatcher;
+      StrMatcher strMatcher;
       Predicate        predicate;
       std::string      predicateStr;
     };
@@ -271,7 +309,7 @@ namespace zypp
     /** \relates AttrMatchData */
     inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
     {
-      str << obj.attr << ": " << obj.attrMatcher;
+      str << obj.attr << ": " << obj.strMatcher;
       if ( obj.predicate )
         str << " +(" << obj.predicateStr << ")";
       return str;
@@ -281,7 +319,7 @@ namespace zypp
     inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs )
     {
       return ( lhs.attr == rhs.attr
-               && lhs.attrMatcher == rhs.attrMatcher
+               && lhs.strMatcher == rhs.strMatcher
                && lhs.predicateStr == rhs.predicateStr );
     }
 
@@ -294,8 +332,8 @@ namespace zypp
     {
       if ( lhs.attr != rhs.attr )
         return (  lhs.attr < rhs.attr );
-      if ( lhs.attrMatcher != rhs.attrMatcher )
-        return (  lhs.attrMatcher < rhs.attrMatcher );
+      if ( lhs.strMatcher != rhs.strMatcher )
+        return (  lhs.strMatcher < rhs.strMatcher );
       if ( lhs.predicateStr != rhs.predicateStr )
         return (  lhs.predicateStr < rhs.predicateStr );
       return false;
@@ -363,17 +401,30 @@ namespace zypp
 
     bool operator==( const PoolQuery::Impl & rhs ) const
     {
-      return ( _strings == rhs._strings
-               && _attrs == rhs._attrs
-               && _uncompiledPredicated == rhs._uncompiledPredicated
-               && _flags == rhs._flags
-               && _match_word == rhs._match_word
-               && _require_all == rhs._require_all
-               && _status_flags == rhs._status_flags
-               && _edition == rhs._edition
-               && _op == rhs._op
-               && _repos == rhs._repos
-               && _kinds == rhs._kinds );
+      if ( _flags == rhs._flags
+       // bnc#792901: while libzypp uses exact match mode for a single
+       // package name lock, zypper always uses glob. :(
+       // We unify those two forms to enable zypper to remove zypp locks
+       // without need to actually evaluate the query (which would require
+       // repos to be loaded).
+       || ( ( ( _flags.isModeString() && rhs._flags.isModeGlob() )
+           || ( _flags.isModeGlob() && rhs._flags.isModeString() ) )
+         && _strings.empty()
+         && _attrs.size() == 1
+         && _attrs.begin()->first == sat::SolvAttr::name ) )
+      {
+       return ( _strings == rhs._strings
+             && _attrs == rhs._attrs
+             && _uncompiledPredicated == rhs._uncompiledPredicated
+             && _match_word == rhs._match_word
+             && _require_all == rhs._require_all
+             && _status_flags == rhs._status_flags
+             && _edition == rhs._edition
+             && _op == rhs._op
+             && _repos == rhs._repos
+             && _kinds == rhs._kinds );
+      }
+      return false;
     }
 
     bool operator!=( const PoolQuery::Impl & rhs ) const
@@ -382,11 +433,11 @@ namespace zypp
   public:
     /** Compile the regex.
      * Basically building the \ref _attrMatchList from strings.
-     * \throws MatchException Any of the exceptions thrown by \ref AttrMatcher::compile.
+     * \throws MatchException Any of the exceptions thrown by \ref StrMatcher::compile.
      */
     void compile() const;
 
-    /** AttrMatcher per attribtue. */
+    /** StrMatcher per attribtue. */
     mutable AttrMatchList _attrMatchList;
 
   private:
@@ -463,7 +514,7 @@ namespace zypp
       if (joined.size() > 1) // switch to regex for multiple strings
         cflags.setModeRegex();
       _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
-                                sat::AttrMatcher( rcstrings, cflags ) ) );
+                                StrMatcher( rcstrings, cflags ) ) );
     }
 
     // // MULTIPLE ATTRIBUTES
@@ -521,8 +572,8 @@ attremptycheckend:
         }
         if (joined.size() > 1) // switch to regex for multiple strings
           cflags.setModeRegex();
-        // May use the same AttrMatcher for all
-        sat::AttrMatcher matcher( rcstrings, cflags );
+        // May use the same StrMatcher for all
+        StrMatcher matcher( rcstrings, cflags );
         for_( ai, _attrs.begin(), _attrs.end() )
         {
           _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
@@ -544,7 +595,7 @@ attremptycheckend:
           if (joined.size() > 1) // switch to regex for multiple strings
             cflags.setModeRegex();
           _attrMatchList.push_back( AttrMatchData( ai->first,
-                                    sat::AttrMatcher( s, cflags ) ) );
+                                    StrMatcher( s, cflags ) ) );
         }
       }
     }
@@ -556,11 +607,11 @@ attremptycheckend:
       invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
       for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
       {
-        if ( it->attrMatcher.flags().mode() == Match::OTHER )
+        if ( it->strMatcher.flags().mode() == Match::OTHER )
         {
           // need to compile:
           StrContainer joined( global );
-          const std::string & mstr( it->attrMatcher.searchstring() );
+          const std::string & mstr( it->strMatcher.searchstring() );
           if ( ! mstr.empty() )
             joined.insert( mstr );
 
@@ -570,7 +621,7 @@ attremptycheckend:
             cflags.setModeRegex();
 
           _attrMatchList.push_back( AttrMatchData( it->attr,
-                                    sat::AttrMatcher( rcstrings, cflags ),
+                                    StrMatcher( rcstrings, cflags ),
                                                       it->predicate, it->predicateStr ) );
         }
         else
@@ -589,13 +640,13 @@ attremptycheckend:
       if ( _strings.size() > 1 ) // switch to regex for multiple strings
         cflags.setModeRegex();
       _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
-                                sat::AttrMatcher( rcstrings, cflags ) ) );
+                                StrMatcher( rcstrings, cflags ) ) );
     }
 
     // Finally check here, whether all involved regex compile.
     for_( it, _attrMatchList.begin(), _attrMatchList.end() )
     {
-      it->attrMatcher.compile(); // throws on error
+      it->strMatcher.compile(); // throws on error
     }
     //DBG << asString() << endl;
   }
@@ -804,12 +855,19 @@ attremptycheckend:
   { _pimpl->_attrs[attr].insert(value); }
 
   void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
+  { return addDependency( attr, name, op, edition, Arch_empty ); }
+
+  void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
   {
     switch ( op.inSwitch() )
     {
       case Rel::ANY_e: // no additional constraint on edition.
-        addAttribute( attr, name );
-        return;
+        if ( arch.empty() )    // no additional constraint on arch.
+       {
+         addAttribute( attr, name );
+         return;
+       }
+       break;
 
       case Rel::NONE_e:        // will never match.
         return;
@@ -820,12 +878,12 @@ attremptycheckend:
 
     // Match::OTHER indicates need to compile
     // (merge global search strings into name).
-    AttrMatchData attrMatchData( attr, sat::AttrMatcher( name, Match::OTHER ) );
+    AttrMatchData attrMatchData( attr, StrMatcher( name, Match::OTHER ) );
 
     if ( isDependencyAttribute( attr ) )
-      attrMatchData.addPredicate( EditionRangePredicate( op, edition ) );
+      attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
     else
-      attrMatchData.addPredicate( SolvableRangePredicate( op, edition ) );
+      attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) );
 
     _pimpl->_uncompiledPredicated.insert( attrMatchData );
   }
@@ -837,7 +895,7 @@ attremptycheckend:
       return;
 
     // Matches STRING per default. (won't get compiled!)
-    AttrMatchData attrMatchData( attr, sat::AttrMatcher( cap.name().asString() ) );
+    AttrMatchData attrMatchData( attr, StrMatcher( cap.name().asString() ) );
 
     if ( isDependencyAttribute( attr ) )
       attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
@@ -1082,8 +1140,6 @@ attremptycheckend:
 
       PoolQueryAttr attribute( attrName );
 
-      MIL << "attribute name: " << attrName << endl;
-
       if ( attribute==PoolQueryAttr::repoAttr )
       {
         addRepo( attrValue );
@@ -1442,8 +1498,8 @@ attremptycheckend:
             {
               const AttrMatchData & matchData( *mi );
               sat::LookupAttr q( matchData.attr, inSolvable );
-              if ( matchData.attrMatcher ) // an empty searchstring matches always
-                q.setAttrMatcher( matchData.attrMatcher );
+              if ( matchData.strMatcher ) // an empty searchstring matches always
+                q.setStrMatcher( matchData.strMatcher );
 
               if ( ! q.empty() ) // there are matches.
               {
@@ -1469,12 +1525,20 @@ attremptycheckend:
 
          // Repo restriction:
          sat::Pool satpool( sat::Pool::instance() );
+
          for_( it, query_r->_repos.begin(), query_r->_repos.end() )
          {
            Repository r( satpool.reposFind( *it ) );
            if ( r )
              _repos.insert( r );
+           else
+             _neverMatchRepo = true;
          }
+         // _neverMatchRepo: we just need to catch the case that no repo
+         // matched, so we'd interpret the empty list as 'take from all'
+         if ( _neverMatchRepo && ! _repos.empty() )
+           _neverMatchRepo = false;
+
          // Kind restriction:
          _kinds = query_r->_kinds;
          // Edition restriction:
@@ -1482,7 +1546,7 @@ attremptycheckend:
          _edition = query_r->_edition;
          // Status restriction:
          _status_flags = query_r->_status_flags;
-          // AttrMatcher
+          // StrMatcher
           _attrMatchList = query_r->_attrMatchList;
        }
 
@@ -1495,6 +1559,9 @@ attremptycheckend:
        {
          sat::LookupAttr q;
 
+         if ( _neverMatchRepo )
+           return q.end();
+
          // Repo restriction:
          if ( _repos.size() == 1 )
            q.setRepo( *_repos.begin() );
@@ -1505,8 +1572,8 @@ attremptycheckend:
          {
             const AttrMatchData & matchData( _attrMatchList.front() );
            q.setAttr( matchData.attr );
-            if ( matchData.attrMatcher ) // empty searchstring matches always
-              q.setAttrMatcher( matchData.attrMatcher );
+            if ( matchData.strMatcher ) // empty searchstring matches always
+              q.setStrMatcher( matchData.strMatcher );
          }
           else // more than 1 attr (but not all)
           {
@@ -1579,8 +1646,8 @@ attremptycheckend:
           {
             const AttrMatchData & matchData( *mi );
             sat::LookupAttr q( matchData.attr, inSolvable );
-            if ( matchData.attrMatcher ) // an empty searchstring matches always
-              q.setAttrMatcher( matchData.attrMatcher );
+            if ( matchData.strMatcher ) // an empty searchstring matches always
+              q.setStrMatcher( matchData.strMatcher );
 
             if ( ! q.empty() ) // there are matches.
             {
@@ -1605,6 +1672,7 @@ attremptycheckend:
       private:
         /** Repositories include in the search. */
         std::set<Repository> _repos;
+       DefaultIntegral<bool,false> _neverMatchRepo;
         /** Resolvable kinds to include. */
         std::set<ResKind> _kinds;
         /** Edition filter. */
@@ -1612,7 +1680,7 @@ attremptycheckend:
         Edition _edition;
         /** Installed status filter flags. \see PoolQuery::StatusFilter */
         int _status_flags;
-        /** AttrMatcher per attribtue. */
+        /** StrMatcher per attribtue. */
         AttrMatchList _attrMatchList;
     };
     ///////////////////////////////////////////////////////////////////