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 , _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() )
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
00230
00231
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
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
00348
00350
00351
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 )
00471 ZYPP_THROW( MatchUnknownModeException( cflags ) );
00472
00474 string rcstrings;
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 if (_attrs.empty())
00487 {
00488 ;
00489 }
00490
00491
00492
00493
00494
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)
00502 cflags.setModeRegex();
00503 _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
00504 sat::AttrMatcher( rcstrings, cflags ) ) );
00505 }
00506
00507
00508 else
00509 {
00510
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
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()));
00535 if (!result.empty())
00536 {
00537 attrvals_thesame = false;
00538 break;
00539 }
00540 }
00541
00542
00543
00544
00545
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)
00561 cflags.setModeRegex();
00562
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
00571
00572
00573
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)
00583 cflags.setModeRegex();
00584 _attrMatchList.push_back( AttrMatchData( ai->first,
00585 sat::AttrMatcher( s, cflags ) ) );
00586 }
00587 }
00588 }
00589
00590
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
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 )
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
00617 _attrMatchList.push_back( *it );
00618 }
00619 }
00620 }
00621
00622
00623 if ( _attrMatchList.empty() )
00624 {
00625 cflags = _flags;
00626 rcstrings = createRegex( _strings, cflags );
00627 if ( _strings.size() > 1 )
00628 cflags.setModeRegex();
00629 _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
00630 sat::AttrMatcher( rcstrings, cflags ) ) );
00631 }
00632
00633
00634 for_( it, _attrMatchList.begin(), _attrMatchList.end() )
00635 {
00636 it->attrMatcher.compile();
00637 }
00638
00639 }
00640
00641
00645 static string wildcards2regex(const string & str)
00646 {
00647 string regexed = str;
00648
00649 string r_all(".*");
00650 string r_one(".");
00651 string::size_type pos;
00652
00653
00654 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
00655 regexed = regexed.replace(pos, 1, r_all);
00656
00657
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
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() )
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() )
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() )
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
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
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
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:
00852 if ( arch.empty() )
00853 {
00854 addAttribute( attr, name );
00855 return;
00856 }
00857 break;
00858
00859 case Rel::NONE_e:
00860 return;
00861
00862 default:
00863 break;
00864 }
00865
00866
00867
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() )
00882 return;
00883
00884
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
01011
01016 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
01017 {
01018 private:
01019 friend class IdStringType<PoolQueryAttr>;
01020 IdString _str;
01021 public:
01022
01023
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
01035 static const PoolQueryAttr noAttr;
01036
01037
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
01094
01095 bool PoolQuery::recover( istream &str, char delim )
01096 {
01097 bool finded_something = false;
01098 string s;
01099 do {
01100 if ( str.eof() )
01101 break;
01102
01103 getline( str, s, delim );
01104
01105 if ((!s.empty()) && s[0]=='#')
01106 {
01107 continue;
01108 }
01109
01110 string::size_type pos = s.find(':');
01111 if (s.empty() || pos == s.npos)
01112 {
01113 if (finded_something)
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)));
01126 string attrValue(str::trim(string(s,pos+1,s.npos)));
01127
01128 PoolQueryAttr attribute( attrName );
01129
01130 MIL << "attribute name: " << attrName << endl;
01131
01132 if ( attribute==PoolQueryAttr::repoAttr )
01133 {
01134 addRepo( attrValue );
01135 }
01136
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
01283 str << delim;
01284
01285 static const zypp::PoolQuery q;
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
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
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();
01441 else
01442 {
01443 base_r.nextSkipSolvable();
01444 ++base_r;
01445 }
01446
01447 while ( base_r != end() )
01448 {
01449 if ( isAMatch( base_r ) )
01450 return true;
01451
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
01470
01471
01472 base_iterator base( base_r );
01473 base.stayInThisSolvable();
01474 return_r.push_back( base );
01475
01476 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01477 for ( ++base; base.inSolvable() == inSolvable; ++base )
01478 {
01479 if ( ! predicate || predicate( base ) )
01480 return_r.push_back( base );
01481 }
01482 }
01483 else
01484 {
01485
01486 for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01487 {
01488 const AttrMatchData & matchData( *mi );
01489 sat::LookupAttr q( matchData.attr, inSolvable );
01490 if ( matchData.attrMatcher )
01491 q.setAttrMatcher( matchData.attrMatcher );
01492
01493 if ( ! q.empty() )
01494 {
01495
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
01516 sat::Pool satpool( sat::Pool::instance() );
01517 for_( it, query_r->_repos.begin(), query_r->_repos.end() )
01518 {
01519 Repository r( satpool.reposFind( *it ) );
01520 if ( r )
01521 _repos.insert( r );
01522 }
01523
01524 _kinds = query_r->_kinds;
01525
01526 _op = query_r->_op;
01527 _edition = query_r->_edition;
01528
01529 _status_flags = query_r->_status_flags;
01530
01531 _attrMatchList = query_r->_attrMatchList;
01532 }
01533
01534 ~PoolQueryMatcher()
01535 {}
01536
01537 private:
01539 base_iterator startNewQyery() const
01540 {
01541 sat::LookupAttr q;
01542
01543
01544 if ( _repos.size() == 1 )
01545 q.setRepo( *_repos.begin() );
01546
01547
01548
01549 if ( _attrMatchList.size() == 1 )
01550 {
01551 const AttrMatchData & matchData( _attrMatchList.front() );
01552 q.setAttr( matchData.attr );
01553 if ( matchData.attrMatcher )
01554 q.setAttrMatcher( matchData.attrMatcher );
01555 }
01556 else
01557 {
01558
01559 q.setAttr( sat::SolvAttr::allAttr );
01560 }
01561
01562 return q.begin();
01563 }
01564
01565
01576 bool isAMatch( base_iterator & base_r ) const
01577 {
01579 Repository inRepo( base_r.inRepo() );
01580
01581 if ( _status_flags
01582 && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
01583 {
01584 base_r.nextSkipRepo();
01585 return false;
01586 }
01587
01588 if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
01589 {
01590 base_r.nextSkipRepo();
01591 return false;
01592 }
01594 sat::Solvable inSolvable( base_r.inSolvable() );
01595
01596 if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
01597 {
01598 base_r.nextSkipSolvable();
01599 return false;
01600 }
01601
01602
01603 if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
01604 {
01605 base_r.nextSkipSolvable();
01606 return false;
01607 }
01609
01610
01611 if ( _attrMatchList.size() == 1 )
01612 {
01613
01614
01615 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01616 if ( ! predicate || predicate( base_r ) )
01617 return true;
01618
01619 return false;
01620 }
01621
01622
01623 for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01624 {
01625 const AttrMatchData & matchData( *mi );
01626 sat::LookupAttr q( matchData.attr, inSolvable );
01627 if ( matchData.attrMatcher )
01628 q.setAttrMatcher( matchData.attrMatcher );
01629
01630 if ( ! q.empty() )
01631 {
01632
01633 const AttrMatchData::Predicate & predicate( matchData.predicate );
01634 if ( predicate )
01635 {
01636 for_( it, q.begin(), q.end() )
01637 {
01638 if ( predicate( it ) )
01639 return true;
01640 }
01641 }
01642 else
01643 return true;
01644 }
01645 }
01646 base_r.nextSkipSolvable();
01647 return false;
01648 }
01649
01650 private:
01652 std::set<Repository> _repos;
01654 std::set<ResKind> _kinds;
01656 Rel _op;
01657 Edition _edition;
01659 int _status_flags;
01661 AttrMatchList _attrMatchList;
01662 };
01664
01665 void PoolQueryIterator::increment()
01666 {
01667
01668
01669
01670 if ( !_matcher )
01671 return;
01672 if ( _matches )
01673 _matches.reset();
01674 if ( ! _matcher->advance( base_reference() ) )
01675 _matcher.reset();
01676 }
01677
01678 const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
01679 {
01680 if ( _matches )
01681 return *_matches;
01682
01683 if ( !_matcher )
01684 {
01685
01686 static const Matches _none;
01687 return _none;
01688 }
01689
01690 _matches.reset( new Matches );
01691 _matcher->matchDetail( base_reference(), *_matches );
01692 return *_matches;
01693 }
01694
01695 std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
01696 {
01697 str << *obj;
01698 if ( ! obj.matchesEmpty() )
01699 {
01700 for_( it, obj.matchesBegin(), obj.matchesEnd() )
01701 {
01702 str << endl << " " << it->inSolvAttr() << "\t" << it->asString();
01703 }
01704 }
01705 return str;
01706 }
01707
01709 }
01711
01712 detail::PoolQueryIterator PoolQuery::begin() const
01713 {
01714 return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
01715 }
01716
01718 }
01720