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

Generated on Tue May 5 14:43:18 2015 for libzypp by  doxygen 1.5.6