00001
00002
00003
00004
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
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 {}
00073
00074 bool operator()( sat::LookupAttr::iterator iter_r )
00075 {
00076 CapDetail cap( iter_r.id() );
00077 if ( ! cap.isSimple() )
00078 return false;
00079 if ( cap.isNamed() )
00080 return true;
00081 return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range );
00082 }
00083
00084 std::string serialize() const
00085 {
00086 std::string ret( "EditionRange" );
00087 str::appendEscaped( ret, _range.op.asString() );
00088 str::appendEscaped( ret, _range.value.asString() );
00089 return ret;
00090 }
00091
00092 Edition::MatchRange _range;
00093 };
00094
00096 struct SolvableRangePredicate
00097 {
00098 SolvableRangePredicate( const Rel & op, const Edition & edition )
00099 : _range( op, edition )
00100 {}
00101
00102 bool operator()( sat::LookupAttr::iterator iter_r )
00103 {
00104 return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
00105 }
00106
00107 std::string serialize() const
00108 {
00109 std::string ret( "SolvableRange" );
00110 str::appendEscaped( ret, _range.op.asString() );
00111 str::appendEscaped( ret, _range.value.asString() );
00112 return ret;
00113 }
00114
00115 Edition::MatchRange _range;
00116 };
00117
00122 struct CapabilityMatchPredicate
00123 {
00124 CapabilityMatchPredicate( Capability cap_r )
00125 : _cap( cap_r )
00126 {}
00127
00128 bool operator()( sat::LookupAttr::iterator iter_r ) const
00129 {
00130 return _cap.matches( iter_r.asType<Capability>() ) == CapMatch::yes;
00131 }
00132
00133 std::string serialize() const
00134 {
00135 std::string ret( "CapabilityMatch" );
00136 str::appendEscaped( ret, _cap.asString() );
00137 return ret;
00138 }
00139
00140 Capability _cap;
00141 };
00142
00144
00146
00164 struct AttrMatchData
00165 {
00166 typedef function<bool(sat::LookupAttr::iterator)> Predicate;
00167
00168 static bool always( sat::LookupAttr::iterator ) { return true; }
00169 static bool never( sat::LookupAttr::iterator ) { return false; }
00170
00171 AttrMatchData()
00172 {}
00173
00174 AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r )
00175 : attr( attr_r )
00176 , attrMatcher( attrMatcher_r )
00177 {}
00178
00179 AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r,
00180 const Predicate & predicate_r, const std::string & predicateStr_r )
00181 : attr( attr_r )
00182 , attrMatcher( attrMatcher_r )
00183 , predicate( predicate_r )
00184 , predicateStr( predicateStr_r )
00185 {}
00186
00192 template<class _Predicate>
00193 void addPredicate( const _Predicate & predicate_r )
00194 {
00195 predicate = predicate_r;
00196 predicateStr = predicate_r.serialize();
00197 }
00198
00204 std::string serialize() const
00205 {
00206 std::string ret( "AttrMatchData" );
00207 str::appendEscaped( ret, attr.asString() );
00208 str::appendEscaped( ret, attrMatcher.searchstring() );
00209
00210
00211
00212 str::appendEscaped( ret, attrMatcher.flags().mode() == Match::OTHER ? "C" : "X" );
00213 str::appendEscaped( ret, predicateStr );
00214 return ret;
00215 }
00216
00220 static AttrMatchData deserialize( const std::string & str_r )
00221 {
00222 std::vector<std::string> words;
00223 str::splitEscaped( str_r, std::back_inserter(words) );
00224 if ( words.empty() || words[0] != "AttrMatchData" )
00225 ZYPP_THROW( Exception( str::Str() << "Expecting AttrMatchData: " << str_r ) );
00226 if ( words.size() != 5 )
00227 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00228
00229 AttrMatchData ret;
00230 ret.attr = sat::SolvAttr( words[1] );
00231 ret.attrMatcher = sat::AttrMatcher( words[2] );
00232 if ( words[3] == "C" )
00233 ret.attrMatcher.setFlags( Match::OTHER );
00234 ret.predicateStr = words[4];
00235
00236
00237 words.clear();
00238 str::splitEscaped( ret.predicateStr, std::back_inserter(words) );
00239 if ( ! words.empty() )
00240 {
00241 if ( words[0] == "EditionRange" )
00242 {
00243 if ( words.size() != 3 )
00244 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00245 ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
00246 }
00247 else if ( words[0] == "SolvableRange" )
00248 {
00249 if ( words.size() != 3 )
00250 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00251 ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
00252 }
00253 else if ( words[0] == "CapabilityMatch" )
00254 {
00255 if ( words.size() != 2 )
00256 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00257 ret.predicate = CapabilityMatchPredicate( Capability(words[1]) );
00258 }
00259 else
00260 ZYPP_THROW( Exception( str::Str() << "Unknown predicate: " << str_r ) );
00261 }
00262 return ret;
00263 }
00264
00265 sat::SolvAttr attr;
00266 sat::AttrMatcher attrMatcher;
00267 Predicate predicate;
00268 std::string predicateStr;
00269 };
00270
00272 inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
00273 {
00274 str << obj.attr << ": " << obj.attrMatcher;
00275 if ( obj.predicate )
00276 str << " +(" << obj.predicateStr << ")";
00277 return str;
00278 }
00279
00281 inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs )
00282 {
00283 return ( lhs.attr == rhs.attr
00284 && lhs.attrMatcher == rhs.attrMatcher
00285 && lhs.predicateStr == rhs.predicateStr );
00286 }
00287
00289 inline bool operator!=( const AttrMatchData & lhs, const AttrMatchData & rhs )
00290 { return !( lhs == rhs ); }
00291
00293 inline bool operator<( const AttrMatchData & lhs, const AttrMatchData & rhs )
00294 {
00295 if ( lhs.attr != rhs.attr )
00296 return ( lhs.attr < rhs.attr );
00297 if ( lhs.attrMatcher != rhs.attrMatcher )
00298 return ( lhs.attrMatcher < rhs.attrMatcher );
00299 if ( lhs.predicateStr != rhs.predicateStr )
00300 return ( lhs.predicateStr < rhs.predicateStr );
00301 return false;
00302 }
00303
00304 typedef std::list<AttrMatchData> AttrMatchList;
00305
00306
00307 }
00308
00310
00312
00313
00314
00316 class PoolQuery::Impl
00317 {
00318 public:
00319 Impl()
00320 : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
00321 , _match_word(false)
00322 , _require_all(false)
00323 , _status_flags(ALL)
00324 {}
00325
00326 ~Impl()
00327 {}
00328
00329 public:
00331 string asString() const;
00332
00336 StrContainer _strings;
00338 AttrRawStrMap _attrs;
00340 std::set<AttrMatchData> _uncompiledPredicated;
00341
00343 Match _flags;
00344 bool _match_word;
00345 bool _require_all;
00346
00348 StatusFilter _status_flags;
00349
00351 Edition _edition;
00353 Rel _op;
00354
00356 StrContainer _repos;
00357
00359 Kinds _kinds;
00361
00362 public:
00363
00364 bool operator==( const PoolQuery::Impl & rhs ) const
00365 {
00366 return ( _strings == rhs._strings
00367 && _attrs == rhs._attrs
00368 && _uncompiledPredicated == rhs._uncompiledPredicated
00369 && _flags == rhs._flags
00370 && _match_word == rhs._match_word
00371 && _require_all == rhs._require_all
00372 && _status_flags == rhs._status_flags
00373 && _edition == rhs._edition
00374 && _op == rhs._op
00375 && _repos == rhs._repos
00376 && _kinds == rhs._kinds );
00377 }
00378
00379 bool operator!=( const PoolQuery::Impl & rhs ) const
00380 { return ! operator==( rhs ); }
00381
00382 public:
00387 void compile() const;
00388
00390 mutable AttrMatchList _attrMatchList;
00391
00392 private:
00394 string createRegex( const StrContainer & container, const Match & flags ) const;
00395
00396 private:
00397 friend Impl * rwcowClone<Impl>( const Impl * rhs );
00399 Impl * clone() const
00400 { return new Impl( *this ); }
00401 };
00402
00404
00405 struct MyInserter
00406 {
00407 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
00408
00409 bool operator()(const string & str)
00410 {
00411 _cont.insert(str);
00412 return true;
00413 }
00414
00415 PoolQuery::StrContainer & _cont;
00416 };
00417
00418
00419 struct EmptyFilter
00420 {
00421 bool operator()(const string & str)
00422 {
00423 return !str.empty();
00424 }
00425 };
00426
00427 void PoolQuery::Impl::compile() const
00428 {
00429 _attrMatchList.clear();
00430
00431 Match cflags( _flags );
00432 if ( cflags.mode() == Match::OTHER )
00433 ZYPP_THROW( MatchUnknownModeException( cflags ) );
00434
00436 string rcstrings;
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 if (_attrs.empty())
00449 {
00450 ;
00451 }
00452
00453
00454
00455
00456
00457 else if (_attrs.size() == 1)
00458 {
00459 StrContainer joined;
00460 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00461 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
00462 rcstrings = createRegex(joined, cflags);
00463 if (joined.size() > 1)
00464 cflags.setModeRegex();
00465 _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
00466 sat::AttrMatcher( rcstrings, cflags ) ) );
00467 }
00468
00469
00470 else
00471 {
00472
00473 bool attrvals_empty = true;
00474 for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
00475 if (!ai->second.empty())
00476 for(StrContainer::const_iterator it = ai->second.begin();
00477 it != ai->second.end(); it++)
00478 if (!it->empty())
00479 {
00480 attrvals_empty = false;
00481 goto attremptycheckend;
00482 }
00483 attremptycheckend:
00484
00485
00486 bool attrvals_thesame = true;
00487 AttrRawStrMap::const_iterator ai = _attrs.begin();
00488 const StrContainer & set1 = ai->second;
00489 ++ai;
00490 for (; ai != _attrs.end(); ++ai)
00491 {
00492 StrContainer result;
00493 set_difference(
00494 set1.begin(), set1.end(),
00495 ai->second.begin(), ai->second.end(),
00496 inserter(result, result.begin()));
00497 if (!result.empty())
00498 {
00499 attrvals_thesame = false;
00500 break;
00501 }
00502 }
00503
00504
00505
00506
00507
00508 if (attrvals_empty || attrvals_thesame)
00509 {
00510 StrContainer joined;
00511 if (attrvals_empty)
00512 {
00513 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00514 rcstrings = createRegex(joined, cflags);
00515 }
00516 else
00517 {
00518 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00519 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
00520 rcstrings = createRegex(joined, cflags);
00521 }
00522 if (joined.size() > 1)
00523 cflags.setModeRegex();
00524
00525 sat::AttrMatcher matcher( rcstrings, cflags );
00526 for_( ai, _attrs.begin(), _attrs.end() )
00527 {
00528 _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
00529 }
00530 }
00531
00532
00533
00534
00535
00536 else
00537 {
00538 for_(ai, _attrs.begin(), _attrs.end())
00539 {
00540 StrContainer joined;
00541 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00542 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
00543 string s = createRegex(joined, cflags);
00544 if (joined.size() > 1)
00545 cflags.setModeRegex();
00546 _attrMatchList.push_back( AttrMatchData( ai->first,
00547 sat::AttrMatcher( s, cflags ) ) );
00548 }
00549 }
00550 }
00551
00552
00553 if ( ! _uncompiledPredicated.empty() )
00554 {
00555 StrContainer global;
00556 invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
00557 for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
00558 {
00559 if ( it->attrMatcher.flags().mode() == Match::OTHER )
00560 {
00561
00562 StrContainer joined( global );
00563 const std::string & mstr( it->attrMatcher.searchstring() );
00564 if ( ! mstr.empty() )
00565 joined.insert( mstr );
00566
00567 cflags = _flags;
00568 rcstrings = createRegex( joined, cflags );
00569 if ( joined.size() > 1 )
00570 cflags.setModeRegex();
00571
00572 _attrMatchList.push_back( AttrMatchData( it->attr,
00573 sat::AttrMatcher( rcstrings, cflags ),
00574 it->predicate, it->predicateStr ) );
00575 }
00576 else
00577 {
00578
00579 _attrMatchList.push_back( *it );
00580 }
00581 }
00582 }
00583
00584
00585 if ( _attrMatchList.empty() )
00586 {
00587 cflags = _flags;
00588 rcstrings = createRegex( _strings, cflags );
00589 if ( _strings.size() > 1 )
00590 cflags.setModeRegex();
00591 _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
00592 sat::AttrMatcher( rcstrings, cflags ) ) );
00593 }
00594
00595
00596 for_( it, _attrMatchList.begin(), _attrMatchList.end() )
00597 {
00598 it->attrMatcher.compile();
00599 }
00600
00601 }
00602
00603
00607 static string wildcards2regex(const string & str)
00608 {
00609 string regexed = str;
00610
00611 string r_all(".*");
00612 string r_one(".");
00613 string::size_type pos;
00614
00615
00616 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
00617 regexed = regexed.replace(pos, 1, r_all);
00618
00619
00620 for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
00621 regexed = regexed.replace(pos, 1, r_one);
00622
00623 return regexed;
00624 }
00625
00626 string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const
00627 {
00629 #define WB (_match_word ? string("\\b") : string())
00630 string rstr;
00631
00632 if (container.empty())
00633 return rstr;
00634
00635 if (container.size() == 1)
00636 {
00637 return WB + *container.begin() + WB;
00638 }
00639
00640
00641
00642 bool use_wildcards = flags.isModeGlob();
00643 StrContainer::const_iterator it = container.begin();
00644 string tmp;
00645
00646 if (use_wildcards)
00647 tmp = wildcards2regex(*it);
00648 else
00649 tmp = *it;
00650
00651 if (_require_all)
00652 {
00653 if ( ! flags.isModeString() )
00654 tmp += ".*" + WB + tmp;
00655 rstr = "(?=" + tmp + ")";
00656 }
00657 else
00658 {
00659 if ( flags.isModeString() || flags.isModeGlob() )
00660 rstr = "^";
00661 rstr += WB + "(" + tmp;
00662 }
00663
00664 ++it;
00665
00666 for (; it != container.end(); ++it)
00667 {
00668 if (use_wildcards)
00669 tmp = wildcards2regex(*it);
00670 else
00671 tmp = *it;
00672
00673 if (_require_all)
00674 {
00675 if ( ! flags.isModeString() )
00676 tmp += ".*" + WB + tmp;
00677 rstr += "(?=" + tmp + ")";
00678 }
00679 else
00680 {
00681 rstr += "|" + tmp;
00682 }
00683 }
00684
00685 if (_require_all)
00686 {
00687 if ( ! flags.isModeString() )
00688 rstr += WB + ".*";
00689 }
00690 else
00691 {
00692 rstr += ")" + WB;
00693 if ( flags.isModeString() || flags.isModeGlob() )
00694 rstr += "$";
00695 }
00696
00697 return rstr;
00698 #undef WB
00699 }
00700
00701 string PoolQuery::Impl::asString() const
00702 {
00703 ostringstream o;
00704
00705 o << "kinds: ";
00706 if ( _kinds.empty() )
00707 o << "ALL";
00708 else
00709 {
00710 for(Kinds::const_iterator it = _kinds.begin();
00711 it != _kinds.end(); ++it)
00712 o << *it << " ";
00713 }
00714 o << endl;
00715
00716 o << "repos: ";
00717 if ( _repos.empty() )
00718 o << "ALL";
00719 else
00720 {
00721 for(StrContainer::const_iterator it = _repos.begin();
00722 it != _repos.end(); ++it)
00723 o << *it << " ";
00724 }
00725 o << endl;
00726
00727 o << "version: "<< _op << " " << _edition.asString() << endl;
00728 o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
00729 : "ALL" ) << endl;
00730
00731 o << "string match flags: " << Match(_flags) << endl;
00732
00733
00734 o << "strings: ";
00735 for(StrContainer::const_iterator it = _strings.begin();
00736 it != _strings.end(); ++it)
00737 o << *it << " ";
00738 o << endl;
00739
00740 o << "attributes: " << endl;
00741 for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
00742 {
00743 o << "* " << ai->first << ": ";
00744 for(StrContainer::const_iterator vi = ai->second.begin();
00745 vi != ai->second.end(); ++vi)
00746 o << *vi << " ";
00747 o << endl;
00748 }
00749
00750 o << "predicated: " << endl;
00751 for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
00752 {
00753 o << "* " << *it << endl;
00754 }
00755
00756
00757 o << "last attribute matcher compiled: " << endl;
00758 if ( _attrMatchList.empty() )
00759 {
00760 o << "not yet compiled" << endl;
00761 }
00762 else
00763 {
00764 for_( it, _attrMatchList.begin(), _attrMatchList.end() )
00765 {
00766 o << "* " << *it << endl;
00767 }
00768 }
00769 return o.str();
00770 }
00771
00773
00775
00776
00777
00779
00780 PoolQuery::PoolQuery()
00781 : _pimpl(new Impl())
00782 {}
00783
00784 PoolQuery::~PoolQuery()
00785 {}
00786
00787 void PoolQuery::addRepo(const std::string &repoalias)
00788 {
00789 if (repoalias.empty())
00790 {
00791 WAR << "ignoring an empty repository alias" << endl;
00792 return;
00793 }
00794 _pimpl->_repos.insert(repoalias);
00795 }
00796
00797 void PoolQuery::addKind(const ResKind & kind)
00798 { _pimpl->_kinds.insert(kind); }
00799
00800 void PoolQuery::addString(const string & value)
00801 { _pimpl->_strings.insert(value); }
00802
00803 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
00804 { _pimpl->_attrs[attr].insert(value); }
00805
00806 void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
00807 {
00808 switch ( op.inSwitch() )
00809 {
00810 case Rel::ANY_e:
00811 addAttribute( attr, name );
00812 return;
00813
00814 case Rel::NONE_e:
00815 return;
00816
00817 default:
00818 break;
00819 }
00820
00821
00822
00823 AttrMatchData attrMatchData( attr, sat::AttrMatcher( name, Match::OTHER ) );
00824
00825 if ( isDependencyAttribute( attr ) )
00826 attrMatchData.addPredicate( EditionRangePredicate( op, edition ) );
00827 else
00828 attrMatchData.addPredicate( SolvableRangePredicate( op, edition ) );
00829
00830 _pimpl->_uncompiledPredicated.insert( attrMatchData );
00831 }
00832
00833 void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
00834 {
00835 CapDetail cap( cap_r );
00836 if ( ! cap.isSimple() )
00837 return;
00838
00839
00840 AttrMatchData attrMatchData( attr, sat::AttrMatcher( cap.name().asString() ) );
00841
00842 if ( isDependencyAttribute( attr ) )
00843 attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
00844 else
00845 attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
00846
00847 _pimpl->_uncompiledPredicated.insert( attrMatchData );
00848 }
00849
00850 void PoolQuery::setEdition(const Edition & edition, const Rel & op)
00851 {
00852 _pimpl->_edition = edition;
00853 _pimpl->_op = op;
00854 }
00855
00856 void PoolQuery::setMatchSubstring() { _pimpl->_flags.setModeSubstring(); }
00857 void PoolQuery::setMatchExact() { _pimpl->_flags.setModeString(); }
00858 void PoolQuery::setMatchRegex() { _pimpl->_flags.setModeRegex(); }
00859 void PoolQuery::setMatchGlob() { _pimpl->_flags.setModeGlob(); }
00860 void PoolQuery::setMatchWord()
00861 {
00862 _pimpl->_match_word = true;
00863 _pimpl->_flags.setModeRegex();
00864 }
00865
00866 Match PoolQuery::flags() const
00867 { return _pimpl->_flags; }
00868 void PoolQuery::setFlags( const Match & flags )
00869 { _pimpl->_flags = flags; }
00870
00871
00872 void PoolQuery::setInstalledOnly()
00873 { _pimpl->_status_flags = INSTALLED_ONLY; }
00874 void PoolQuery::setUninstalledOnly()
00875 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
00876 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
00877 { _pimpl->_status_flags = flags; }
00878
00879
00880 void PoolQuery::setRequireAll(bool require_all)
00881 { _pimpl->_require_all = require_all; }
00882
00883
00884 const PoolQuery::StrContainer &
00885 PoolQuery::strings() const
00886 { return _pimpl->_strings; }
00887
00888 const PoolQuery::AttrRawStrMap &
00889 PoolQuery::attributes() const
00890 { return _pimpl->_attrs; }
00891
00892 const PoolQuery::StrContainer &
00893 PoolQuery::attribute(const sat::SolvAttr & attr) const
00894 {
00895 static const PoolQuery::StrContainer nocontainer;
00896 AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
00897 return it != _pimpl->_attrs.end() ? it->second : nocontainer;
00898 }
00899
00900 const Edition PoolQuery::edition() const
00901 { return _pimpl->_edition; }
00902 const Rel PoolQuery::editionRel() const
00903 { return _pimpl->_op; }
00904
00905
00906 const PoolQuery::Kinds &
00907 PoolQuery::kinds() const
00908 { return _pimpl->_kinds; }
00909
00910 const PoolQuery::StrContainer &
00911 PoolQuery::repos() const
00912 { return _pimpl->_repos; }
00913
00914
00915 bool PoolQuery::caseSensitive() const
00916 { return !_pimpl->_flags.test( Match::NOCASE ); }
00917 void PoolQuery::setCaseSensitive( bool value )
00918 { _pimpl->_flags.turn( Match::NOCASE, !value ); }
00919
00920 bool PoolQuery::filesMatchFullPath() const
00921 { return _pimpl->_flags.test( Match::FILES ); }
00922 void PoolQuery::setFilesMatchFullPath( bool value )
00923 { _pimpl->_flags.turn( Match::FILES, value ); }
00924
00925 bool PoolQuery::matchExact() const { return _pimpl->_flags.isModeString(); }
00926 bool PoolQuery::matchSubstring() const { return _pimpl->_flags.isModeSubstring(); }
00927 bool PoolQuery::matchGlob() const { return _pimpl->_flags.isModeGlob(); }
00928 bool PoolQuery::matchRegex() const { return _pimpl->_flags.isModeRegex(); }
00929
00930 bool PoolQuery::matchWord() const
00931 { return _pimpl->_match_word; }
00932
00933 bool PoolQuery::requireAll() const
00934 { return _pimpl->_require_all; }
00935
00936 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
00937 { return _pimpl->_status_flags; }
00938
00939 bool PoolQuery::empty() const
00940 {
00941 try { return begin() == end(); }
00942 catch (const Exception & ex) {}
00943 return true;
00944 }
00945
00946 PoolQuery::size_type PoolQuery::size() const
00947 {
00948 try
00949 {
00950 size_type count = 0;
00951 for_( it, begin(), end() )
00952 ++count;
00953 return count;
00954 }
00955 catch (const Exception & ex) {}
00956 return 0;
00957 }
00958
00959 void PoolQuery::execute(ProcessResolvable fnc)
00960 { invokeOnEach( begin(), end(), fnc); }
00961
00962
00964
00965
00966
00971 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
00972 {
00973 private:
00974 friend class IdStringType<PoolQueryAttr>;
00975 IdString _str;
00976 public:
00977
00978
00979 PoolQueryAttr(){}
00980
00981 explicit PoolQueryAttr( const char* cstr_r )
00982 : _str( cstr_r )
00983 {}
00984
00985 explicit PoolQueryAttr( const std::string & str_r )
00986 : _str( str_r )
00987 {}
00988
00989
00990 static const PoolQueryAttr noAttr;
00991
00992
00993 static const PoolQueryAttr repoAttr;
00994 static const PoolQueryAttr kindAttr;
00995 static const PoolQueryAttr stringAttr;
00996 static const PoolQueryAttr stringTypeAttr;
00997 static const PoolQueryAttr requireAllAttr;
00998 static const PoolQueryAttr caseSensitiveAttr;
00999 static const PoolQueryAttr installStatusAttr;
01000 static const PoolQueryAttr editionAttr;
01001 static const PoolQueryAttr complexAttr;
01002 };
01003
01004 const PoolQueryAttr PoolQueryAttr::noAttr;
01005
01006 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
01007 const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
01008 const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
01009 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
01010 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
01011 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
01012 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
01013 const PoolQueryAttr PoolQueryAttr::editionAttr("version");
01014 const PoolQueryAttr PoolQueryAttr::complexAttr("complex");
01015
01016 class StringTypeAttr : public IdStringType<PoolQueryAttr>
01017 {
01018 friend class IdStringType<StringTypeAttr>;
01019 IdString _str;
01020
01021 public:
01022 StringTypeAttr(){}
01023 explicit StringTypeAttr( const char* cstr_r )
01024 : _str( cstr_r ){}
01025 explicit StringTypeAttr( const std::string & str_r )
01026 : _str( str_r ){}
01027
01028 static const StringTypeAttr noAttr;
01029
01030 static const StringTypeAttr exactAttr;
01031 static const StringTypeAttr substringAttr;
01032 static const StringTypeAttr regexAttr;
01033 static const StringTypeAttr globAttr;
01034 static const StringTypeAttr wordAttr;
01035 };
01036
01037 const StringTypeAttr StringTypeAttr::noAttr;
01038
01039 const StringTypeAttr StringTypeAttr::exactAttr("exact");
01040 const StringTypeAttr StringTypeAttr::substringAttr("substring");
01041 const StringTypeAttr StringTypeAttr::regexAttr("regex");
01042 const StringTypeAttr StringTypeAttr::globAttr("glob");
01043 const StringTypeAttr StringTypeAttr::wordAttr("word");
01044
01046
01047
01048
01049
01050 bool PoolQuery::recover( istream &str, char delim )
01051 {
01052 bool finded_something = false;
01053 string s;
01054 do {
01055 if ( str.eof() )
01056 break;
01057
01058 getline( str, s, delim );
01059
01060 if ((!s.empty()) && s[0]=='#')
01061 {
01062 continue;
01063 }
01064
01065 string::size_type pos = s.find(':');
01066 if (s.empty() || pos == s.npos)
01067 {
01068 if (finded_something)
01069 {
01070 break;
01071 }
01072 else
01073 {
01074 continue;
01075 }
01076 }
01077
01078 finded_something = true;
01079
01080 string attrName(str::trim(string(s,0,pos)));
01081 string attrValue(str::trim(string(s,pos+1,s.npos)));
01082
01083 PoolQueryAttr attribute( attrName );
01084
01085 MIL << "attribute name: " << attrName << endl;
01086
01087 if ( attribute==PoolQueryAttr::repoAttr )
01088 {
01089 addRepo( attrValue );
01090 }
01091
01092 else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
01093 {
01094 addKind( ResKind(attrValue) );
01095 }
01096 else if ( attribute==PoolQueryAttr::stringAttr
01097 || attribute=="global_string")
01098 {
01099 addString( attrValue );
01100 }
01101 else if ( attribute==PoolQueryAttr::stringTypeAttr
01102 || attribute=="string_type" )
01103 {
01104 StringTypeAttr s(attrValue);
01105 if( s == StringTypeAttr::regexAttr )
01106 {
01107 setMatchRegex();
01108 }
01109 else if ( s == StringTypeAttr::globAttr )
01110 {
01111 setMatchGlob();
01112 }
01113 else if ( s == StringTypeAttr::exactAttr )
01114 {
01115 setMatchExact();
01116 }
01117 else if ( s == StringTypeAttr::substringAttr )
01118 {
01119 setMatchSubstring();
01120 }
01121 else if ( s == StringTypeAttr::wordAttr )
01122 {
01123 setMatchWord();
01124 }
01125 else if ( s == StringTypeAttr::noAttr )
01126 {
01127 WAR << "unknown string type " << attrValue << endl;
01128 }
01129 else
01130 {
01131 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
01132 }
01133 }
01134 else if ( attribute==PoolQueryAttr::requireAllAttr )
01135 {
01136 if ( str::strToTrue(attrValue) )
01137 {
01138 setRequireAll(true);
01139 }
01140 else if ( !str::strToFalse(attrValue) )
01141 {
01142 setRequireAll(false);
01143 }
01144 else
01145 {
01146 WAR << "unknown boolean value " << attrValue << endl;
01147 }
01148 }
01149 else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
01150 {
01151 if ( str::strToTrue(attrValue) )
01152 {
01153 setCaseSensitive(true);
01154 }
01155 else if ( !str::strToFalse(attrValue) )
01156 {
01157 setCaseSensitive(false);
01158 }
01159 else
01160 {
01161 WAR << "unknown boolean value " << attrValue << endl;
01162 }
01163 }
01164 else if ( attribute==PoolQueryAttr::installStatusAttr )
01165 {
01166 if( attrValue == "all" )
01167 {
01168 setStatusFilterFlags( ALL );
01169 }
01170 else if( attrValue == "installed" )
01171 {
01172 setInstalledOnly();
01173 }
01174 else if( attrValue == "not-installed" )
01175 {
01176 setUninstalledOnly();
01177 }
01178 else
01179 {
01180 WAR << "Unknown value for install status " << attrValue << endl;
01181 }
01182 }
01183 else if ( attribute == PoolQueryAttr::editionAttr)
01184 {
01185 string::size_type pos;
01186 Rel rel("==");
01187 if (attrValue.find_first_of("=<>!") == 0)
01188 {
01189 pos = attrValue.find_last_of("=<>");
01190 rel = Rel(attrValue.substr(0, pos+1));
01191 attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
01192 }
01193
01194 setEdition(Edition(attrValue), rel);
01195 }
01196 else if ( attribute == PoolQueryAttr::complexAttr )
01197 {
01198 try
01199 {
01200 _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
01201 }
01202 catch ( const Exception & err )
01203 {
01204 WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
01205
01206 }
01207 }
01208 else if ( attribute==PoolQueryAttr::noAttr )
01209 {
01210 WAR << "empty attribute name" << endl;
01211 }
01212 else
01213 {
01214 string s = attrName;
01215 str::replaceAll( s,"_",":" );
01216 SolvAttr a(s);
01217 addAttribute(a,attrValue);
01218 }
01219
01220 } while ( true );
01221
01222 return finded_something;
01223 }
01224
01225 void PoolQuery::serialize( ostream &str, char delim ) const
01226 {
01227
01228 str << delim;
01229
01230 static const zypp::PoolQuery q;
01231
01232 for_( it, repos().begin(), repos().end() )
01233 {
01234 str << "repo: " << *it << delim ;
01235 }
01236
01237 for_( it, kinds().begin(), kinds().end() )
01238 {
01239 str << PoolQueryAttr::kindAttr.asString() << ": "
01240 << it->idStr() << delim ;
01241 }
01242
01243 if (editionRel() != Rel::ANY && edition() != Edition::noedition)
01244 str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
01245
01246 if (matchMode()!=q.matchMode())
01247 {
01248 switch( matchMode() )
01249 {
01250 case Match::STRING:
01251 str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
01252 break;
01253 case Match::SUBSTRING:
01254 str << PoolQueryAttr::stringTypeAttr.asString()
01255 << ": substring" << delim;
01256 break;
01257 case Match::GLOB:
01258 str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
01259 break;
01260 case Match::REGEX:
01261 str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
01262 break;
01263 default:
01264 WAR << "unknown match type " << matchMode() << endl;
01265 }
01266 }
01267
01268 if( caseSensitive() != q.caseSensitive() )
01269 {
01270 str << "case_sensitive: ";
01271 if (caseSensitive())
01272 {
01273 str << "on" << delim;
01274 }
01275 else
01276 {
01277 str << "off" << delim;
01278 }
01279 }
01280
01281 if( requireAll() != q.requireAll() )
01282 {
01283 str << "require_all: ";
01284 if (requireAll())
01285 {
01286 str << "on" << delim;
01287 }
01288 else
01289 {
01290 str << "off" << delim;
01291 }
01292 }
01293
01294 if( statusFilterFlags() != q.statusFilterFlags() )
01295 {
01296 switch( statusFilterFlags() )
01297 {
01298 case ALL:
01299 str << "install_status: all" << delim;
01300 break;
01301 case INSTALLED_ONLY:
01302 str << "install_status: installed" << delim;
01303 break;
01304 case UNINSTALLED_ONLY:
01305 str << "install_status: not-installed" << delim;
01306 break;
01307 }
01308 }
01309
01310 for_( it, strings().begin(), strings().end() )
01311 {
01312 str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
01313 }
01314
01315 for_( it, attributes().begin(), attributes().end() )
01316 {
01317 string s = it->first.asString();
01318 str::replaceAll(s,":","_");
01319 for_( it2,it->second.begin(),it->second.end() )
01320 {
01321 str << s <<": "<< *it2 << delim;
01322 }
01323 }
01324
01325 for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
01326 {
01327 str << "complex: "<< it->serialize() << delim;
01328 }
01329
01330
01331 str << delim;
01332 }
01333
01334 string PoolQuery::asString() const
01335 { return _pimpl->asString(); }
01336
01337 ostream & operator<<( ostream & str, const PoolQuery & obj )
01338 { return str << obj.asString(); }
01339
01340 std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
01341 { return dumpRange( str << obj, obj.begin(), obj.end() ); }
01342
01343 bool PoolQuery::operator==( const PoolQuery & rhs ) const
01344 { return *_pimpl == *rhs._pimpl; }
01345
01347 namespace detail
01348 {
01349
01351
01352
01353
01370 class PoolQueryMatcher
01371 {
01372 public:
01373 typedef sat::LookupAttr::iterator base_iterator;
01374
01375 public:
01376 const base_iterator & end() const
01377 {
01378 static base_iterator _end;
01379 return _end;
01380 }
01381
01382 bool advance( base_iterator & base_r ) const
01383 {
01384 if ( base_r == end() )
01385 base_r = startNewQyery();
01386 else
01387 {
01388 base_r.nextSkipSolvable();
01389 ++base_r;
01390 }
01391
01392 while ( base_r != end() )
01393 {
01394 if ( isAMatch( base_r ) )
01395 return true;
01396
01397 ++base_r;
01398 }
01399 return false;
01400 }
01401
01405 void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const
01406 {
01407 if ( base_r == end() )
01408 return;
01409
01410 sat::Solvable inSolvable( base_r.inSolvable() );
01411
01412 if ( _attrMatchList.size() == 1 )
01413 {
01414
01415
01416
01417 base_iterator base( base_r );
01418 base.stayInThisSolvable();
01419 return_r.push_back( base );
01420
01421 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01422 for ( ++base; base.inSolvable() == inSolvable; ++base )
01423 {
01424 if ( ! predicate || predicate( base ) )
01425 return_r.push_back( base );
01426 }
01427 }
01428 else
01429 {
01430
01431 for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01432 {
01433 const AttrMatchData & matchData( *mi );
01434 sat::LookupAttr q( matchData.attr, inSolvable );
01435 if ( matchData.attrMatcher )
01436 q.setAttrMatcher( matchData.attrMatcher );
01437
01438 if ( ! q.empty() )
01439 {
01440
01441 const AttrMatchData::Predicate & predicate( matchData.predicate );
01442 for_( it, q.begin(), q.end() )
01443 {
01444 if ( ! predicate || predicate( it ) )
01445 return_r.push_back( it );
01446 }
01447 }
01448 }
01449 }
01450 }
01451
01452 public:
01456 PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
01457 {
01458 query_r->compile();
01459
01460
01461 sat::Pool satpool( sat::Pool::instance() );
01462 for_( it, query_r->_repos.begin(), query_r->_repos.end() )
01463 {
01464 Repository r( satpool.reposFind( *it ) );
01465 if ( r )
01466 _repos.insert( r );
01467 }
01468
01469 _kinds = query_r->_kinds;
01470
01471 _op = query_r->_op;
01472 _edition = query_r->_edition;
01473
01474 _status_flags = query_r->_status_flags;
01475
01476 _attrMatchList = query_r->_attrMatchList;
01477 }
01478
01479 ~PoolQueryMatcher()
01480 {}
01481
01482 private:
01484 base_iterator startNewQyery() const
01485 {
01486 sat::LookupAttr q;
01487
01488
01489 if ( _repos.size() == 1 )
01490 q.setRepo( *_repos.begin() );
01491
01492
01493
01494 if ( _attrMatchList.size() == 1 )
01495 {
01496 const AttrMatchData & matchData( _attrMatchList.front() );
01497 q.setAttr( matchData.attr );
01498 if ( matchData.attrMatcher )
01499 q.setAttrMatcher( matchData.attrMatcher );
01500 }
01501 else
01502 {
01503
01504 q.setAttr( sat::SolvAttr::allAttr );
01505 }
01506
01507 return q.begin();
01508 }
01509
01510
01521 bool isAMatch( base_iterator & base_r ) const
01522 {
01524 Repository inRepo( base_r.inRepo() );
01525
01526 if ( _status_flags
01527 && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
01528 {
01529 base_r.nextSkipRepo();
01530 return false;
01531 }
01532
01533 if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
01534 {
01535 base_r.nextSkipRepo();
01536 return false;
01537 }
01539 sat::Solvable inSolvable( base_r.inSolvable() );
01540
01541 if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
01542 {
01543 base_r.nextSkipSolvable();
01544 return false;
01545 }
01546
01547
01548 if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
01549 {
01550 base_r.nextSkipSolvable();
01551 return false;
01552 }
01554
01555
01556 if ( _attrMatchList.size() == 1 )
01557 {
01558
01559
01560 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01561 if ( ! predicate || predicate( base_r ) )
01562 return true;
01563
01564 return false;
01565 }
01566
01567
01568 for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01569 {
01570 const AttrMatchData & matchData( *mi );
01571 sat::LookupAttr q( matchData.attr, inSolvable );
01572 if ( matchData.attrMatcher )
01573 q.setAttrMatcher( matchData.attrMatcher );
01574
01575 if ( ! q.empty() )
01576 {
01577
01578 const AttrMatchData::Predicate & predicate( matchData.predicate );
01579 if ( predicate )
01580 {
01581 for_( it, q.begin(), q.end() )
01582 {
01583 if ( predicate( it ) )
01584 return true;
01585 }
01586 }
01587 else
01588 return true;
01589 }
01590 }
01591 base_r.nextSkipSolvable();
01592 return false;
01593 }
01594
01595 private:
01597 std::set<Repository> _repos;
01599 std::set<ResKind> _kinds;
01601 Rel _op;
01602 Edition _edition;
01604 int _status_flags;
01606 AttrMatchList _attrMatchList;
01607 };
01609
01610 void PoolQueryIterator::increment()
01611 {
01612
01613
01614
01615 if ( !_matcher )
01616 return;
01617 if ( _matches )
01618 _matches.reset();
01619 if ( ! _matcher->advance( base_reference() ) )
01620 _matcher.reset();
01621 }
01622
01623 const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
01624 {
01625 if ( _matches )
01626 return *_matches;
01627
01628 if ( !_matcher )
01629 {
01630
01631 static const Matches _none;
01632 return _none;
01633 }
01634
01635 _matches.reset( new Matches );
01636 _matcher->matchDetail( base_reference(), *_matches );
01637 return *_matches;
01638 }
01639
01640 std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
01641 {
01642 str << *obj;
01643 if ( ! obj.matchesEmpty() )
01644 {
01645 for_( it, obj.matchesBegin(), obj.matchesEnd() )
01646 {
01647 str << endl << " " << it->inSolvAttr() << "\t" << it->asString();
01648 }
01649 }
01650 return str;
01651 }
01652
01654 }
01656
01657 detail::PoolQueryIterator PoolQuery::begin() const
01658 {
01659 return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
01660 }
01661
01663 }
01665