libzypp 9.41.1
|
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