libzypp
10.5.0
|
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 return ( _strings == rhs._strings 00405 && _attrs == rhs._attrs 00406 && _uncompiledPredicated == rhs._uncompiledPredicated 00407 && _flags == rhs._flags 00408 && _match_word == rhs._match_word 00409 && _require_all == rhs._require_all 00410 && _status_flags == rhs._status_flags 00411 && _edition == rhs._edition 00412 && _op == rhs._op 00413 && _repos == rhs._repos 00414 && _kinds == rhs._kinds ); 00415 } 00416 00417 bool operator!=( const PoolQuery::Impl & rhs ) const 00418 { return ! operator==( rhs ); } 00419 00420 public: 00425 void compile() const; 00426 00428 mutable AttrMatchList _attrMatchList; 00429 00430 private: 00432 string createRegex( const StrContainer & container, const Match & flags ) const; 00433 00434 private: 00435 friend Impl * rwcowClone<Impl>( const Impl * rhs ); 00437 Impl * clone() const 00438 { return new Impl( *this ); } 00439 }; 00440 00442 00443 struct MyInserter 00444 { 00445 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {} 00446 00447 bool operator()(const string & str) 00448 { 00449 _cont.insert(str); 00450 return true; 00451 } 00452 00453 PoolQuery::StrContainer & _cont; 00454 }; 00455 00456 00457 struct EmptyFilter 00458 { 00459 bool operator()(const string & str) 00460 { 00461 return !str.empty(); 00462 } 00463 }; 00464 00465 void PoolQuery::Impl::compile() const 00466 { 00467 _attrMatchList.clear(); 00468 00469 Match cflags( _flags ); 00470 if ( cflags.mode() == Match::OTHER ) // this will never succeed... 00471 ZYPP_THROW( MatchUnknownModeException( cflags ) ); 00472 00474 string rcstrings; 00475 00476 00477 // 'different' - will have to iterate through all and match by ourselves (slow) 00478 // 'same' - will pass the compiled string to dataiterator_init 00479 // 'one-attr' - will pass it to dataiterator_init 00480 // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING 00481 00482 // // NO ATTRIBUTE 00483 // else 00484 // for all _strings 00485 // create regex; store in rcstrings; if more strings flag regex; 00486 if (_attrs.empty()) 00487 { 00488 ; // A default 'query-all' will be added after all sources are processed. 00489 } 00490 00491 // // ONE ATTRIBUTE 00492 // else if _attrs is not empty but it contains just one attr 00493 // for all _strings and _attr[key] strings 00494 // create regex; flag 'one-attr'; if more strings flag regex; 00495 else if (_attrs.size() == 1) 00496 { 00497 StrContainer joined; 00498 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined)); 00499 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined)); 00500 rcstrings = createRegex(joined, cflags); 00501 if (joined.size() > 1) // switch to regex for multiple strings 00502 cflags.setModeRegex(); 00503 _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first, 00504 sat::AttrMatcher( rcstrings, cflags ) ) ); 00505 } 00506 00507 // // MULTIPLE ATTRIBUTES 00508 else 00509 { 00510 // check whether there are any per-attribute strings 00511 bool attrvals_empty = true; 00512 for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai) 00513 if (!ai->second.empty()) 00514 for(StrContainer::const_iterator it = ai->second.begin(); 00515 it != ai->second.end(); it++) 00516 if (!it->empty()) 00517 { 00518 attrvals_empty = false; 00519 goto attremptycheckend; 00520 } 00521 attremptycheckend: 00522 00523 // chceck whether the per-attribute strings are all the same 00524 bool attrvals_thesame = true; 00525 AttrRawStrMap::const_iterator ai = _attrs.begin(); 00526 const StrContainer & set1 = ai->second; 00527 ++ai; 00528 for (; ai != _attrs.end(); ++ai) 00529 { 00530 StrContainer result; 00531 set_difference( 00532 set1.begin(), set1.end(), 00533 ai->second.begin(), ai->second.end(), 00534 inserter(result, result.begin())/*, ltstr()*/); 00535 if (!result.empty()) 00536 { 00537 attrvals_thesame = false; 00538 break; 00539 } 00540 } 00541 00542 // // THE SAME STRINGS FOR DIFFERENT ATTRS 00543 // else if _attrs is not empty but it does not contain strings 00544 // for each key in _attrs take all _strings 00545 // create regex; store in rcstrings; flag 'same'; if more strings flag regex; 00546 if (attrvals_empty || attrvals_thesame) 00547 { 00548 StrContainer joined; 00549 if (attrvals_empty) 00550 { 00551 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined)); 00552 rcstrings = createRegex(joined, cflags); 00553 } 00554 else 00555 { 00556 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined)); 00557 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined)); 00558 rcstrings = createRegex(joined, cflags); 00559 } 00560 if (joined.size() > 1) // switch to regex for multiple strings 00561 cflags.setModeRegex(); 00562 // May use the same AttrMatcher for all 00563 sat::AttrMatcher matcher( rcstrings, cflags ); 00564 for_( ai, _attrs.begin(), _attrs.end() ) 00565 { 00566 _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) ); 00567 } 00568 } 00569 00570 // // DIFFERENT STRINGS FOR DIFFERENT ATTRS 00571 // if _attrs is not empty and it contains non-empty vectors with non-empty strings 00572 // for each key in _attrs take all _strings + all _attrs[key] strings 00573 // create regex; flag 'different'; if more strings flag regex; 00574 else 00575 { 00576 for_(ai, _attrs.begin(), _attrs.end()) 00577 { 00578 StrContainer joined; 00579 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined)); 00580 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined)); 00581 string s = createRegex(joined, cflags); 00582 if (joined.size() > 1) // switch to regex for multiple strings 00583 cflags.setModeRegex(); 00584 _attrMatchList.push_back( AttrMatchData( ai->first, 00585 sat::AttrMatcher( s, cflags ) ) ); 00586 } 00587 } 00588 } 00589 00590 // Now handle any predicated queries 00591 if ( ! _uncompiledPredicated.empty() ) 00592 { 00593 StrContainer global; 00594 invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) ); 00595 for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() ) 00596 { 00597 if ( it->attrMatcher.flags().mode() == Match::OTHER ) 00598 { 00599 // need to compile: 00600 StrContainer joined( global ); 00601 const std::string & mstr( it->attrMatcher.searchstring() ); 00602 if ( ! mstr.empty() ) 00603 joined.insert( mstr ); 00604 00605 cflags = _flags; 00606 rcstrings = createRegex( joined, cflags ); 00607 if ( joined.size() > 1 ) // switch to regex for multiple strings 00608 cflags.setModeRegex(); 00609 00610 _attrMatchList.push_back( AttrMatchData( it->attr, 00611 sat::AttrMatcher( rcstrings, cflags ), 00612 it->predicate, it->predicateStr ) ); 00613 } 00614 else 00615 { 00616 // copy matcher 00617 _attrMatchList.push_back( *it ); 00618 } 00619 } 00620 } 00621 00622 // If no attributes defined at all, then add 'query all' 00623 if ( _attrMatchList.empty() ) 00624 { 00625 cflags = _flags; 00626 rcstrings = createRegex( _strings, cflags ); 00627 if ( _strings.size() > 1 ) // switch to regex for multiple strings 00628 cflags.setModeRegex(); 00629 _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr, 00630 sat::AttrMatcher( rcstrings, cflags ) ) ); 00631 } 00632 00633 // Finally check here, whether all involved regex compile. 00634 for_( it, _attrMatchList.begin(), _attrMatchList.end() ) 00635 { 00636 it->attrMatcher.compile(); // throws on error 00637 } 00638 //DBG << asString() << endl; 00639 } 00640 00641 00645 static string wildcards2regex(const string & str) 00646 { 00647 string regexed = str; 00648 00649 string r_all(".*"); // regex equivalent of '*' 00650 string r_one("."); // regex equivalent of '?' 00651 string::size_type pos; 00652 00653 // replace all "*" in input with ".*" 00654 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2) 00655 regexed = regexed.replace(pos, 1, r_all); 00656 00657 // replace all "?" in input with "." 00658 for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos) 00659 regexed = regexed.replace(pos, 1, r_one); 00660 00661 return regexed; 00662 } 00663 00664 string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const 00665 { 00667 #define WB (_match_word ? string("\\b") : string()) 00668 string rstr; 00669 00670 if (container.empty()) 00671 return rstr; 00672 00673 if (container.size() == 1) 00674 { 00675 return WB + *container.begin() + WB; 00676 } 00677 00678 // multiple strings 00679 00680 bool use_wildcards = flags.isModeGlob(); 00681 StrContainer::const_iterator it = container.begin(); 00682 string tmp; 00683 00684 if (use_wildcards) 00685 tmp = wildcards2regex(*it); 00686 else 00687 tmp = *it; 00688 00689 if (_require_all) 00690 { 00691 if ( ! flags.isModeString() ) // not match exact 00692 tmp += ".*" + WB + tmp; 00693 rstr = "(?=" + tmp + ")"; 00694 } 00695 else 00696 { 00697 if ( flags.isModeString() || flags.isModeGlob() ) 00698 rstr = "^"; 00699 rstr += WB + "(" + tmp; 00700 } 00701 00702 ++it; 00703 00704 for (; it != container.end(); ++it) 00705 { 00706 if (use_wildcards) 00707 tmp = wildcards2regex(*it); 00708 else 00709 tmp = *it; 00710 00711 if (_require_all) 00712 { 00713 if ( ! flags.isModeString() ) // not match exact 00714 tmp += ".*" + WB + tmp; 00715 rstr += "(?=" + tmp + ")"; 00716 } 00717 else 00718 { 00719 rstr += "|" + tmp; 00720 } 00721 } 00722 00723 if (_require_all) 00724 { 00725 if ( ! flags.isModeString() ) // not match exact 00726 rstr += WB + ".*"; 00727 } 00728 else 00729 { 00730 rstr += ")" + WB; 00731 if ( flags.isModeString() || flags.isModeGlob() ) 00732 rstr += "$"; 00733 } 00734 00735 return rstr; 00736 #undef WB 00737 } 00738 00739 string PoolQuery::Impl::asString() const 00740 { 00741 ostringstream o; 00742 00743 o << "kinds: "; 00744 if ( _kinds.empty() ) 00745 o << "ALL"; 00746 else 00747 { 00748 for(Kinds::const_iterator it = _kinds.begin(); 00749 it != _kinds.end(); ++it) 00750 o << *it << " "; 00751 } 00752 o << endl; 00753 00754 o << "repos: "; 00755 if ( _repos.empty() ) 00756 o << "ALL"; 00757 else 00758 { 00759 for(StrContainer::const_iterator it = _repos.begin(); 00760 it != _repos.end(); ++it) 00761 o << *it << " "; 00762 } 00763 o << endl; 00764 00765 o << "version: "<< _op << " " << _edition.asString() << endl; 00766 o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" ) 00767 : "ALL" ) << endl; 00768 00769 o << "string match flags: " << Match(_flags) << endl; 00770 00771 // raw 00772 o << "strings: "; 00773 for(StrContainer::const_iterator it = _strings.begin(); 00774 it != _strings.end(); ++it) 00775 o << *it << " "; 00776 o << endl; 00777 00778 o << "attributes: " << endl; 00779 for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai) 00780 { 00781 o << "* " << ai->first << ": "; 00782 for(StrContainer::const_iterator vi = ai->second.begin(); 00783 vi != ai->second.end(); ++vi) 00784 o << *vi << " "; 00785 o << endl; 00786 } 00787 00788 o << "predicated: " << endl; 00789 for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() ) 00790 { 00791 o << "* " << *it << endl; 00792 } 00793 00794 // compiled 00795 o << "last attribute matcher compiled: " << endl; 00796 if ( _attrMatchList.empty() ) 00797 { 00798 o << "not yet compiled" << endl; 00799 } 00800 else 00801 { 00802 for_( it, _attrMatchList.begin(), _attrMatchList.end() ) 00803 { 00804 o << "* " << *it << endl; 00805 } 00806 } 00807 return o.str(); 00808 } 00809 00811 00813 // 00814 // CLASS NAME : PoolQuery 00815 // 00817 00818 PoolQuery::PoolQuery() 00819 : _pimpl(new Impl()) 00820 {} 00821 00822 PoolQuery::~PoolQuery() 00823 {} 00824 00825 void PoolQuery::addRepo(const std::string &repoalias) 00826 { 00827 if (repoalias.empty()) 00828 { 00829 WAR << "ignoring an empty repository alias" << endl; 00830 return; 00831 } 00832 _pimpl->_repos.insert(repoalias); 00833 } 00834 00835 void PoolQuery::addKind(const ResKind & kind) 00836 { _pimpl->_kinds.insert(kind); } 00837 00838 void PoolQuery::addString(const string & value) 00839 { _pimpl->_strings.insert(value); } 00840 00841 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value) 00842 { _pimpl->_attrs[attr].insert(value); } 00843 00844 void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition ) 00845 { return addDependency( attr, name, op, edition, Arch_empty ); } 00846 00847 void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch ) 00848 { 00849 switch ( op.inSwitch() ) 00850 { 00851 case Rel::ANY_e: // no additional constraint on edition. 00852 if ( arch.empty() ) // no additional constraint on arch. 00853 { 00854 addAttribute( attr, name ); 00855 return; 00856 } 00857 break; 00858 00859 case Rel::NONE_e: // will never match. 00860 return; 00861 00862 default: // go and add the predicated query (uncompiled) 00863 break; 00864 } 00865 00866 // Match::OTHER indicates need to compile 00867 // (merge global search strings into name). 00868 AttrMatchData attrMatchData( attr, sat::AttrMatcher( name, Match::OTHER ) ); 00869 00870 if ( isDependencyAttribute( attr ) ) 00871 attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) ); 00872 else 00873 attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) ); 00874 00875 _pimpl->_uncompiledPredicated.insert( attrMatchData ); 00876 } 00877 00878 void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r ) 00879 { 00880 CapDetail cap( cap_r ); 00881 if ( ! cap.isSimple() ) // will never match. 00882 return; 00883 00884 // Matches STRING per default. (won't get compiled!) 00885 AttrMatchData attrMatchData( attr, sat::AttrMatcher( cap.name().asString() ) ); 00886 00887 if ( isDependencyAttribute( attr ) ) 00888 attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) ); 00889 else 00890 attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) ); 00891 00892 _pimpl->_uncompiledPredicated.insert( attrMatchData ); 00893 } 00894 00895 void PoolQuery::setEdition(const Edition & edition, const Rel & op) 00896 { 00897 _pimpl->_edition = edition; 00898 _pimpl->_op = op; 00899 } 00900 00901 void PoolQuery::setMatchSubstring() { _pimpl->_flags.setModeSubstring(); } 00902 void PoolQuery::setMatchExact() { _pimpl->_flags.setModeString(); } 00903 void PoolQuery::setMatchRegex() { _pimpl->_flags.setModeRegex(); } 00904 void PoolQuery::setMatchGlob() { _pimpl->_flags.setModeGlob(); } 00905 void PoolQuery::setMatchWord() 00906 { 00907 _pimpl->_match_word = true; 00908 _pimpl->_flags.setModeRegex(); 00909 } 00910 00911 Match PoolQuery::flags() const 00912 { return _pimpl->_flags; } 00913 void PoolQuery::setFlags( const Match & flags ) 00914 { _pimpl->_flags = flags; } 00915 00916 00917 void PoolQuery::setInstalledOnly() 00918 { _pimpl->_status_flags = INSTALLED_ONLY; } 00919 void PoolQuery::setUninstalledOnly() 00920 { _pimpl->_status_flags = UNINSTALLED_ONLY; } 00921 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags ) 00922 { _pimpl->_status_flags = flags; } 00923 00924 00925 void PoolQuery::setRequireAll(bool require_all) 00926 { _pimpl->_require_all = require_all; } 00927 00928 00929 const PoolQuery::StrContainer & 00930 PoolQuery::strings() const 00931 { return _pimpl->_strings; } 00932 00933 const PoolQuery::AttrRawStrMap & 00934 PoolQuery::attributes() const 00935 { return _pimpl->_attrs; } 00936 00937 const PoolQuery::StrContainer & 00938 PoolQuery::attribute(const sat::SolvAttr & attr) const 00939 { 00940 static const PoolQuery::StrContainer nocontainer; 00941 AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr); 00942 return it != _pimpl->_attrs.end() ? it->second : nocontainer; 00943 } 00944 00945 const Edition PoolQuery::edition() const 00946 { return _pimpl->_edition; } 00947 const Rel PoolQuery::editionRel() const 00948 { return _pimpl->_op; } 00949 00950 00951 const PoolQuery::Kinds & 00952 PoolQuery::kinds() const 00953 { return _pimpl->_kinds; } 00954 00955 const PoolQuery::StrContainer & 00956 PoolQuery::repos() const 00957 { return _pimpl->_repos; } 00958 00959 00960 bool PoolQuery::caseSensitive() const 00961 { return !_pimpl->_flags.test( Match::NOCASE ); } 00962 void PoolQuery::setCaseSensitive( bool value ) 00963 { _pimpl->_flags.turn( Match::NOCASE, !value ); } 00964 00965 bool PoolQuery::filesMatchFullPath() const 00966 { return _pimpl->_flags.test( Match::FILES ); } 00967 void PoolQuery::setFilesMatchFullPath( bool value ) 00968 { _pimpl->_flags.turn( Match::FILES, value ); } 00969 00970 bool PoolQuery::matchExact() const { return _pimpl->_flags.isModeString(); } 00971 bool PoolQuery::matchSubstring() const { return _pimpl->_flags.isModeSubstring(); } 00972 bool PoolQuery::matchGlob() const { return _pimpl->_flags.isModeGlob(); } 00973 bool PoolQuery::matchRegex() const { return _pimpl->_flags.isModeRegex(); } 00974 00975 bool PoolQuery::matchWord() const 00976 { return _pimpl->_match_word; } 00977 00978 bool PoolQuery::requireAll() const 00979 { return _pimpl->_require_all; } 00980 00981 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const 00982 { return _pimpl->_status_flags; } 00983 00984 bool PoolQuery::empty() const 00985 { 00986 try { return begin() == end(); } 00987 catch (const Exception & ex) {} 00988 return true; 00989 } 00990 00991 PoolQuery::size_type PoolQuery::size() const 00992 { 00993 try 00994 { 00995 size_type count = 0; 00996 for_( it, begin(), end() ) 00997 ++count; 00998 return count; 00999 } 01000 catch (const Exception & ex) {} 01001 return 0; 01002 } 01003 01004 void PoolQuery::execute(ProcessResolvable fnc) 01005 { invokeOnEach( begin(), end(), fnc); } 01006 01007 01009 // 01010 // CLASS NAME : PoolQuery::Attr 01011 // 01016 struct PoolQueryAttr : public IdStringType<PoolQueryAttr> 01017 { 01018 private: 01019 friend class IdStringType<PoolQueryAttr>; 01020 IdString _str; 01021 public: 01022 01023 //noAttr 01024 PoolQueryAttr(){} 01025 01026 explicit PoolQueryAttr( const char* cstr_r ) 01027 : _str( cstr_r ) 01028 {} 01029 01030 explicit PoolQueryAttr( const std::string & str_r ) 01031 : _str( str_r ) 01032 {} 01033 01034 // unknown atributes 01035 static const PoolQueryAttr noAttr; 01036 01037 // PoolQuery's own attributes 01038 static const PoolQueryAttr repoAttr; 01039 static const PoolQueryAttr kindAttr; 01040 static const PoolQueryAttr stringAttr; 01041 static const PoolQueryAttr stringTypeAttr; 01042 static const PoolQueryAttr requireAllAttr; 01043 static const PoolQueryAttr caseSensitiveAttr; 01044 static const PoolQueryAttr installStatusAttr; 01045 static const PoolQueryAttr editionAttr; 01046 static const PoolQueryAttr complexAttr; 01047 }; 01048 01049 const PoolQueryAttr PoolQueryAttr::noAttr; 01050 01051 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" ); 01052 const PoolQueryAttr PoolQueryAttr::kindAttr( "type" ); 01053 const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" ); 01054 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type"); 01055 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all"); 01056 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive"); 01057 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status"); 01058 const PoolQueryAttr PoolQueryAttr::editionAttr("version"); 01059 const PoolQueryAttr PoolQueryAttr::complexAttr("complex"); 01060 01061 class StringTypeAttr : public IdStringType<PoolQueryAttr> 01062 { 01063 friend class IdStringType<StringTypeAttr>; 01064 IdString _str; 01065 01066 public: 01067 StringTypeAttr(){} 01068 explicit StringTypeAttr( const char* cstr_r ) 01069 : _str( cstr_r ){} 01070 explicit StringTypeAttr( const std::string & str_r ) 01071 : _str( str_r ){} 01072 01073 static const StringTypeAttr noAttr; 01074 01075 static const StringTypeAttr exactAttr; 01076 static const StringTypeAttr substringAttr; 01077 static const StringTypeAttr regexAttr; 01078 static const StringTypeAttr globAttr; 01079 static const StringTypeAttr wordAttr; 01080 }; 01081 01082 const StringTypeAttr StringTypeAttr::noAttr; 01083 01084 const StringTypeAttr StringTypeAttr::exactAttr("exact"); 01085 const StringTypeAttr StringTypeAttr::substringAttr("substring"); 01086 const StringTypeAttr StringTypeAttr::regexAttr("regex"); 01087 const StringTypeAttr StringTypeAttr::globAttr("glob"); 01088 const StringTypeAttr StringTypeAttr::wordAttr("word"); 01089 01091 01092 01093 //\TODO maybe ctor with stream can be usefull 01094 //\TODO let it throw, let it throw, let it throw. 01095 bool PoolQuery::recover( istream &str, char delim ) 01096 { 01097 bool finded_something = false; //indicates some atributes is finded 01098 string s; 01099 do { 01100 if ( str.eof() ) 01101 break; 01102 01103 getline( str, s, delim ); 01104 01105 if ((!s.empty()) && s[0]=='#') //comment 01106 { 01107 continue; 01108 } 01109 01110 string::size_type pos = s.find(':'); 01111 if (s.empty() || pos == s.npos) // some garbage on line... act like blank line 01112 { 01113 if (finded_something) //is first blank line after record? 01114 { 01115 break; 01116 } 01117 else 01118 { 01119 continue; 01120 } 01121 } 01122 01123 finded_something = true; 01124 01125 string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute 01126 string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value 01127 01128 PoolQueryAttr attribute( attrName ); 01129 01130 MIL << "attribute name: " << attrName << endl; 01131 01132 if ( attribute==PoolQueryAttr::repoAttr ) 01133 { 01134 addRepo( attrValue ); 01135 } 01136 /* some backwards compatibility */ 01137 else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" ) 01138 { 01139 addKind( ResKind(attrValue) ); 01140 } 01141 else if ( attribute==PoolQueryAttr::stringAttr 01142 || attribute=="global_string") 01143 { 01144 addString( attrValue ); 01145 } 01146 else if ( attribute==PoolQueryAttr::stringTypeAttr 01147 || attribute=="string_type" ) 01148 { 01149 StringTypeAttr s(attrValue); 01150 if( s == StringTypeAttr::regexAttr ) 01151 { 01152 setMatchRegex(); 01153 } 01154 else if ( s == StringTypeAttr::globAttr ) 01155 { 01156 setMatchGlob(); 01157 } 01158 else if ( s == StringTypeAttr::exactAttr ) 01159 { 01160 setMatchExact(); 01161 } 01162 else if ( s == StringTypeAttr::substringAttr ) 01163 { 01164 setMatchSubstring(); 01165 } 01166 else if ( s == StringTypeAttr::wordAttr ) 01167 { 01168 setMatchWord(); 01169 } 01170 else if ( s == StringTypeAttr::noAttr ) 01171 { 01172 WAR << "unknown string type " << attrValue << endl; 01173 } 01174 else 01175 { 01176 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl; 01177 } 01178 } 01179 else if ( attribute==PoolQueryAttr::requireAllAttr ) 01180 { 01181 if ( str::strToTrue(attrValue) ) 01182 { 01183 setRequireAll(true); 01184 } 01185 else if ( !str::strToFalse(attrValue) ) 01186 { 01187 setRequireAll(false); 01188 } 01189 else 01190 { 01191 WAR << "unknown boolean value " << attrValue << endl; 01192 } 01193 } 01194 else if ( attribute==PoolQueryAttr::caseSensitiveAttr ) 01195 { 01196 if ( str::strToTrue(attrValue) ) 01197 { 01198 setCaseSensitive(true); 01199 } 01200 else if ( !str::strToFalse(attrValue) ) 01201 { 01202 setCaseSensitive(false); 01203 } 01204 else 01205 { 01206 WAR << "unknown boolean value " << attrValue << endl; 01207 } 01208 } 01209 else if ( attribute==PoolQueryAttr::installStatusAttr ) 01210 { 01211 if( attrValue == "all" ) 01212 { 01213 setStatusFilterFlags( ALL ); 01214 } 01215 else if( attrValue == "installed" ) 01216 { 01217 setInstalledOnly(); 01218 } 01219 else if( attrValue == "not-installed" ) 01220 { 01221 setUninstalledOnly(); 01222 } 01223 else 01224 { 01225 WAR << "Unknown value for install status " << attrValue << endl; 01226 } 01227 } 01228 else if ( attribute == PoolQueryAttr::editionAttr) 01229 { 01230 string::size_type pos; 01231 Rel rel("=="); 01232 if (attrValue.find_first_of("=<>!") == 0) 01233 { 01234 pos = attrValue.find_last_of("=<>"); 01235 rel = Rel(attrValue.substr(0, pos+1)); 01236 attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos)); 01237 } 01238 01239 setEdition(Edition(attrValue), rel); 01240 } 01241 else if ( attribute == PoolQueryAttr::complexAttr ) 01242 { 01243 try 01244 { 01245 _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) ); 01246 } 01247 catch ( const Exception & err ) 01248 { 01249 WAR << "Unparsable value for complex: " << err.asUserHistory() << endl; 01250 01251 } 01252 } 01253 else if ( attribute==PoolQueryAttr::noAttr ) 01254 { 01255 WAR << "empty attribute name" << endl; 01256 } 01257 else 01258 { 01259 string s = attrName; 01260 str::replaceAll( s,"_",":" ); 01261 SolvAttr a(s); 01262 if ( a == SolvAttr::name || isDependencyAttribute( a ) ) 01263 { 01264 Capability c( attrValue ); 01265 CapDetail d( c ); 01266 if ( d.isVersioned() ) 01267 addDependency( a, d.name().asString(), d.op(), d.ed() ); 01268 else 01269 addDependency( a, attrValue ); 01270 } 01271 else 01272 addAttribute( a, attrValue ); 01273 } 01274 01275 } while ( true ); 01276 01277 return finded_something; 01278 } 01279 01280 void PoolQuery::serialize( ostream &str, char delim ) const 01281 { 01282 //separating delim 01283 str << delim; 01284 //iterate thrue all settings and write it 01285 static const zypp::PoolQuery q; //not save default options, so create default query example 01286 01287 for_( it, repos().begin(), repos().end() ) 01288 { 01289 str << "repo: " << *it << delim ; 01290 } 01291 01292 for_( it, kinds().begin(), kinds().end() ) 01293 { 01294 str << PoolQueryAttr::kindAttr.asString() << ": " 01295 << it->idStr() << delim ; 01296 } 01297 01298 if (editionRel() != Rel::ANY && edition() != Edition::noedition) 01299 str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim; 01300 01301 if (matchMode()!=q.matchMode()) 01302 { 01303 switch( matchMode() ) 01304 { 01305 case Match::STRING: 01306 str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim; 01307 break; 01308 case Match::SUBSTRING: 01309 str << PoolQueryAttr::stringTypeAttr.asString() 01310 << ": substring" << delim; 01311 break; 01312 case Match::GLOB: 01313 str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim; 01314 break; 01315 case Match::REGEX: 01316 str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim; 01317 break; 01318 default: 01319 WAR << "unknown match type " << matchMode() << endl; 01320 } 01321 } 01322 01323 if( caseSensitive() != q.caseSensitive() ) 01324 { 01325 str << "case_sensitive: "; 01326 if (caseSensitive()) 01327 { 01328 str << "on" << delim; 01329 } 01330 else 01331 { 01332 str << "off" << delim; 01333 } 01334 } 01335 01336 if( requireAll() != q.requireAll() ) 01337 { 01338 str << "require_all: "; 01339 if (requireAll()) 01340 { 01341 str << "on" << delim; 01342 } 01343 else 01344 { 01345 str << "off" << delim; 01346 } 01347 } 01348 01349 if( statusFilterFlags() != q.statusFilterFlags() ) 01350 { 01351 switch( statusFilterFlags() ) 01352 { 01353 case ALL: 01354 str << "install_status: all" << delim; 01355 break; 01356 case INSTALLED_ONLY: 01357 str << "install_status: installed" << delim; 01358 break; 01359 case UNINSTALLED_ONLY: 01360 str << "install_status: not-installed" << delim; 01361 break; 01362 } 01363 } 01364 01365 for_( it, strings().begin(), strings().end() ) 01366 { 01367 str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim; 01368 } 01369 01370 for_( it, attributes().begin(), attributes().end() ) 01371 { 01372 string s = it->first.asString(); 01373 str::replaceAll(s,":","_"); 01374 for_( it2,it->second.begin(),it->second.end() ) 01375 { 01376 str << s <<": "<< *it2 << delim; 01377 } 01378 } 01379 01380 for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() ) 01381 { 01382 str << "complex: "<< it->serialize() << delim; 01383 } 01384 01385 //separating delim - protection 01386 str << delim; 01387 } 01388 01389 string PoolQuery::asString() const 01390 { return _pimpl->asString(); } 01391 01392 ostream & operator<<( ostream & str, const PoolQuery & obj ) 01393 { return str << obj.asString(); } 01394 01395 std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj ) 01396 { return dumpRange( str << obj, obj.begin(), obj.end() ); } 01397 01398 bool PoolQuery::operator==( const PoolQuery & rhs ) const 01399 { return *_pimpl == *rhs._pimpl; } 01400 01402 namespace detail 01403 { 01404 01406 // 01407 // CLASS NAME : PoolQueryMatcher 01408 // 01425 class PoolQueryMatcher 01426 { 01427 public: 01428 typedef sat::LookupAttr::iterator base_iterator; 01429 01430 public: 01431 const base_iterator & end() const 01432 { 01433 static base_iterator _end; 01434 return _end; 01435 } 01436 01437 bool advance( base_iterator & base_r ) const 01438 { 01439 if ( base_r == end() ) 01440 base_r = startNewQyery(); // first candidate 01441 else 01442 { 01443 base_r.nextSkipSolvable(); // assert we don't visit this Solvable again 01444 ++base_r; // advance to next candidate 01445 } 01446 01447 while ( base_r != end() ) 01448 { 01449 if ( isAMatch( base_r ) ) 01450 return true; 01451 // No match: try next 01452 ++base_r; 01453 } 01454 return false; 01455 } 01456 01460 void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const 01461 { 01462 if ( base_r == end() ) 01463 return; 01464 01465 sat::Solvable inSolvable( base_r.inSolvable() ); 01466 01467 if ( _attrMatchList.size() == 1 ) 01468 { 01469 // base_r is already on the 1st matching attribute! 01470 // String matching is done by the base iterator. We must check the predicate here. 01471 // Let's see if there are more matches for this solvable: 01472 base_iterator base( base_r ); 01473 base.stayInThisSolvable(); // avoid discarding matches we found far away from here. 01474 return_r.push_back( base ); 01475 01476 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate ); 01477 for ( ++base; base.inSolvable() == inSolvable; ++base ) // safe even if base == end() 01478 { 01479 if ( ! predicate || predicate( base ) ) 01480 return_r.push_back( base ); 01481 } 01482 } 01483 else 01484 { 01485 // Here: search all attributes ;( 01486 for_( mi, _attrMatchList.begin(), _attrMatchList.end() ) 01487 { 01488 const AttrMatchData & matchData( *mi ); 01489 sat::LookupAttr q( matchData.attr, inSolvable ); 01490 if ( matchData.attrMatcher ) // an empty searchstring matches always 01491 q.setAttrMatcher( matchData.attrMatcher ); 01492 01493 if ( ! q.empty() ) // there are matches. 01494 { 01495 // now check any predicate: 01496 const AttrMatchData::Predicate & predicate( matchData.predicate ); 01497 for_( it, q.begin(), q.end() ) 01498 { 01499 if ( ! predicate || predicate( it ) ) 01500 return_r.push_back( it ); 01501 } 01502 } 01503 } 01504 } 01505 } 01506 01507 public: 01511 PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r ) 01512 { 01513 query_r->compile(); 01514 01515 // Repo restriction: 01516 sat::Pool satpool( sat::Pool::instance() ); 01517 01518 for_( it, query_r->_repos.begin(), query_r->_repos.end() ) 01519 { 01520 Repository r( satpool.reposFind( *it ) ); 01521 if ( r ) 01522 _repos.insert( r ); 01523 else 01524 _neverMatchRepo = true; 01525 } 01526 // _neverMatchRepo: we just need to catch the case that no repo 01527 // matched, so we'd interpret the empty list as 'take from all' 01528 if ( _neverMatchRepo && ! _repos.empty() ) 01529 _neverMatchRepo = false; 01530 01531 // Kind restriction: 01532 _kinds = query_r->_kinds; 01533 // Edition restriction: 01534 _op = query_r->_op; 01535 _edition = query_r->_edition; 01536 // Status restriction: 01537 _status_flags = query_r->_status_flags; 01538 // AttrMatcher 01539 _attrMatchList = query_r->_attrMatchList; 01540 } 01541 01542 ~PoolQueryMatcher() 01543 {} 01544 01545 private: 01547 base_iterator startNewQyery() const 01548 { 01549 sat::LookupAttr q; 01550 01551 if ( _neverMatchRepo ) 01552 return q.end(); 01553 01554 // Repo restriction: 01555 if ( _repos.size() == 1 ) 01556 q.setRepo( *_repos.begin() ); 01557 // else: handled in isAMatch. 01558 01559 // Attribute restriction: 01560 if ( _attrMatchList.size() == 1 ) // all (SolvAttr::allAttr) or 1 attr 01561 { 01562 const AttrMatchData & matchData( _attrMatchList.front() ); 01563 q.setAttr( matchData.attr ); 01564 if ( matchData.attrMatcher ) // empty searchstring matches always 01565 q.setAttrMatcher( matchData.attrMatcher ); 01566 } 01567 else // more than 1 attr (but not all) 01568 { 01569 // no restriction, it's all handled in isAMatch. 01570 q.setAttr( sat::SolvAttr::allAttr ); 01571 } 01572 01573 return q.begin(); 01574 } 01575 01576 01587 bool isAMatch( base_iterator & base_r ) const 01588 { 01590 Repository inRepo( base_r.inRepo() ); 01591 // Status restriction: 01592 if ( _status_flags 01593 && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) ) 01594 { 01595 base_r.nextSkipRepo(); 01596 return false; 01597 } 01598 // Repo restriction: 01599 if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() ) 01600 { 01601 base_r.nextSkipRepo(); 01602 return false; 01603 } 01605 sat::Solvable inSolvable( base_r.inSolvable() ); 01606 // Kind restriction: 01607 if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) ) 01608 { 01609 base_r.nextSkipSolvable(); 01610 return false; 01611 } 01612 01613 // Edition restriction: 01614 if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) ) 01615 { 01616 base_r.nextSkipSolvable(); 01617 return false; 01618 } 01620 // string and predicate matching: 01621 01622 if ( _attrMatchList.size() == 1 ) 01623 { 01624 // String matching was done by the base iterator. 01625 // Now check any predicate: 01626 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate ); 01627 if ( ! predicate || predicate( base_r ) ) 01628 return true; 01629 01630 return false; // no skip as there may be more occurrences od this attr. 01631 } 01632 01633 // Here: search all attributes ;( 01634 for_( mi, _attrMatchList.begin(), _attrMatchList.end() ) 01635 { 01636 const AttrMatchData & matchData( *mi ); 01637 sat::LookupAttr q( matchData.attr, inSolvable ); 01638 if ( matchData.attrMatcher ) // an empty searchstring matches always 01639 q.setAttrMatcher( matchData.attrMatcher ); 01640 01641 if ( ! q.empty() ) // there are matches. 01642 { 01643 // now check any predicate: 01644 const AttrMatchData::Predicate & predicate( matchData.predicate ); 01645 if ( predicate ) 01646 { 01647 for_( it, q.begin(), q.end() ) 01648 { 01649 if ( predicate( it ) ) 01650 return true; 01651 } 01652 } 01653 else 01654 return true; 01655 } 01656 } 01657 base_r.nextSkipSolvable(); 01658 return false; 01659 } 01660 01661 private: 01663 std::set<Repository> _repos; 01664 DefaultIntegral<bool,false> _neverMatchRepo; 01666 std::set<ResKind> _kinds; 01668 Rel _op; 01669 Edition _edition; 01671 int _status_flags; 01673 AttrMatchList _attrMatchList; 01674 }; 01676 01677 void PoolQueryIterator::increment() 01678 { 01679 // matcher restarts if at end! It is called from the ctor 01680 // to get the 1st match. But if the end is reached, it should 01681 // be deleted, otherwise we'd start over again. 01682 if ( !_matcher ) 01683 return; // at end 01684 if ( _matches ) 01685 _matches.reset(); // invalidate old matches 01686 if ( ! _matcher->advance( base_reference() ) ) 01687 _matcher.reset(); 01688 } 01689 01690 const PoolQueryIterator::Matches & PoolQueryIterator::matches() const 01691 { 01692 if ( _matches ) 01693 return *_matches; 01694 01695 if ( !_matcher ) 01696 { 01697 // at end of query: 01698 static const Matches _none; 01699 return _none; 01700 } 01701 01702 _matches.reset( new Matches ); 01703 _matcher->matchDetail( base_reference(), *_matches ); 01704 return *_matches; 01705 } 01706 01707 std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj ) 01708 { 01709 str << *obj; 01710 if ( ! obj.matchesEmpty() ) 01711 { 01712 for_( it, obj.matchesBegin(), obj.matchesEnd() ) 01713 { 01714 str << endl << " " << it->inSolvAttr() << "\t" << it->asString(); 01715 } 01716 } 01717 return str; 01718 } 01719 01721 } //namespace detail 01723 01724 detail::PoolQueryIterator PoolQuery::begin() const 01725 { 01726 return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) ); 01727 } 01728 01730 } // namespace zypp 01732