libzypp 9.41.1

PoolQuery.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <sstream>
00014 
00015 #include "zypp/base/Gettext.h"
00016 #include "zypp/base/LogTools.h"
00017 #include "zypp/base/Algorithm.h"
00018 #include "zypp/base/String.h"
00019 #include "zypp/repo/RepoException.h"
00020 #include "zypp/RelCompare.h"
00021 
00022 #include "zypp/sat/Pool.h"
00023 #include "zypp/sat/Solvable.h"
00024 #include "zypp/sat/AttrMatcher.h"
00025 
00026 #include "zypp/PoolQuery.h"
00027 
00028 #undef ZYPP_BASE_LOGGER_LOGGROUP
00029 #define ZYPP_BASE_LOGGER_LOGGROUP "PoolQuery"
00030 
00031 using namespace std;
00032 using namespace zypp::sat;
00033 
00035 namespace zypp
00036 { 
00037 
00039   typedef sat::AttrMatcher StrMatcher;
00040 
00042   namespace
00043   { 
00044 
00046     // some Helpers and Predicates
00048 
00049     bool isDependencyAttribute( sat::SolvAttr attr_r )
00050     {
00051       static sat::SolvAttr deps[] = {
00052         SolvAttr::provides,
00053         SolvAttr::requires,
00054         SolvAttr::recommends,
00055         SolvAttr::obsoletes,
00056         SolvAttr::conflicts,
00057         SolvAttr::suggests,
00058         SolvAttr::supplements,
00059         SolvAttr::enhances,
00060       };
00061       for_( it, arrayBegin(deps), arrayEnd(deps) )
00062         if ( *it == attr_r )
00063           return true;
00064       return false;
00065     }
00066 
00071     struct EditionRangePredicate
00072     {
00073       EditionRangePredicate( const Rel & op, const Edition & edition )
00074         : _range( op, edition )
00075         , _arch( Arch_empty )
00076       {}
00077       EditionRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
00078         : _range( op, edition )
00079         , _arch( arch )
00080       {}
00081 
00082       bool operator()( sat::LookupAttr::iterator iter_r )
00083       {
00084         if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
00085           return false;
00086 
00087         CapDetail cap( iter_r.id() );
00088         if ( ! cap.isSimple() )
00089           return false;
00090         if ( cap.isNamed() ) // no range to match
00091           return true;
00092         return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range );
00093       }
00094 
00095       std::string serialize() const
00096       {
00097         std::string ret( "EditionRange" );
00098         str::appendEscaped( ret, _range.op.asString() );
00099         str::appendEscaped( ret, _range.value.asString() );
00100         str::appendEscaped( ret, _arch.asString() );
00101         return ret;
00102       }
00103 
00104       Edition::MatchRange _range;
00105       Arch                _arch;
00106    };
00107 
00109     struct SolvableRangePredicate
00110     {
00111       SolvableRangePredicate( const Rel & op, const Edition & edition )
00112         : _range( op, edition )
00113         , _arch( Arch_empty )
00114       {}
00115 
00116       SolvableRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
00117         : _range( op, edition )
00118         , _arch( arch )
00119       {}
00120 
00121       bool operator()( sat::LookupAttr::iterator iter_r )
00122       {
00123         if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
00124           return false;
00125         return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
00126       }
00127 
00128       std::string serialize() const
00129       {
00130         std::string ret( "SolvableRange" );
00131         str::appendEscaped( ret, _range.op.asString() );
00132         str::appendEscaped( ret, _range.value.asString() );
00133         str::appendEscaped( ret, _arch.asString() );
00134         return ret;
00135       }
00136 
00137       Edition::MatchRange _range;
00138       Arch                _arch;
00139     };
00140 
00145     struct CapabilityMatchPredicate
00146     {
00147       CapabilityMatchPredicate( Capability cap_r )
00148         : _cap( cap_r )
00149       {}
00150 
00151       bool operator()( sat::LookupAttr::iterator iter_r ) const
00152       {
00153         return _cap.matches( iter_r.asType<Capability>() ) == CapMatch::yes;
00154       }
00155 
00156       std::string serialize() const
00157       {
00158         std::string ret( "CapabilityMatch" );
00159         str::appendEscaped( ret, _cap.asString() );
00160         return ret;
00161       }
00162 
00163       Capability _cap;
00164     };
00165 
00167     //
00169 
00187     struct AttrMatchData
00188     {
00189       typedef function<bool(sat::LookupAttr::iterator)> Predicate;
00190 
00191       static bool always( sat::LookupAttr::iterator ) { return true; }
00192       static bool never( sat::LookupAttr::iterator ) { return false; }
00193 
00194       AttrMatchData()
00195       {}
00196 
00197       AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r )
00198         : attr( attr_r )
00199         , attrMatcher( attrMatcher_r )
00200       {}
00201 
00202       AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r,
00203                      const Predicate & predicate_r, const std::string & predicateStr_r )
00204         : attr( attr_r )
00205         , attrMatcher( attrMatcher_r )
00206         , predicate( predicate_r )
00207         , predicateStr( predicateStr_r )
00208       {}
00209 
00215       template<class _Predicate>
00216       void addPredicate( const _Predicate & predicate_r )
00217       {
00218         predicate    = predicate_r;
00219         predicateStr = predicate_r.serialize();
00220       }
00221 
00227       std::string serialize() const
00228       {
00229         std::string ret( "AttrMatchData" );
00230         str::appendEscaped( ret, attr.asString() );
00231         str::appendEscaped( ret, attrMatcher.searchstring() );
00232         // TODO: Actually the flag should be serialized too, but for PoolQuery
00233         // it's by now sufficient to differ between mode OTHER and others,
00234         // i.e. whether to compile or not compile.
00235         str::appendEscaped( ret, attrMatcher.flags().mode() == Match::OTHER ? "C" : "X" );
00236         str::appendEscaped( ret, predicateStr );
00237         return ret;
00238       }
00239 
00243       static AttrMatchData deserialize( const std::string & str_r )
00244       {
00245         std::vector<std::string> words;
00246         str::splitEscaped( str_r, std::back_inserter(words) );
00247         if ( words.empty() || words[0] != "AttrMatchData" )
00248           ZYPP_THROW( Exception( str::Str() << "Expecting AttrMatchData: " << str_r ) );
00249         if ( words.size() != 5 )
00250           ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00251 
00252         AttrMatchData ret;
00253         ret.attr = sat::SolvAttr( words[1] );
00254         ret.attrMatcher = sat::AttrMatcher( words[2] );
00255         if ( words[3] == "C" )
00256           ret.attrMatcher.setFlags( Match::OTHER );
00257         ret.predicateStr = words[4];
00258 
00259         // now the predicate
00260         words.clear();
00261         str::splitEscaped( ret.predicateStr, std::back_inserter(words) );
00262         if ( ! words.empty() )
00263         {
00264           if ( words[0] == "EditionRange" )
00265           {
00266             switch( words.size() )
00267             {
00268               case 3:
00269                 ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
00270                 break;
00271               case 4:
00272                 ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
00273                 break;
00274               default:
00275                 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00276                 break;
00277             }
00278           }
00279           else if ( words[0] == "SolvableRange" )
00280           {
00281             switch( words.size() )
00282             {
00283               case 3:
00284                 ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
00285                 break;
00286               case 4:
00287                 ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
00288                 break;
00289               default:
00290                 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00291                 break;
00292             }
00293           }
00294           else if ( words[0] == "CapabilityMatch" )
00295           {
00296             if ( words.size() != 2 )
00297               ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00298             ret.predicate = CapabilityMatchPredicate( Capability(words[1]) );
00299           }
00300           else
00301             ZYPP_THROW( Exception( str::Str() << "Unknown predicate: " << str_r ) );
00302         }
00303         return ret;
00304      }
00305 
00306       sat::SolvAttr    attr;
00307       sat::AttrMatcher attrMatcher;
00308       Predicate        predicate;
00309       std::string      predicateStr;
00310     };
00311 
00313     inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
00314     {
00315       str << obj.attr << ": " << obj.attrMatcher;
00316       if ( obj.predicate )
00317         str << " +(" << obj.predicateStr << ")";
00318       return str;
00319     }
00320 
00322     inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs )
00323     {
00324       return ( lhs.attr == rhs.attr
00325                && lhs.attrMatcher == rhs.attrMatcher
00326                && lhs.predicateStr == rhs.predicateStr );
00327     }
00328 
00330     inline bool operator!=( const AttrMatchData & lhs, const AttrMatchData & rhs )
00331     { return !( lhs == rhs ); }
00332 
00334     inline bool operator<( const AttrMatchData & lhs, const AttrMatchData & rhs )
00335     {
00336       if ( lhs.attr != rhs.attr )
00337         return (  lhs.attr < rhs.attr );
00338       if ( lhs.attrMatcher != rhs.attrMatcher )
00339         return (  lhs.attrMatcher < rhs.attrMatcher );
00340       if ( lhs.predicateStr != rhs.predicateStr )
00341         return (  lhs.predicateStr < rhs.predicateStr );
00342       return false;
00343     }
00344 
00345     typedef std::list<AttrMatchData> AttrMatchList;
00346 
00347 
00348   } 
00349   // namespace
00351 
00353   //
00354   //  CLASS NAME : PoolQuery::Impl
00355   //
00357   class PoolQuery::Impl
00358   {
00359   public:
00360     Impl()
00361       : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
00362       , _match_word(false)
00363       , _status_flags(ALL)
00364     {}
00365 
00366     ~Impl()
00367     {}
00368 
00369   public:
00371     string asString() const;
00372 
00376     StrContainer _strings;
00378     AttrRawStrMap _attrs;
00380     std::set<AttrMatchData> _uncompiledPredicated;
00381 
00383     Match _flags;
00384     bool _match_word;
00385 
00387     StatusFilter _status_flags;
00388 
00390     Edition _edition;
00392     Rel _op;
00393 
00395     StrContainer _repos;
00396 
00398     Kinds _kinds;
00400 
00401   public:
00402 
00403     bool operator==( const PoolQuery::Impl & rhs ) const
00404     {
00405       if ( _flags == rhs._flags
00406         // bnc#792901: while libzypp uses exact match mode for a single
00407         // package name lock, zypper always uses glob. :(
00408         // We unify those two forms to enable zypper to remove zypp locks
00409         // without need to actually evaluate the query (which would require
00410         // repos to be loaded).
00411         || ( ( ( _flags.isModeString() && rhs._flags.isModeGlob() )
00412             || ( _flags.isModeGlob() && rhs._flags.isModeString() ) )
00413           && _strings.empty()
00414           && _attrs.size() == 1
00415           && _attrs.begin()->first == sat::SolvAttr::name ) )
00416       {
00417         return ( _strings == rhs._strings
00418               && _attrs == rhs._attrs
00419               && _uncompiledPredicated == rhs._uncompiledPredicated
00420               && _match_word == rhs._match_word
00421               && _status_flags == rhs._status_flags
00422               && _edition == rhs._edition
00423               && _op == rhs._op
00424               && _repos == rhs._repos
00425               && _kinds == rhs._kinds );
00426       }
00427       return false;
00428     }
00429 
00430     bool operator!=( const PoolQuery::Impl & rhs ) const
00431     { return ! operator==( rhs ); }
00432 
00433   public:
00438     void compile() const;
00439 
00441     mutable AttrMatchList _attrMatchList;
00442 
00443   private:
00447     StrMatcher joinedStrMatcher( const StrContainer & container_r, const Match & flags_r ) const;
00448 
00449   private:
00450     friend Impl * rwcowClone<Impl>( const Impl * rhs );
00452     Impl * clone() const
00453     { return new Impl( *this ); }
00454   };
00455 
00457 
00458   struct MyInserter
00459   {
00460     MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
00461 
00462     bool operator()(const string & str)
00463     {
00464       _cont.insert(str);
00465       return true;
00466     }
00467 
00468     PoolQuery::StrContainer & _cont;
00469   };
00470 
00471 
00472   struct EmptyFilter
00473   {
00474     bool operator()(const string & str)
00475     {
00476       return !str.empty();
00477     }
00478   };
00479 
00480   void PoolQuery::Impl::compile() const
00481   {
00482     _attrMatchList.clear();
00483 
00484     if ( _flags.mode() == Match::OTHER ) // this will never succeed...
00485       ZYPP_THROW( MatchUnknownModeException( _flags ) );
00486 
00487     // 'different'         - will have to iterate through all and match by ourselves (slow)
00488     // 'same'              - will pass the compiled string to dataiterator_init
00489     // 'one-attr'          - will pass it to dataiterator_init
00490     // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
00491 
00492     // // NO ATTRIBUTE
00493     // else
00494     //   for all _strings
00495     //     create regex; store in rcstrings; if more strings flag regex;
00496     if (_attrs.empty())
00497     {
00498       ; // A default 'query-all' will be added after all sources are processed.
00499     }
00500 
00501     // // ONE ATTRIBUTE
00502     // else if _attrs is not empty but it contains just one attr
00503     //   for all _strings and _attr[key] strings
00504     //     create regex; flag 'one-attr'; if more strings flag regex;
00505     else if (_attrs.size() == 1)
00506     {
00507       StrContainer joined;
00508       invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00509       invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
00510 
00511       _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first, joinedStrMatcher( joined, _flags ) ) );
00512     }
00513 
00514     // // MULTIPLE ATTRIBUTES
00515     else
00516     {
00517       // check whether there are any per-attribute strings
00518       bool attrvals_empty = true;
00519       for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
00520         if (!ai->second.empty())
00521           for(StrContainer::const_iterator it = ai->second.begin();
00522               it != ai->second.end(); it++)
00523             if (!it->empty())
00524             {
00525               attrvals_empty = false;
00526               goto attremptycheckend;
00527             }
00528 attremptycheckend:
00529 
00530       // chceck whether the per-attribute strings are all the same
00531       bool attrvals_thesame = true;
00532       AttrRawStrMap::const_iterator ai = _attrs.begin();
00533       const StrContainer & set1 = ai->second;
00534       ++ai;
00535       for (; ai != _attrs.end(); ++ai)
00536       {
00537         StrContainer result;
00538         set_difference(
00539           set1.begin(), set1.end(),
00540           ai->second.begin(), ai->second.end(),
00541           inserter(result, result.begin())/*, ltstr()*/);
00542         if (!result.empty())
00543         {
00544           attrvals_thesame = false;
00545           break;
00546         }
00547       }
00548 
00549       // // THE SAME STRINGS FOR DIFFERENT ATTRS
00550       // else if _attrs is not empty but it does not contain strings
00551       //   for each key in _attrs take all _strings
00552       //     create regex; store in rcstrings; flag 'same'; if more strings flag regex;
00553       if (attrvals_empty || attrvals_thesame)
00554       {
00555         StrContainer joined;
00556         if (attrvals_empty)
00557         {
00558           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00559         }
00560         else
00561         {
00562           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00563           invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
00564         }
00565 
00566         // May use the same StrMatcher for all
00567         StrMatcher matcher( joinedStrMatcher( joined, _flags ) );
00568         for_( ai, _attrs.begin(), _attrs.end() )
00569         {
00570           _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
00571         }
00572       }
00573 
00574       // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
00575       // if _attrs is not empty and it contains non-empty vectors with non-empty strings
00576       //   for each key in _attrs take all _strings + all _attrs[key] strings
00577       //     create regex; flag 'different'; if more strings flag regex;
00578       else
00579       {
00580         for_(ai, _attrs.begin(), _attrs.end())
00581         {
00582           StrContainer joined;
00583           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00584           invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
00585 
00586           _attrMatchList.push_back( AttrMatchData( ai->first, joinedStrMatcher( joined, _flags ) ) );
00587         }
00588       }
00589     }
00590 
00591     // Now handle any predicated queries
00592     if ( ! _uncompiledPredicated.empty() )
00593     {
00594       StrContainer global;
00595       invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
00596       for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
00597       {
00598         if ( it->attrMatcher.flags().mode() == Match::OTHER )
00599         {
00600           // need to compile:
00601           StrContainer joined( global );
00602           const std::string & mstr( it->attrMatcher.searchstring() );
00603           if ( ! mstr.empty() )
00604             joined.insert( mstr );
00605 
00606           // copy and exchange the StrMatcher
00607           AttrMatchData nattr( *it );
00608           nattr.attrMatcher = joinedStrMatcher( joined, _flags );
00609           _attrMatchList.push_back( nattr );
00610         }
00611         else
00612         {
00613           // copy matcher
00614          _attrMatchList.push_back( *it );
00615         }
00616       }
00617     }
00618 
00619     // If no attributes defined at all, then add 'query all'
00620     if ( _attrMatchList.empty() )
00621     {
00622       _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr, joinedStrMatcher( _strings, _flags ) ) );
00623     }
00624 
00625     // Finally check here, whether all involved regex compile.
00626     for_( it, _attrMatchList.begin(), _attrMatchList.end() )
00627     {
00628       it->attrMatcher.compile(); // throws on error
00629     }
00630     //DBG << asString() << endl;
00631   }
00632 
00634   namespace
00635   {
00640     std::string rxEscape( const std::string & str_r, const Match & flags_r )
00641     {
00642       if ( str_r.empty() || flags_r.isModeRegex() )
00643         return str_r;
00644 
00645       if ( flags_r.isModeGlob() )
00646         return str::rxEscapeGlob( str_r );
00647 
00648       return str::rxEscapeStr( str_r );
00649     }
00650   } // namespace
00652 
00653   StrMatcher PoolQuery::Impl::joinedStrMatcher( const StrContainer & container_r, const Match & flags_r ) const
00654   {
00655     if ( container_r.empty() )
00656       return StrMatcher( std::string(), flags_r );
00657 
00658     if ( container_r.size() == 1 && !_match_word )      // use RX to match words
00659       return StrMatcher( *container_r.begin(), flags_r );
00660 
00661     // Convert to a regex.
00662     // Note: Modes STRING and GLOB match whole strings (anchored ^ $)
00663     //       SUBSTRING and REGEX match substrings      (match_word anchores SUBSTRING \b)
00664     Match retflags( flags_r );
00665     retflags.setModeRegex();
00666     str::Str ret;
00667 
00668     if ( flags_r.isModeString() || flags_r.isModeGlob() )
00669       ret << "^";
00670     else if ( _match_word )
00671       ret << "\\b";
00672 
00673     // (..|..|..)
00674     char sep = '(';
00675     for_( it, container_r.begin(), container_r.end() )
00676     {
00677       ret << sep << rxEscape( *it, flags_r );
00678       if ( sep == '(' )
00679         sep = '|';
00680     }
00681     ret << ')';
00682 
00683     if ( flags_r.isModeString() || flags_r.isModeGlob() )
00684       ret << "$";
00685     else if ( _match_word )
00686       ret << "\\b";
00687 
00688     return StrMatcher( ret, retflags );
00689   }
00690 
00691   string PoolQuery::Impl::asString() const
00692   {
00693     ostringstream o;
00694 
00695     o << "kinds: ";
00696     if ( _kinds.empty() )
00697       o << "ALL";
00698     else
00699     {
00700       for(Kinds::const_iterator it = _kinds.begin();
00701           it != _kinds.end(); ++it)
00702         o << *it << " ";
00703     }
00704     o << endl;
00705 
00706     o << "repos: ";
00707     if ( _repos.empty() )
00708       o << "ALL";
00709     else
00710     {
00711       for(StrContainer::const_iterator it = _repos.begin();
00712           it != _repos.end(); ++it)
00713         o << *it << " ";
00714     }
00715     o << endl;
00716 
00717     o << "version: "<< _op << " " << _edition.asString() << endl;
00718     o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
00719                                        : "ALL" ) << endl;
00720 
00721     o << "string match flags: " << Match(_flags) << endl;
00722 
00723     // raw
00724     o << "strings: ";
00725     for(StrContainer::const_iterator it = _strings.begin();
00726         it != _strings.end(); ++it)
00727       o << *it << " ";
00728     o << endl;
00729 
00730     o << "attributes: " << endl;
00731     for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
00732     {
00733       o << "* " << ai->first << ": ";
00734       for(StrContainer::const_iterator vi = ai->second.begin();
00735           vi != ai->second.end(); ++vi)
00736         o << *vi << " ";
00737       o << endl;
00738     }
00739 
00740     o << "predicated: " << endl;
00741     for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
00742     {
00743       o << "* " << *it << endl;
00744     }
00745 
00746     // compiled
00747     o << "last attribute matcher compiled: " << endl;
00748     if ( _attrMatchList.empty() )
00749     {
00750       o << "not yet compiled" << endl;
00751     }
00752     else
00753     {
00754       for_( it, _attrMatchList.begin(), _attrMatchList.end() )
00755       {
00756         o << "* " << *it << endl;
00757       }
00758     }
00759     return o.str();
00760   }
00761 
00763 
00765   //
00766   //    CLASS NAME : PoolQuery
00767   //
00769 
00770   PoolQuery::PoolQuery()
00771     : _pimpl(new Impl())
00772   {}
00773 
00774   PoolQuery::~PoolQuery()
00775   {}
00776 
00777   void PoolQuery::addRepo(const std::string &repoalias)
00778   {
00779     if (repoalias.empty())
00780     {
00781       WAR << "ignoring an empty repository alias" << endl;
00782       return;
00783     }
00784     _pimpl->_repos.insert(repoalias);
00785   }
00786 
00787   void PoolQuery::addKind(const ResKind & kind)
00788   { _pimpl->_kinds.insert(kind); }
00789 
00790   void PoolQuery::addString(const string & value)
00791   { _pimpl->_strings.insert(value); }
00792 
00793   void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
00794   { _pimpl->_attrs[attr].insert(value); }
00795 
00796   void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
00797   { return addDependency( attr, name, op, edition, Arch_empty ); }
00798 
00799   void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
00800   {
00801     switch ( op.inSwitch() )
00802     {
00803       case Rel::ANY_e:  // no additional constraint on edition.
00804         if ( arch.empty() )     // no additional constraint on arch.
00805         {
00806           addAttribute( attr, name );
00807           return;
00808         }
00809         break;
00810 
00811       case Rel::NONE_e: // will never match.
00812         return;
00813 
00814       default: // go and add the predicated query (uncompiled)
00815         break;
00816     }
00817 
00818     // Match::OTHER indicates need to compile
00819     // (merge global search strings into name).
00820     AttrMatchData attrMatchData( attr, sat::AttrMatcher( name, Match::OTHER ) );
00821 
00822     if ( isDependencyAttribute( attr ) )
00823       attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
00824     else
00825       attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) );
00826 
00827     _pimpl->_uncompiledPredicated.insert( attrMatchData );
00828   }
00829 
00830   void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
00831   {
00832     CapDetail cap( cap_r );
00833     if ( ! cap.isSimple() ) // will never match.
00834       return;
00835 
00836     // Matches STRING per default. (won't get compiled!)
00837     AttrMatchData attrMatchData( attr, sat::AttrMatcher( cap.name().asString() ) );
00838 
00839     if ( isDependencyAttribute( attr ) )
00840       attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
00841     else
00842       attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
00843 
00844     _pimpl->_uncompiledPredicated.insert( attrMatchData );
00845   }
00846 
00847   void PoolQuery::setEdition(const Edition & edition, const Rel & op)
00848   {
00849     _pimpl->_edition = edition;
00850     _pimpl->_op = op;
00851   }
00852 
00853   void PoolQuery::setMatchSubstring()   { _pimpl->_flags.setModeSubstring();    _pimpl->_match_word = false; }
00854   void PoolQuery::setMatchExact()       { _pimpl->_flags.setModeString();       _pimpl->_match_word = false; }
00855   void PoolQuery::setMatchRegex()       { _pimpl->_flags.setModeRegex();        _pimpl->_match_word = false; }
00856   void PoolQuery::setMatchGlob()        { _pimpl->_flags.setModeGlob();         _pimpl->_match_word = false; }
00857   void PoolQuery::setMatchWord()        { _pimpl->_flags.setModeSubstring();    _pimpl->_match_word = true; }
00858 
00859   Match PoolQuery::flags() const
00860   { return _pimpl->_flags; }
00861   void PoolQuery::setFlags( const Match & flags )
00862   { _pimpl->_flags = flags; }
00863 
00864 
00865   void PoolQuery::setInstalledOnly()
00866   { _pimpl->_status_flags = INSTALLED_ONLY; }
00867   void PoolQuery::setUninstalledOnly()
00868   { _pimpl->_status_flags = UNINSTALLED_ONLY; }
00869   void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
00870   { _pimpl->_status_flags = flags; }
00871 
00872 
00873   const PoolQuery::StrContainer &
00874   PoolQuery::strings() const
00875   { return _pimpl->_strings; }
00876 
00877   const PoolQuery::AttrRawStrMap &
00878   PoolQuery::attributes() const
00879   { return _pimpl->_attrs; }
00880 
00881   const PoolQuery::StrContainer &
00882   PoolQuery::attribute(const sat::SolvAttr & attr) const
00883   {
00884     static const PoolQuery::StrContainer nocontainer;
00885     AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
00886     return it != _pimpl->_attrs.end() ? it->second : nocontainer;
00887   }
00888 
00889   const Edition PoolQuery::edition() const
00890   { return _pimpl->_edition; }
00891   const Rel PoolQuery::editionRel() const
00892   { return _pimpl->_op; }
00893 
00894 
00895   const PoolQuery::Kinds &
00896   PoolQuery::kinds() const
00897   { return _pimpl->_kinds; }
00898 
00899   const PoolQuery::StrContainer &
00900   PoolQuery::repos() const
00901   { return _pimpl->_repos; }
00902 
00903 
00904   bool PoolQuery::caseSensitive() const
00905   { return !_pimpl->_flags.test( Match::NOCASE ); }
00906   void PoolQuery::setCaseSensitive( bool value )
00907   { _pimpl->_flags.turn( Match::NOCASE, !value ); }
00908 
00909   bool PoolQuery::filesMatchFullPath() const
00910   { return _pimpl->_flags.test( Match::FILES ); }
00911   void PoolQuery::setFilesMatchFullPath( bool value )
00912   { _pimpl->_flags.turn( Match::FILES, value ); }
00913 
00914   bool PoolQuery::matchExact() const            { return _pimpl->_flags.isModeString(); }
00915   bool PoolQuery::matchSubstring() const        { return _pimpl->_flags.isModeSubstring() && !_pimpl->_match_word; }
00916   bool PoolQuery::matchGlob() const             { return _pimpl->_flags.isModeGlob(); }
00917   bool PoolQuery::matchRegex() const            { return _pimpl->_flags.isModeRegex(); }
00918   bool PoolQuery::matchWord() const             { return _pimpl->_flags.isModeSubstring() && _pimpl->_match_word; }
00919 
00920   PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
00921   { return _pimpl->_status_flags; }
00922 
00923   bool PoolQuery::empty() const
00924   {
00925     try { return begin() == end(); }
00926     catch (const Exception & ex) {}
00927     return true;
00928   }
00929 
00930   PoolQuery::size_type PoolQuery::size() const
00931   {
00932     try
00933     {
00934       size_type count = 0;
00935       for_( it, begin(), end() )
00936         ++count;
00937       return count;
00938     }
00939     catch (const Exception & ex) {}
00940     return 0;
00941   }
00942 
00943   void PoolQuery::execute(ProcessResolvable fnc)
00944   { invokeOnEach( begin(), end(), fnc); }
00945 
00946 
00947   /*DEPRECATED LEGACY:*/void PoolQuery::setRequireAll( bool ) {}
00948   /*DEPRECATED LEGACY:*/bool PoolQuery::requireAll() const    { return false; }
00949 
00951   //
00952   //  CLASS NAME : PoolQuery::Attr
00953   //
00958   struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
00959   {
00960   private:
00961     friend class IdStringType<PoolQueryAttr>;
00962     IdString _str;
00963   public:
00964 
00965     //noAttr
00966     PoolQueryAttr(){}
00967 
00968     explicit PoolQueryAttr( const char* cstr_r )
00969         : _str( cstr_r )
00970       {}
00971 
00972     explicit PoolQueryAttr( const std::string & str_r )
00973         : _str( str_r )
00974       {}
00975 
00976     // unknown atributes
00977     static const PoolQueryAttr noAttr;
00978 
00979     // PoolQuery's own attributes
00980     static const PoolQueryAttr repoAttr;
00981     static const PoolQueryAttr kindAttr;
00982     static const PoolQueryAttr stringAttr;
00983     static const PoolQueryAttr stringTypeAttr;
00984     static const PoolQueryAttr requireAllAttr;  // LEAGACY: attribute was defined but never implemented.
00985     static const PoolQueryAttr caseSensitiveAttr;
00986     static const PoolQueryAttr installStatusAttr;
00987     static const PoolQueryAttr editionAttr;
00988     static const PoolQueryAttr complexAttr;
00989   };
00990 
00991   const PoolQueryAttr PoolQueryAttr::noAttr;
00992 
00993   const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
00994   const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
00995   const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
00996   const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
00997   const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");     // LEAGACY: attribute was defined but never implemented.
00998   const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
00999   const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
01000   const PoolQueryAttr PoolQueryAttr::editionAttr("version");
01001   const PoolQueryAttr PoolQueryAttr::complexAttr("complex");
01002 
01003   class StringTypeAttr : public IdStringType<PoolQueryAttr>
01004   {
01005     friend class IdStringType<StringTypeAttr>;
01006     IdString _str;
01007 
01008   public:
01009     StringTypeAttr(){}
01010     explicit StringTypeAttr( const char* cstr_r )
01011             : _str( cstr_r ){}
01012     explicit StringTypeAttr( const std::string & str_r )
01013              : _str( str_r ){}
01014 
01015     static const StringTypeAttr noAttr;
01016 
01017     static const StringTypeAttr exactAttr;
01018     static const StringTypeAttr substringAttr;
01019     static const StringTypeAttr regexAttr;
01020     static const StringTypeAttr globAttr;
01021     static const StringTypeAttr wordAttr;
01022   };
01023 
01024   const StringTypeAttr StringTypeAttr::noAttr;
01025 
01026   const StringTypeAttr StringTypeAttr::exactAttr("exact");
01027   const StringTypeAttr StringTypeAttr::substringAttr("substring");
01028   const StringTypeAttr StringTypeAttr::regexAttr("regex");
01029   const StringTypeAttr StringTypeAttr::globAttr("glob");
01030   const StringTypeAttr StringTypeAttr::wordAttr("word");
01031 
01033 
01034 
01035   //\TODO maybe ctor with stream can be usefull
01036   //\TODO let it throw, let it throw, let it throw.
01037   bool PoolQuery::recover( istream &str, char delim )
01038   {
01039     bool finded_something = false; //indicates some atributes is finded
01040     string s;
01041     do {
01042       if ( str.eof() )
01043         break;
01044 
01045       getline( str, s, delim );
01046 
01047       if ((!s.empty()) && s[0]=='#') //comment
01048       {
01049         continue;
01050       }
01051 
01052       string::size_type pos = s.find(':');
01053       if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
01054       {
01055         if (finded_something) //is first blank line after record?
01056         {
01057           break;
01058         }
01059         else
01060         {
01061           continue;
01062         }
01063       }
01064 
01065       finded_something = true;
01066 
01067       string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
01068       string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
01069 
01070       PoolQueryAttr attribute( attrName );
01071 
01072       MIL << "attribute name: " << attrName << endl;
01073 
01074       if ( attribute==PoolQueryAttr::repoAttr )
01075       {
01076         addRepo( attrValue );
01077       }
01078       /* some backwards compatibility */
01079       else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
01080       {
01081         addKind( ResKind(attrValue) );
01082       }
01083       else if ( attribute==PoolQueryAttr::stringAttr
01084         || attribute=="global_string")
01085       {
01086         addString( attrValue );
01087       }
01088       else if ( attribute==PoolQueryAttr::stringTypeAttr
01089         || attribute=="string_type" )
01090       {
01091         StringTypeAttr s(attrValue);
01092         if( s == StringTypeAttr::regexAttr )
01093         {
01094           setMatchRegex();
01095         }
01096         else if ( s == StringTypeAttr::globAttr )
01097         {
01098           setMatchGlob();
01099         }
01100         else if ( s == StringTypeAttr::exactAttr )
01101         {
01102           setMatchExact();
01103         }
01104         else if ( s == StringTypeAttr::substringAttr )
01105         {
01106           setMatchSubstring();
01107         }
01108         else if ( s == StringTypeAttr::wordAttr )
01109         {
01110           setMatchWord();
01111         }
01112         else if ( s == StringTypeAttr::noAttr )
01113         {
01114           WAR << "unknown string type " << attrValue << endl;
01115         }
01116         else
01117         {
01118           WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
01119         }
01120       }
01121       else if ( attribute==PoolQueryAttr::requireAllAttr )
01122       {
01123         // LEAGACY: attribute was defined but never implemented.
01124         // Actually it should not occur outside our testcases.
01125       }
01126       else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
01127       {
01128         if ( str::strToTrue(attrValue) )
01129         {
01130           setCaseSensitive(true);
01131         }
01132         else if ( !str::strToFalse(attrValue) )
01133         {
01134           setCaseSensitive(false);
01135         }
01136         else
01137         {
01138           WAR << "unknown boolean value " << attrValue << endl;
01139         }
01140       }
01141       else if ( attribute==PoolQueryAttr::installStatusAttr )
01142       {
01143         if( attrValue == "all" )
01144         {
01145           setStatusFilterFlags( ALL );
01146         }
01147         else if( attrValue == "installed" )
01148         {
01149           setInstalledOnly();
01150         }
01151         else if( attrValue == "not-installed" )
01152         {
01153           setUninstalledOnly();
01154         }
01155         else
01156         {
01157           WAR << "Unknown value for install status " << attrValue << endl;
01158         }
01159       }
01160       else if ( attribute == PoolQueryAttr::editionAttr)
01161       {
01162         string::size_type pos;
01163         Rel rel("==");
01164         if (attrValue.find_first_of("=<>!") == 0)
01165         {
01166           pos = attrValue.find_last_of("=<>");
01167           rel = Rel(attrValue.substr(0, pos+1));
01168           attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
01169         }
01170 
01171         setEdition(Edition(attrValue), rel);
01172       }
01173       else if ( attribute == PoolQueryAttr::complexAttr )
01174       {
01175         try
01176         {
01177           _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
01178         }
01179         catch ( const Exception & err )
01180         {
01181           WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
01182 
01183         }
01184       }
01185       else if ( attribute==PoolQueryAttr::noAttr )
01186       {
01187         WAR << "empty attribute name" << endl;
01188       }
01189       else
01190       {
01191         string s = attrName;
01192         str::replaceAll( s,"_",":" );
01193         SolvAttr a(s);
01194         if ( a == SolvAttr::name || isDependencyAttribute( a ) )
01195         {
01196           Capability c( attrValue );
01197           CapDetail d( c );
01198           if ( d.isVersioned() )
01199             addDependency( a, d.name().asString(), d.op(), d.ed() );
01200           else
01201             addDependency( a, attrValue );
01202         }
01203         else
01204           addAttribute( a, attrValue );
01205       }
01206 
01207     } while ( true );
01208 
01209     return finded_something;
01210   }
01211 
01212   void PoolQuery::serialize( ostream &str, char delim ) const
01213   {
01214     //separating delim
01215     str << delim;
01216     //iterate thrue all settings and write it
01217     static const zypp::PoolQuery q; //not save default options, so create default query example
01218 
01219     for_( it, repos().begin(), repos().end() )
01220     {
01221       str << "repo: " << *it << delim ;
01222     }
01223 
01224     for_( it, kinds().begin(), kinds().end() )
01225     {
01226       str << PoolQueryAttr::kindAttr.asString() << ": "
01227           << it->idStr() << delim ;
01228     }
01229 
01230     if (editionRel() != Rel::ANY && edition() != Edition::noedition)
01231       str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
01232 
01233     if (matchMode()!=q.matchMode())
01234     {
01235       switch( matchMode() )
01236       {
01237       case Match::STRING:
01238         str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
01239         break;
01240       case Match::SUBSTRING:
01241         str << PoolQueryAttr::stringTypeAttr.asString()
01242             << ": substring" << delim;
01243         break;
01244       case Match::GLOB:
01245         str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
01246         break;
01247       case Match::REGEX:
01248         str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
01249         break;
01250       default:
01251         WAR << "unknown match type "  << matchMode() << endl;
01252       }
01253     }
01254 
01255     if( caseSensitive() != q.caseSensitive() )
01256     {
01257       str << "case_sensitive: ";
01258       if (caseSensitive())
01259       {
01260         str << "on" << delim;
01261       }
01262       else
01263       {
01264         str << "off" << delim;
01265       }
01266     }
01267 
01268     if( statusFilterFlags() != q.statusFilterFlags() )
01269     {
01270       switch( statusFilterFlags() )
01271       {
01272       case ALL:
01273         str << "install_status: all" << delim;
01274         break;
01275       case INSTALLED_ONLY:
01276         str << "install_status: installed" << delim;
01277         break;
01278       case UNINSTALLED_ONLY:
01279         str << "install_status: not-installed" << delim;
01280         break;
01281       }
01282     }
01283 
01284     for_( it, strings().begin(), strings().end() )
01285     {
01286       str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
01287     }
01288 
01289     for_( it, attributes().begin(), attributes().end() )
01290     {
01291       string s = it->first.asString();
01292       str::replaceAll(s,":","_");
01293       for_( it2,it->second.begin(),it->second.end() )
01294       {
01295         str << s <<": "<< *it2 << delim;
01296       }
01297     }
01298 
01299     for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
01300     {
01301       str << "complex: "<< it->serialize() << delim;
01302     }
01303 
01304     //separating delim - protection
01305     str << delim;
01306   }
01307 
01308   string PoolQuery::asString() const
01309   { return _pimpl->asString(); }
01310 
01311   ostream & operator<<( ostream & str, const PoolQuery & obj )
01312   { return str << obj.asString(); }
01313 
01314   std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
01315   { return dumpRange( str << obj, obj.begin(), obj.end() ); }
01316 
01317   bool PoolQuery::operator==( const PoolQuery & rhs ) const
01318   { return *_pimpl == *rhs._pimpl; }
01319 
01321   namespace detail
01322   { 
01323 
01325     //
01326     //  CLASS NAME : PoolQueryMatcher
01327     //
01344     class PoolQueryMatcher
01345     {
01346       public:
01347         typedef sat::LookupAttr::iterator base_iterator;
01348 
01349       public:
01350         const base_iterator & end() const
01351         {
01352           static base_iterator _end;
01353           return _end;
01354         }
01355 
01356         bool advance( base_iterator & base_r ) const
01357         {
01358           if ( base_r == end() )
01359             base_r = startNewQyery(); // first candidate
01360           else
01361           {
01362             base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
01363             ++base_r; // advance to next candidate
01364           }
01365 
01366           while ( base_r != end() )
01367           {
01368             if ( isAMatch( base_r ) )
01369               return true;
01370             // No match: try next
01371             ++base_r;
01372           }
01373           return false;
01374         }
01375 
01379         void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const
01380         {
01381           if ( base_r == end() )
01382             return;
01383 
01384           sat::Solvable inSolvable( base_r.inSolvable() );
01385 
01386           if ( _attrMatchList.size() == 1 )
01387           {
01388             // base_r is already on the 1st matching attribute!
01389             // String matching is done by the base iterator. We must check the predicate here.
01390             // Let's see if there are more matches for this solvable:
01391             base_iterator base( base_r );
01392             base.stayInThisSolvable(); // avoid discarding matches we found far away from here.
01393             return_r.push_back( base );
01394 
01395             const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01396             for ( ++base; base.inSolvable() == inSolvable; ++base ) // safe even if base == end()
01397             {
01398               if ( ! predicate || predicate( base ) )
01399                 return_r.push_back( base );
01400             }
01401           }
01402           else
01403           {
01404             // Here: search all attributes ;(
01405             for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01406             {
01407               const AttrMatchData & matchData( *mi );
01408               sat::LookupAttr q( matchData.attr, inSolvable );
01409               if ( matchData.attrMatcher ) // an empty searchstring matches always
01410                 q.setAttrMatcher( matchData.attrMatcher );
01411 
01412               if ( ! q.empty() ) // there are matches.
01413               {
01414                 // now check any predicate:
01415                 const AttrMatchData::Predicate & predicate( matchData.predicate );
01416                 for_( it, q.begin(), q.end() )
01417                 {
01418                   if ( ! predicate || predicate( it ) )
01419                     return_r.push_back( it );
01420                 }
01421               }
01422             }
01423           }
01424         }
01425 
01426       public:
01430         PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
01431         {
01432           query_r->compile();
01433 
01434           // Repo restriction:
01435           sat::Pool satpool( sat::Pool::instance() );
01436 
01437           for_( it, query_r->_repos.begin(), query_r->_repos.end() )
01438           {
01439             Repository r( satpool.reposFind( *it ) );
01440             if ( r )
01441               _repos.insert( r );
01442             else
01443               _neverMatchRepo = true;
01444           }
01445           // _neverMatchRepo: we just need to catch the case that no repo
01446           // matched, so we'd interpret the empty list as 'take from all'
01447           if ( _neverMatchRepo && ! _repos.empty() )
01448             _neverMatchRepo = false;
01449 
01450           // Kind restriction:
01451           _kinds = query_r->_kinds;
01452           // Edition restriction:
01453           _op      = query_r->_op;
01454           _edition = query_r->_edition;
01455           // Status restriction:
01456           _status_flags = query_r->_status_flags;
01457           // AttrMatcher
01458           _attrMatchList = query_r->_attrMatchList;
01459         }
01460 
01461         ~PoolQueryMatcher()
01462         {}
01463 
01464       private:
01466         base_iterator startNewQyery() const
01467         {
01468           sat::LookupAttr q;
01469 
01470           if ( _neverMatchRepo )
01471             return q.end();
01472 
01473           // Repo restriction:
01474           if ( _repos.size() == 1 )
01475             q.setRepo( *_repos.begin() );
01476           // else: handled in isAMatch.
01477 
01478           // Attribute restriction:
01479           if ( _attrMatchList.size() == 1 ) // all (SolvAttr::allAttr) or 1 attr
01480           {
01481             const AttrMatchData & matchData( _attrMatchList.front() );
01482             q.setAttr( matchData.attr );
01483             if ( matchData.attrMatcher ) // empty searchstring matches always
01484               q.setAttrMatcher( matchData.attrMatcher );
01485           }
01486           else // more than 1 attr (but not all)
01487           {
01488             // no restriction, it's all handled in isAMatch.
01489             q.setAttr( sat::SolvAttr::allAttr );
01490           }
01491 
01492           return q.begin();
01493         }
01494 
01495 
01506         bool isAMatch( base_iterator & base_r ) const
01507         {
01509           Repository inRepo( base_r.inRepo() );
01510           // Status restriction:
01511           if ( _status_flags
01512              && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
01513           {
01514             base_r.nextSkipRepo();
01515             return false;
01516           }
01517           // Repo restriction:
01518           if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
01519           {
01520             base_r.nextSkipRepo();
01521             return false;
01522           }
01524           sat::Solvable inSolvable( base_r.inSolvable() );
01525           // Kind restriction:
01526           if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
01527           {
01528             base_r.nextSkipSolvable();
01529             return false;
01530           }
01531 
01532           // Edition restriction:
01533           if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
01534           {
01535             base_r.nextSkipSolvable();
01536             return false;
01537           }
01539           // string and predicate matching:
01540 
01541           if ( _attrMatchList.size() == 1 )
01542           {
01543             // String matching was done by the base iterator.
01544             // Now check any predicate:
01545             const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01546             if ( ! predicate || predicate( base_r ) )
01547               return true;
01548 
01549             return false; // no skip as there may be more occurrences od this attr.
01550           }
01551 
01552           // Here: search all attributes ;(
01553           for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01554           {
01555             const AttrMatchData & matchData( *mi );
01556             sat::LookupAttr q( matchData.attr, inSolvable );
01557             if ( matchData.attrMatcher ) // an empty searchstring matches always
01558               q.setAttrMatcher( matchData.attrMatcher );
01559 
01560             if ( ! q.empty() ) // there are matches.
01561             {
01562               // now check any predicate:
01563               const AttrMatchData::Predicate & predicate( matchData.predicate );
01564               if ( predicate )
01565               {
01566                 for_( it, q.begin(), q.end() )
01567                 {
01568                   if ( predicate( it ) )
01569                     return true;
01570                 }
01571               }
01572               else
01573                 return true;
01574             }
01575           }
01576           base_r.nextSkipSolvable();
01577           return false;
01578         }
01579 
01580       private:
01582         std::set<Repository> _repos;
01583         DefaultIntegral<bool,false> _neverMatchRepo;
01585         std::set<ResKind> _kinds;
01587         Rel _op;
01588         Edition _edition;
01590         int _status_flags;
01592         AttrMatchList _attrMatchList;
01593     };
01595 
01596     void PoolQueryIterator::increment()
01597     {
01598       // matcher restarts if at end! It is called from the ctor
01599       // to get the 1st match. But if the end is reached, it should
01600       // be deleted, otherwise we'd start over again.
01601       if ( !_matcher )
01602         return; // at end
01603       if ( _matches )
01604         _matches.reset(); // invalidate old matches
01605       if ( ! _matcher->advance( base_reference() ) )
01606         _matcher.reset();
01607     }
01608 
01609     const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
01610     {
01611       if ( _matches )
01612         return *_matches;
01613 
01614       if ( !_matcher )
01615       {
01616         // at end of query:
01617         static const Matches _none;
01618         return _none;
01619       }
01620 
01621       _matches.reset( new Matches );
01622       _matcher->matchDetail( base_reference(), *_matches );
01623       return *_matches;
01624     }
01625 
01626     std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
01627     {
01628       str << *obj;
01629       if ( ! obj.matchesEmpty() )
01630       {
01631         for_( it, obj.matchesBegin(), obj.matchesEnd() )
01632         {
01633           str << endl << "    " << it->inSolvAttr() << "\t" << it->asString();
01634         }
01635       }
01636       return str;
01637     }
01638 
01640   } //namespace detail
01642 
01643   detail::PoolQueryIterator PoolQuery::begin() const
01644   {
01645     return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
01646   }
01647 
01649 } // namespace zypp
01651