1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PoolQuery.cc
15 #include "zypp/base/Gettext.h"
16 #include "zypp/base/LogTools.h"
17 #include "zypp/base/Algorithm.h"
18 #include "zypp/base/String.h"
19 #include "zypp/repo/RepoException.h"
20 #include "zypp/RelCompare.h"
22 #include "zypp/sat/Pool.h"
23 #include "zypp/sat/Solvable.h"
24 #include "zypp/base/StrMatcher.h"
26 #include "zypp/PoolQuery.h"
28 #undef ZYPP_BASE_LOGGER_LOGGROUP
29 #define ZYPP_BASE_LOGGER_LOGGROUP "PoolQuery"
32 using namespace zypp::sat;
34 ///////////////////////////////////////////////////////////////////
36 { /////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////
40 { /////////////////////////////////////////////////////////////////
42 /////////////////////////////////////////////////////////////////
43 // some Helpers and Predicates
44 /////////////////////////////////////////////////////////////////
46 bool isDependencyAttribute( sat::SolvAttr attr_r )
48 static sat::SolvAttr deps[] = {
55 SolvAttr::supplements,
58 for_( it, arrayBegin(deps), arrayEnd(deps) )
64 /** Whether the current capabilities edition range ovelaps and/or its solvables arch matches.
65 * Query asserts \a iter_r points to a capability and we
66 * have to check the range only.
68 struct EditionRangePredicate
70 EditionRangePredicate( const Rel & op, const Edition & edition )
71 : _range( op, edition )
74 EditionRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
75 : _range( op, edition )
79 bool operator()( sat::LookupAttr::iterator iter_r )
81 if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
84 CapDetail cap( iter_r.id() );
85 if ( ! cap.isSimple() )
87 if ( cap.isNamed() ) // no range to match
89 return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range );
92 std::string serialize() const
94 std::string ret( "EditionRange" );
95 str::appendEscaped( ret, _range.op.asString() );
96 str::appendEscaped( ret, _range.value.asString() );
97 str::appendEscaped( ret, _arch.asString() );
101 Edition::MatchRange _range;
105 /** Whether the current Solvables edition is within a given range and/or its arch matches. */
106 struct SolvableRangePredicate
108 SolvableRangePredicate( const Rel & op, const Edition & edition )
109 : _range( op, edition )
110 , _arch( Arch_empty )
113 SolvableRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
114 : _range( op, edition )
118 bool operator()( sat::LookupAttr::iterator iter_r )
120 if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
122 return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
125 std::string serialize() const
127 std::string ret( "SolvableRange" );
128 str::appendEscaped( ret, _range.op.asString() );
129 str::appendEscaped( ret, _range.value.asString() );
130 str::appendEscaped( ret, _arch.asString() );
134 Edition::MatchRange _range;
138 /** Whether the current capability matches a given one.
139 * Query asserts \a iter_r points to a capability and we
140 * have to check the match only.
142 struct CapabilityMatchPredicate
144 CapabilityMatchPredicate( Capability cap_r )
148 bool operator()( sat::LookupAttr::iterator iter_r ) const
150 return _cap.matches( iter_r.asType<Capability>() ) == CapMatch::yes;
153 std::string serialize() const
155 std::string ret( "CapabilityMatch" );
156 str::appendEscaped( ret, _cap.asString() );
163 /////////////////////////////////////////////////////////////////
165 /////////////////////////////////////////////////////////////////
166 /** Match data per attribtue.
168 * This includes the attribute itself, an optional \ref StrMatcher
169 * to restrict the query to certain string values, and an optional
170 * boolean \ref Predicate that may apply further restrictions that can
171 * not be expressed by the \ref strMatcher.
173 * Example for such a \ref predicate would be an additional edition range
174 * check whan looking for dependencies. The \ref strMatcher would
175 * find potential matches by looking at the dependencies name, the
176 * predicate will then check the edition ranges.
178 * As the \ref predicate takes an iterator pointing to the current
179 * match, it's also suitable for sub-structure (flexarray) inspection
180 * (\see \ref sat::LookupAttr::iterator::solvAttrSubEntry).
182 * (bsc#1035729) If SolvAttr::name searches for an explicit \c kind:name,
183 * this \c kind is stored in \ref kindPredicate and will overwrite any
184 * 'global' kind restriction applied via \ref PoolQuery::addKind. This
185 * task can't be passed off to a predicate, as \ref PoolQueryMatcher::isAMatch
186 * must accept only explicit-kind-checking predicate matches, in case the
187 * 'global' kind restriction woudl otherwise discard the match.
189 * \note: \see \ref addPredicate for further constraints.
193 typedef function<bool(sat::LookupAttr::iterator)> Predicate;
195 static bool always( sat::LookupAttr::iterator ) { return true; }
196 static bool never( sat::LookupAttr::iterator ) { return false; }
201 AttrMatchData( sat::SolvAttr attr_r )
205 AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r )
207 , strMatcher( strMatcher_r )
210 AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r,
211 const Predicate & predicate_r, const std::string & predicateStr_r )
213 , strMatcher( strMatcher_r )
214 , predicate( predicate_r )
215 , predicateStr( predicateStr_r )
218 /** A usable Predicate must provide a string serialization.
219 * As there is no \c operator== for \ref Predicate, we compare it's
220 * string representation instead. If you add new predicated, check the
221 * deserialization code in \ref deserialize.
223 template<class _Predicate>
224 void addPredicate( const _Predicate & predicate_r )
226 predicate = predicate_r;
227 predicateStr = predicate_r.serialize();
230 /** Dumb serialization.
232 * AttrMatchData ATTRIBUTE SEARCHSTRING [C|X] SERIALIZED_PREDICATE
235 std::string serialize() const
237 std::string ret( "AttrMatchData" );
238 str::appendEscaped( ret, attr.asString() );
239 str::appendEscaped( ret, strMatcher.searchstring() );
240 // TODO: Actually the flag should be serialized too, but for PoolQuery
241 // it's by now sufficient to differ between mode OTHER and others,
242 // i.e. whether to compile or not compile.
243 str::appendEscaped( ret, strMatcher.flags().mode() == Match::OTHER ? "C" : "X" );
244 str::appendEscaped( ret, predicateStr );
248 /** Dumb restore from serialized string.
249 * \throw Exception on parse error.
251 static AttrMatchData deserialize( const std::string & str_r )
253 std::vector<std::string> words;
254 str::splitEscaped( str_r, std::back_inserter(words) );
255 if ( words.empty() || words[0] != "AttrMatchData" )
256 ZYPP_THROW( Exception( str::Str() << "Expecting AttrMatchData: " << str_r ) );
257 if ( words.size() != 5 )
258 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
261 ret.attr = sat::SolvAttr( words[1] );
262 ret.strMatcher = StrMatcher( words[2] );
263 if ( words[3] == "C" )
264 ret.strMatcher.setFlags( Match::OTHER );
265 ret.predicateStr = words[4];
269 str::splitEscaped( ret.predicateStr, std::back_inserter(words) );
270 if ( ! words.empty() )
272 if ( words[0] == "EditionRange" )
274 switch( words.size() )
277 ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
280 ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
283 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
287 else if ( words[0] == "SolvableRange" )
289 switch( words.size() )
292 ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
295 ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
298 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
302 else if ( words[0] == "CapabilityMatch" )
304 if ( words.size() != 2 )
305 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
306 ret.predicate = CapabilityMatchPredicate( Capability(words[1]) );
309 ZYPP_THROW( Exception( str::Str() << "Unknown predicate: " << str_r ) );
315 StrMatcher strMatcher;
317 std::string predicateStr;
318 ResKind kindPredicate = ResKind::nokind; // holds the 'kind' part if SolvAttr:name looks for an explicit 'kind:name'
321 /** \relates AttrMatchData */
322 inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
324 str << obj.attr << ": " << obj.strMatcher;
325 if ( obj.kindPredicate )
326 str << " +(" << obj.kindPredicate << ")";
328 str << " +(" << obj.predicateStr << ")";
332 /** \relates AttrMatchData */
333 inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs )
335 return ( lhs.attr == rhs.attr
336 && lhs.strMatcher == rhs.strMatcher
337 && lhs.predicateStr == rhs.predicateStr );
340 /** \relates AttrMatchData */
341 inline bool operator!=( const AttrMatchData & lhs, const AttrMatchData & rhs )
342 { return !( lhs == rhs ); }
344 /** \relates AttrMatchData Arbitrary order for std::container. */
345 inline bool operator<( const AttrMatchData & lhs, const AttrMatchData & rhs )
347 if ( lhs.attr != rhs.attr )
348 return ( lhs.attr < rhs.attr );
349 if ( lhs.strMatcher != rhs.strMatcher )
350 return ( lhs.strMatcher < rhs.strMatcher );
351 if ( lhs.predicateStr != rhs.predicateStr )
352 return ( lhs.predicateStr < rhs.predicateStr );
356 typedef std::list<AttrMatchData> AttrMatchList;
359 } /////////////////////////////////////////////////////////////////
361 ///////////////////////////////////////////////////////////////////
363 ///////////////////////////////////////////////////////////////////
365 // CLASS NAME : PoolQuery::Impl
368 class PoolQuery::Impl
372 : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
381 /** String representation */
382 string asString() const;
384 /** \name Raw query options. */
386 /** Raw search strings. */
387 StrContainer _strings;
388 /** Raw attributes */
389 AttrRawStrMap _attrs;
390 /** Uncompiled attributes with predicate. */
391 std::set<AttrMatchData> _uncompiledPredicated;
393 /** Sat solver search flags */
397 /** Sat solver status flags */
398 StatusFilter _status_flags;
400 /** Edition condition operand */
402 /** Operator for edition condition */
405 /** Repos to search. */
408 /** Kinds to search */
414 bool operator<( const PoolQuery::Impl & rhs ) const
416 #define OUTS(A) if ( A != rhs.A ) return A < rhs.A;
419 OUTS( _uncompiledPredicated );
420 OUTS( _flags.get() );
422 OUTS( _status_flags );
424 OUTS( _op.inSwitch() );
431 bool operator==( const PoolQuery::Impl & rhs ) const
433 if ( _flags == rhs._flags
434 // bnc#792901: while libzypp uses exact match mode for a single
435 // package name lock, zypper always uses glob. :(
436 // We unify those two forms to enable zypper to remove zypp locks
437 // without need to actually evaluate the query (which would require
438 // repos to be loaded).
439 || ( ( ( _flags.isModeString() && rhs._flags.isModeGlob() )
440 || ( _flags.isModeGlob() && rhs._flags.isModeString() ) )
442 && _attrs.size() == 1
443 && _attrs.begin()->first == sat::SolvAttr::name ) )
445 return ( _strings == rhs._strings
446 && _attrs == rhs._attrs
447 && _uncompiledPredicated == rhs._uncompiledPredicated
448 && _match_word == rhs._match_word
449 && _status_flags == rhs._status_flags
450 && _edition == rhs._edition
452 && _repos == rhs._repos
453 && _kinds == rhs._kinds );
458 bool operator!=( const PoolQuery::Impl & rhs ) const
459 { return ! operator==( rhs ); }
462 /** Compile the regex.
463 * Basically building the \ref _attrMatchList from strings.
464 * \throws MatchException Any of the exceptions thrown by \ref StrMatcher::compile.
466 void compile() const;
468 /** StrMatcher per attribtue. */
469 mutable AttrMatchList _attrMatchList;
472 /** Join patterns in \a container_r according to \a flags_r into a single \ref StrMatcher.
473 * The \ref StrMatcher returned will be a REGEX if more than one pattern was passed.
475 StrMatcher joinedStrMatcher( const StrContainer & container_r, const Match & flags_r ) const;
478 friend Impl * rwcowClone<Impl>( const Impl * rhs );
479 /** clone for RWCOW_pointer */
481 { return new Impl( *this ); }
484 ///////////////////////////////////////////////////////////////////
488 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
490 bool operator()(const string & str)
496 PoolQuery::StrContainer & _cont;
502 bool operator()(const string & str)
508 void PoolQuery::Impl::compile() const
510 _attrMatchList.clear();
512 if ( _flags.mode() == Match::OTHER ) // this will never succeed...
513 ZYPP_THROW( MatchUnknownModeException( _flags ) );
515 // 'different' - will have to iterate through all and match by ourselves (slow)
516 // 'same' - will pass the compiled string to dataiterator_init
517 // 'one-attr' - will pass it to dataiterator_init
518 // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
523 // create regex; store in rcstrings; if more strings flag regex;
526 ; // A default 'query-all' will be added after all sources are processed.
530 // else if _attrs is not empty but it contains just one attr
531 // for all _strings and _attr[key] strings
532 // create regex; flag 'one-attr'; if more strings flag regex;
533 else if (_attrs.size() == 1)
536 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
537 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
539 _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first, joinedStrMatcher( joined, _flags ) ) );
542 // // MULTIPLE ATTRIBUTES
545 // check whether there are any per-attribute strings
546 bool attrvals_empty = true;
547 for_( ai, _attrs.begin(), _attrs.end() )
549 if ( ai->second.empty() )
551 for_( it, ai->second.begin(), ai->second.end() )
555 attrvals_empty = false;
559 if ( ! attrvals_empty )
563 // chceck whether the per-attribute strings are all the same
564 bool attrvals_thesame = true;
565 AttrRawStrMap::const_iterator ai = _attrs.begin();
566 const StrContainer & set1 = ai->second;
568 for (; ai != _attrs.end(); ++ai)
572 set1.begin(), set1.end(),
573 ai->second.begin(), ai->second.end(),
574 inserter(result, result.begin())/*, ltstr()*/);
577 attrvals_thesame = false;
582 // // THE SAME STRINGS FOR DIFFERENT ATTRS
583 // else if _attrs is not empty but it does not contain strings
584 // for each key in _attrs take all _strings
585 // create regex; store in rcstrings; flag 'same'; if more strings flag regex;
586 if (attrvals_empty || attrvals_thesame)
591 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
595 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
596 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
599 // May use the same StrMatcher for all
600 StrMatcher matcher( joinedStrMatcher( joined, _flags ) );
601 for_( ai, _attrs.begin(), _attrs.end() )
603 _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
607 // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
608 // if _attrs is not empty and it contains non-empty vectors with non-empty strings
609 // for each key in _attrs take all _strings + all _attrs[key] strings
610 // create regex; flag 'different'; if more strings flag regex;
613 for_(ai, _attrs.begin(), _attrs.end())
616 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
617 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
619 _attrMatchList.push_back( AttrMatchData( ai->first, joinedStrMatcher( joined, _flags ) ) );
624 // Now handle any predicated queries
625 if ( ! _uncompiledPredicated.empty() )
628 invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
629 for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
631 if ( it->strMatcher.flags().mode() == Match::OTHER )
634 StrContainer joined( global );
635 const std::string & mstr( it->strMatcher.searchstring() );
636 if ( ! mstr.empty() )
637 joined.insert( mstr );
639 // copy and exchange the StrMatcher
640 AttrMatchData nattr( *it );
641 nattr.strMatcher = joinedStrMatcher( joined, _flags );
642 _attrMatchList.push_back( std::move(nattr) );
647 _attrMatchList.push_back( *it );
652 // If no attributes defined at all, then add 'query all'
653 if ( _attrMatchList.empty() )
655 _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr, joinedStrMatcher( _strings, _flags ) ) );
658 // Finally check here, whether all involved regex compile.
659 for_( it, _attrMatchList.begin(), _attrMatchList.end() )
661 it->strMatcher.compile(); // throws on error
663 //DBG << asString() << endl;
666 ///////////////////////////////////////////////////////////////////
669 /** Escape \a str_r for use in a regex.
670 * \a flags_r determines whether the input string is interpreted
671 * as regex, glob or plain string.
673 std::string rxEscape( std::string str_r, const Match & flags_r )
675 if ( str_r.empty() || flags_r.isModeRegex() )
678 if ( flags_r.isModeGlob() )
679 return str::rxEscapeGlob( std::move(str_r) );
681 return str::rxEscapeStr( std::move(str_r) );
684 ///////////////////////////////////////////////////////////////////
686 StrMatcher PoolQuery::Impl::joinedStrMatcher( const StrContainer & container_r, const Match & flags_r ) const
688 if ( container_r.empty() )
689 return StrMatcher( std::string(), flags_r );
691 if ( container_r.size() == 1 && !_match_word ) // use RX to match words
692 return StrMatcher( *container_r.begin(), flags_r );
694 // Convert to a regex.
695 // Note: Modes STRING and GLOB match whole strings (anchored ^ $)
696 // SUBSTRING and REGEX match substrings (match_word anchores SUBSTRING \b)
697 Match retflags( flags_r );
698 retflags.setModeRegex();
701 if ( flags_r.isModeString() || flags_r.isModeGlob() )
703 else if ( _match_word )
708 for ( const::std::string & s : container_r )
710 ret << sep << rxEscape( s, flags_r );
716 if ( flags_r.isModeString() || flags_r.isModeGlob() )
718 else if ( _match_word )
721 return StrMatcher( ret, retflags );
724 string PoolQuery::Impl::asString() const
729 if ( _kinds.empty() )
733 for(Kinds::const_iterator it = _kinds.begin();
734 it != _kinds.end(); ++it)
740 if ( _repos.empty() )
744 for(StrContainer::const_iterator it = _repos.begin();
745 it != _repos.end(); ++it)
750 o << "version: "<< _op << " " << _edition.asString() << endl;
751 o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
754 o << "string match flags: " << Match(_flags) << endl;
758 for(StrContainer::const_iterator it = _strings.begin();
759 it != _strings.end(); ++it)
763 o << "attributes: " << endl;
764 for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
766 o << "* " << ai->first << ": ";
767 for(StrContainer::const_iterator vi = ai->second.begin();
768 vi != ai->second.end(); ++vi)
773 o << "predicated: " << endl;
774 for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
776 o << "* " << *it << endl;
780 o << "last attribute matcher compiled: " << endl;
781 if ( _attrMatchList.empty() )
783 o << "not yet compiled" << endl;
787 for_( it, _attrMatchList.begin(), _attrMatchList.end() )
789 o << "* " << *it << endl;
795 ///////////////////////////////////////////////////////////////////
797 ///////////////////////////////////////////////////////////////////
799 // CLASS NAME : PoolQuery
801 ///////////////////////////////////////////////////////////////////
803 PoolQuery::PoolQuery()
807 PoolQuery::~PoolQuery()
810 void PoolQuery::addRepo(const std::string &repoalias)
812 if (repoalias.empty())
814 WAR << "ignoring an empty repository alias" << endl;
817 _pimpl->_repos.insert(repoalias);
820 void PoolQuery::addKind(const ResKind & kind)
821 { _pimpl->_kinds.insert(kind); }
823 void PoolQuery::addString(const string & value)
824 { _pimpl->_strings.insert(value); }
826 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
827 { _pimpl->_attrs[attr].insert(value); }
829 void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
830 { return addDependency( attr, name, op, edition, Arch_empty ); }
832 void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
834 // SolvAttr::name with explicit 'kind:name' will overwrite the default _kinds
835 ResKind explicitKind;
836 if ( attr == sat::SolvAttr::name ) explicitKind = ResKind::explicitBuiltin( name );
838 switch ( op.inSwitch() )
840 case Rel::ANY_e: // no additional constraint on edition.
841 if ( arch.empty() && !explicitKind ) // no additional constraint on arch/kind
843 addAttribute( attr, name );
848 case Rel::NONE_e: // will never match.
851 default: // go and add the predicated query (uncompiled)
855 // Match::OTHER indicates need to compile
856 // (merge global search strings into name).
857 AttrMatchData attrMatchData( attr );
859 attrMatchData.strMatcher = StrMatcher( name, Match::OTHER );
862 // ResKind::explicitBuiltin call above asserts the presence of the ':' in name
863 attrMatchData.strMatcher = StrMatcher( strchr( name.c_str(), ':')+1, Match::OTHER );
864 attrMatchData.kindPredicate = explicitKind;
867 if ( isDependencyAttribute( attr ) )
868 attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
870 attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) );
872 _pimpl->_uncompiledPredicated.insert( attrMatchData );
875 void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
877 CapDetail cap( cap_r );
878 if ( ! cap.isSimple() ) // will never match.
881 // Matches STRING per default. (won't get compiled!)
882 AttrMatchData attrMatchData( attr, StrMatcher( cap.name().asString() ) );
884 if ( isDependencyAttribute( attr ) )
885 attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
887 attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
889 _pimpl->_uncompiledPredicated.insert( attrMatchData );
892 void PoolQuery::setEdition(const Edition & edition, const Rel & op)
894 _pimpl->_edition = edition;
898 void PoolQuery::setMatchSubstring() { _pimpl->_flags.setModeSubstring(); _pimpl->_match_word = false; }
899 void PoolQuery::setMatchExact() { _pimpl->_flags.setModeString(); _pimpl->_match_word = false; }
900 void PoolQuery::setMatchRegex() { _pimpl->_flags.setModeRegex(); _pimpl->_match_word = false; }
901 void PoolQuery::setMatchGlob() { _pimpl->_flags.setModeGlob(); _pimpl->_match_word = false; }
902 void PoolQuery::setMatchWord() { _pimpl->_flags.setModeSubstring(); _pimpl->_match_word = true; }
904 Match PoolQuery::flags() const
905 { return _pimpl->_flags; }
906 void PoolQuery::setFlags( const Match & flags )
907 { _pimpl->_flags = flags; }
910 void PoolQuery::setInstalledOnly()
911 { _pimpl->_status_flags = INSTALLED_ONLY; }
912 void PoolQuery::setUninstalledOnly()
913 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
914 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
915 { _pimpl->_status_flags = flags; }
918 const PoolQuery::StrContainer &
919 PoolQuery::strings() const
920 { return _pimpl->_strings; }
922 const PoolQuery::AttrRawStrMap &
923 PoolQuery::attributes() const
924 { return _pimpl->_attrs; }
926 const PoolQuery::StrContainer &
927 PoolQuery::attribute(const sat::SolvAttr & attr) const
929 static const PoolQuery::StrContainer nocontainer;
930 AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
931 return it != _pimpl->_attrs.end() ? it->second : nocontainer;
934 const Edition PoolQuery::edition() const
935 { return _pimpl->_edition; }
936 const Rel PoolQuery::editionRel() const
937 { return _pimpl->_op; }
940 const PoolQuery::Kinds &
941 PoolQuery::kinds() const
942 { return _pimpl->_kinds; }
944 const PoolQuery::StrContainer &
945 PoolQuery::repos() const
946 { return _pimpl->_repos; }
949 bool PoolQuery::caseSensitive() const
950 { return !_pimpl->_flags.test( Match::NOCASE ); }
951 void PoolQuery::setCaseSensitive( bool value )
952 { _pimpl->_flags.turn( Match::NOCASE, !value ); }
954 bool PoolQuery::filesMatchFullPath() const
955 { return _pimpl->_flags.test( Match::FILES ); }
956 void PoolQuery::setFilesMatchFullPath( bool value )
957 { _pimpl->_flags.turn( Match::FILES, value ); }
959 bool PoolQuery::matchExact() const { return _pimpl->_flags.isModeString(); }
960 bool PoolQuery::matchSubstring() const { return _pimpl->_flags.isModeSubstring() && !_pimpl->_match_word; }
961 bool PoolQuery::matchGlob() const { return _pimpl->_flags.isModeGlob(); }
962 bool PoolQuery::matchRegex() const { return _pimpl->_flags.isModeRegex(); }
963 bool PoolQuery::matchWord() const { return _pimpl->_flags.isModeSubstring() && _pimpl->_match_word; }
965 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
966 { return _pimpl->_status_flags; }
968 bool PoolQuery::empty() const
970 try { return begin() == end(); }
971 catch (const Exception & ex) {}
975 PoolQuery::size_type PoolQuery::size() const
980 for_( it, begin(), end() )
984 catch (const Exception & ex) {}
988 void PoolQuery::execute(ProcessResolvable fnc)
989 { invokeOnEach( begin(), end(), fnc); }
992 /*DEPRECATED LEGACY:*/void PoolQuery::setRequireAll( bool ) {}
993 /*DEPRECATED LEGACY:*/bool PoolQuery::requireAll() const { return false; }
995 ///////////////////////////////////////////////////////////////////
997 // CLASS NAME : PoolQuery::Attr
1000 * represents all atributes in PoolQuery except SolvAtributes, which are
1001 * used as is (not needed extend anything if someone adds new solv attr)
1003 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
1006 friend class IdStringType<PoolQueryAttr>;
1013 explicit PoolQueryAttr( const char* cstr_r )
1017 explicit PoolQueryAttr( const std::string & str_r )
1021 // unknown atributes
1022 static const PoolQueryAttr noAttr;
1024 // PoolQuery's own attributes
1025 static const PoolQueryAttr repoAttr;
1026 static const PoolQueryAttr kindAttr;
1027 static const PoolQueryAttr stringAttr;
1028 static const PoolQueryAttr stringTypeAttr;
1029 static const PoolQueryAttr requireAllAttr; // LEAGACY: attribute was defined but never implemented.
1030 static const PoolQueryAttr caseSensitiveAttr;
1031 static const PoolQueryAttr installStatusAttr;
1032 static const PoolQueryAttr editionAttr;
1033 static const PoolQueryAttr complexAttr;
1036 const PoolQueryAttr PoolQueryAttr::noAttr;
1038 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
1039 const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
1040 const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
1041 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
1042 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all"); // LEAGACY: attribute was defined but never implemented.
1043 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
1044 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
1045 const PoolQueryAttr PoolQueryAttr::editionAttr("version");
1046 const PoolQueryAttr PoolQueryAttr::complexAttr("complex");
1048 class StringTypeAttr : public IdStringType<PoolQueryAttr>
1050 friend class IdStringType<StringTypeAttr>;
1055 explicit StringTypeAttr( const char* cstr_r )
1057 explicit StringTypeAttr( const std::string & str_r )
1060 static const StringTypeAttr noAttr;
1062 static const StringTypeAttr exactAttr;
1063 static const StringTypeAttr substringAttr;
1064 static const StringTypeAttr regexAttr;
1065 static const StringTypeAttr globAttr;
1066 static const StringTypeAttr wordAttr;
1069 const StringTypeAttr StringTypeAttr::noAttr;
1071 const StringTypeAttr StringTypeAttr::exactAttr("exact");
1072 const StringTypeAttr StringTypeAttr::substringAttr("substring");
1073 const StringTypeAttr StringTypeAttr::regexAttr("regex");
1074 const StringTypeAttr StringTypeAttr::globAttr("glob");
1075 const StringTypeAttr StringTypeAttr::wordAttr("word");
1077 ///////////////////////////////////////////////////////////////////
1080 //\TODO maybe ctor with stream can be usefull
1081 //\TODO let it throw, let it throw, let it throw.
1082 bool PoolQuery::recover( istream &str, char delim )
1084 bool finded_something = false; //indicates some atributes is finded
1090 getline( str, s, delim );
1092 if ((!s.empty()) && s[0]=='#') //comment
1097 string::size_type pos = s.find(':');
1098 if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
1100 if (finded_something) //is first blank line after record?
1110 finded_something = true;
1112 string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
1113 string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
1115 PoolQueryAttr attribute( attrName );
1117 if ( attribute==PoolQueryAttr::repoAttr )
1119 addRepo( attrValue );
1121 /* some backwards compatibility */
1122 else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
1124 addKind( ResKind(attrValue) );
1126 else if ( attribute==PoolQueryAttr::stringAttr
1127 || attribute=="global_string")
1129 addString( attrValue );
1131 else if ( attribute==PoolQueryAttr::stringTypeAttr
1132 || attribute=="string_type" )
1134 StringTypeAttr s(attrValue);
1135 if( s == StringTypeAttr::regexAttr )
1139 else if ( s == StringTypeAttr::globAttr )
1143 else if ( s == StringTypeAttr::exactAttr )
1147 else if ( s == StringTypeAttr::substringAttr )
1149 setMatchSubstring();
1151 else if ( s == StringTypeAttr::wordAttr )
1155 else if ( s == StringTypeAttr::noAttr )
1157 WAR << "unknown string type " << attrValue << endl;
1161 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
1164 else if ( attribute==PoolQueryAttr::requireAllAttr )
1166 // LEAGACY: attribute was defined but never implemented.
1167 // Actually it should not occur outside our testcases.
1169 else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
1171 if ( str::strToTrue(attrValue) )
1173 setCaseSensitive(true);
1175 else if ( !str::strToFalse(attrValue) )
1177 setCaseSensitive(false);
1181 WAR << "unknown boolean value " << attrValue << endl;
1184 else if ( attribute==PoolQueryAttr::installStatusAttr )
1186 if( attrValue == "all" )
1188 setStatusFilterFlags( ALL );
1190 else if( attrValue == "installed" )
1194 else if( attrValue == "not-installed" )
1196 setUninstalledOnly();
1200 WAR << "Unknown value for install status " << attrValue << endl;
1203 else if ( attribute == PoolQueryAttr::editionAttr)
1205 string::size_type pos;
1207 if (attrValue.find_first_of("=<>!") == 0)
1209 pos = attrValue.find_last_of("=<>");
1210 rel = Rel(attrValue.substr(0, pos+1));
1211 attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
1214 setEdition(Edition(attrValue), rel);
1216 else if ( attribute == PoolQueryAttr::complexAttr )
1220 _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
1222 catch ( const Exception & err )
1224 WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
1228 else if ( attribute==PoolQueryAttr::noAttr )
1230 WAR << "empty attribute name" << endl;
1234 string s = attrName;
1235 str::replaceAll( s,"_",":" );
1237 if ( a == SolvAttr::name || isDependencyAttribute( a ) )
1239 Capability c( attrValue );
1241 if ( d.isVersioned() )
1242 addDependency( a, d.name().asString(), d.op(), d.ed() );
1244 addDependency( a, attrValue );
1247 addAttribute( a, attrValue );
1252 // OLD STYLE VERSIONED LOCKS:
1253 // solvable_name: kernel
1256 // NEW STYLE VERSIONED LOCKS:
1257 // complex: AttrMatchData solvable:name kernel C SolvableRange\ >\ 1\ \"\"
1259 // solvable_name: kernel > 1
1261 // Semantically equivalent as locks, but due to the different syntax
1262 // the complex lock is wrongly handled by zypper.
1264 // bsc#1112911: Unfortunately all styles are found in real-life locks-files.
1265 // libzypp will try to make sure, when parsing the locks-file, that complex
1266 // locks are rewritten into to OLD STYLE queries zypper can handle.
1267 if ( !_pimpl->_attrs.count(SolvAttr::name) && _pimpl->_uncompiledPredicated.size() == 1 )
1269 // No OLD STYLE lock for SolvAttr::name and exactly one complex lock...
1270 const AttrMatchData & attrmatch { *_pimpl->_uncompiledPredicated.begin() };
1271 if ( attrmatch.attr == SolvAttr::name && attrmatch.strMatcher.flags().mode() == Match::OTHER )
1273 // ...for SolvAttr::name and following the global search flags.
1274 // A candidate for a rewrite?
1276 std::vector<std::string> words;
1277 str::splitEscaped( attrmatch.predicateStr, std::back_inserter(words) );
1278 if ( words.size() < 4 || words[3].empty() )
1280 // We have _NO_ arch rule in the complex predicate, so we can simplify it.
1282 // NOTE: AFAIK it's not possible to create (or have created) a complex lock
1283 // with arch rule with zypper means. Nevertheless, in case such a rule made it
1284 // into a locks file, it's better to have a strange looking 'zypper locks' list
1285 // than to lock the wrong packages.
1286 // (and remember that you can't use "addAttribute( SolvAttr::arch, ... )" because
1287 // attributes are `OR`ed)
1290 if ( attrmatch.kindPredicate )
1292 _pimpl->_kinds.clear(); // an explicit kind overwrites any global one
1293 addKind( attrmatch.kindPredicate );
1297 addAttribute( SolvAttr::name, attrmatch.strMatcher.searchstring() );
1300 std::vector<std::string> words;
1301 str::splitEscaped( attrmatch.predicateStr, std::back_inserter(words) );
1302 if ( ! words.empty() )
1304 if ( words[0] == "EditionRange" || words[0] == "SolvableRange" )
1306 setEdition( Edition(words[2]), Rel(words[1]) );
1310 // finally remove the complex lock
1311 _pimpl->_uncompiledPredicated.clear();
1316 return finded_something;
1319 void PoolQuery::serialize( ostream &str, char delim ) const
1323 //iterate thrue all settings and write it
1324 static const zypp::PoolQuery q; //not save default options, so create default query example
1326 for_( it, repos().begin(), repos().end() )
1328 str << "repo: " << *it << delim ;
1331 for_( it, kinds().begin(), kinds().end() )
1333 str << PoolQueryAttr::kindAttr.asString() << ": "
1334 << it->idStr() << delim ;
1337 if (editionRel() != Rel::ANY && edition() != Edition::noedition)
1338 str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
1340 if (matchMode()!=q.matchMode())
1342 switch( matchMode() )
1345 str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
1347 case Match::SUBSTRING:
1348 str << PoolQueryAttr::stringTypeAttr.asString()
1349 << ": substring" << delim;
1352 str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
1355 str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
1358 WAR << "unknown match type " << matchMode() << endl;
1362 if( caseSensitive() != q.caseSensitive() )
1364 str << "case_sensitive: ";
1365 if (caseSensitive())
1367 str << "on" << delim;
1371 str << "off" << delim;
1375 if( statusFilterFlags() != q.statusFilterFlags() )
1377 switch( statusFilterFlags() )
1380 str << "install_status: all" << delim;
1382 case INSTALLED_ONLY:
1383 str << "install_status: installed" << delim;
1385 case UNINSTALLED_ONLY:
1386 str << "install_status: not-installed" << delim;
1391 for_( it, strings().begin(), strings().end() )
1393 str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
1396 for_( it, attributes().begin(), attributes().end() )
1398 string s = it->first.asString();
1399 str::replaceAll(s,":","_");
1400 for_( it2,it->second.begin(),it->second.end() )
1402 str << s <<": "<< *it2 << delim;
1406 for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
1408 str << "complex: "<< it->serialize() << delim;
1411 //separating delim - protection
1415 string PoolQuery::asString() const
1416 { return _pimpl->asString(); }
1418 ostream & operator<<( ostream & str, const PoolQuery & obj )
1419 { return str << obj.asString(); }
1421 std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
1422 { return dumpRange( str << obj, obj.begin(), obj.end() ); }
1424 bool PoolQuery::operator==( const PoolQuery & rhs ) const
1425 { return *_pimpl == *rhs._pimpl; }
1427 bool PoolQuery::operator<( const PoolQuery & rhs ) const
1428 { return *_pimpl < *rhs._pimpl; }
1430 ///////////////////////////////////////////////////////////////////
1432 { /////////////////////////////////////////////////////////////////
1434 ///////////////////////////////////////////////////////////////////
1436 // CLASS NAME : PoolQueryMatcher
1438 /** Store \ref PoolQuery settings and assist \ref PoolQueryIterator.
1440 * Basically the matcher performs a base query, which should preselect
1441 * candidates for a match. And has some filter conditions on top of it.
1442 * Query and fileter depend on the \ref PoolQuery settings.
1444 * Matcher must be stateless, as it is shared between multiple
1445 * \ref PoolQueryIterator instances.
1447 * If \ref base_iterator is at the \ref end, \ref advance moves it
1448 * to the first match. Otherwise advance moves to the next match, or
1449 * to the \ref end, if there is no more match.
1451 * \note The original implementation treated an empty search string as
1452 * <it>"match always"</it>. We stay compatible.
1454 class PoolQueryMatcher
1457 typedef sat::LookupAttr::iterator base_iterator;
1460 const base_iterator & end() const
1462 static base_iterator _end;
1466 bool advance( base_iterator & base_r ) const
1468 if ( base_r == end() )
1469 base_r = startNewQyery(); // first candidate
1472 base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
1473 ++base_r; // advance to next candidate
1476 while ( base_r != end() )
1478 if ( isAMatch( base_r ) )
1480 // No match: try next
1486 /** Provide all matching attributes within this solvable.
1489 void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const
1491 if ( base_r == end() )
1494 sat::Solvable inSolvable( base_r.inSolvable() );
1496 if ( _attrMatchList.size() == 1 )
1498 // base_r is already on the 1st matching attribute!
1499 // String matching is done by the base iterator. We must check the predicate here.
1500 // Let's see if there are more matches for this solvable:
1501 base_iterator base( base_r );
1502 base.stayInThisSolvable(); // avoid discarding matches we found far away from here.
1503 return_r.push_back( base );
1505 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
1506 for ( ++base; base.inSolvable() == inSolvable; ++base ) // safe even if base == end()
1508 if ( ! predicate || predicate( base ) )
1509 return_r.push_back( base );
1514 // Here: search all attributes ;(
1515 for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
1517 const AttrMatchData & matchData( *mi );
1518 sat::LookupAttr q( matchData.attr, inSolvable );
1519 if ( matchData.strMatcher ) // an empty searchstring matches always
1520 q.setStrMatcher( matchData.strMatcher );
1522 if ( ! q.empty() ) // there are matches.
1524 // now check any predicate:
1525 const AttrMatchData::Predicate & predicate( matchData.predicate );
1526 for_( it, q.begin(), q.end() )
1528 if ( ! predicate || predicate( it ) )
1529 return_r.push_back( it );
1537 /** Ctor stores the \ref PoolQuery settings.
1538 * \throw MatchException Any of the exceptions thrown by \ref PoolQuery::Impl::compile.
1540 PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
1544 // Repo restriction:
1545 sat::Pool satpool( sat::Pool::instance() );
1547 for_( it, query_r->_repos.begin(), query_r->_repos.end() )
1549 Repository r( satpool.reposFind( *it ) );
1553 _neverMatchRepo = true;
1555 // _neverMatchRepo: we just need to catch the case that no repo
1556 // matched, so we'd interpret the empty list as 'take from all'
1557 if ( _neverMatchRepo && ! _repos.empty() )
1558 _neverMatchRepo = false;
1560 // Kind restriction:
1561 _kinds = query_r->_kinds;
1562 // Edition restriction:
1564 _edition = query_r->_edition;
1565 // Status restriction:
1566 _status_flags = query_r->_status_flags;
1568 _attrMatchList = query_r->_attrMatchList;
1575 /** Initialize a new base query. */
1576 base_iterator startNewQyery() const
1580 if ( _neverMatchRepo )
1583 // Repo restriction:
1584 if ( _repos.size() == 1 )
1585 q.setRepo( *_repos.begin() );
1586 // else: handled in isAMatch.
1588 // Attribute restriction:
1589 if ( _attrMatchList.size() == 1 ) // all (SolvAttr::allAttr) or 1 attr
1591 const AttrMatchData & matchData( _attrMatchList.front() );
1592 q.setAttr( matchData.attr );
1593 if ( matchData.strMatcher ) // empty searchstring matches always
1594 q.setStrMatcher( matchData.strMatcher );
1596 else // more than 1 attr (but not all)
1598 // no restriction, it's all handled in isAMatch.
1599 q.setAttr( sat::SolvAttr::allAttr );
1606 /** Check whether we are on a match.
1608 * The check covers the whole Solvable, not just the current
1609 * attribute \c base_r points to. If there's no match, also
1610 * prepare \c base_r to advance appropriately. If there is
1611 * a match, simply return \c true. \ref advance always moves
1612 * to the next Solvable if there was a match.
1614 * \note: Caller asserts we're not at \ref end.
1616 bool isAMatch( base_iterator & base_r ) const
1618 /////////////////////////////////////////////////////////////////////
1619 Repository inRepo( base_r.inRepo() );
1620 // Status restriction:
1622 && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
1624 base_r.nextSkipRepo();
1627 // Repo restriction:
1628 if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
1630 base_r.nextSkipRepo();
1633 /////////////////////////////////////////////////////////////////////
1634 sat::Solvable inSolvable( base_r.inSolvable() );
1635 // Edition restriction:
1636 if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
1638 base_r.nextSkipSolvable();
1642 // Kind restriction:
1643 // Delay the decision to nextSkipSolvable and return false, as there may be
1644 // some explicit kind:name predicate which overrules the global kinds.
1645 bool globalKindOk =( _kinds.empty() || inSolvable.isKind( _kinds.begin(), _kinds.end() ) );
1647 /////////////////////////////////////////////////////////////////////
1648 // string and predicate matching:
1650 if ( _attrMatchList.size() == 1 )
1652 // String matching was done by the base iterator.
1653 // Now check any predicate:
1654 const AttrMatchData & matchData( _attrMatchList.front() );
1656 if ( matchData.kindPredicate )
1658 if ( matchData.kindPredicate != inSolvable.kind() )
1660 base_r.nextSkipSolvable(); // this matchData will never match in this solvable
1664 else if ( !globalKindOk )
1665 return false; // only matching kindPredicate could overwrite this
1667 if ( !matchData.predicate || matchData.predicate( base_r ) )
1670 return false; // no skip as there may be more occurrences in this solvable of this attr.
1673 // Here: search all attributes ;(
1674 for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
1676 const AttrMatchData & matchData( *mi );
1678 if ( matchData.kindPredicate )
1680 if ( matchData.kindPredicate != inSolvable.kind() )
1681 continue; // this matchData does not apply
1683 else if ( !globalKindOk )
1684 continue; // only matching kindPredicate could overwrite this
1686 sat::LookupAttr q( matchData.attr, inSolvable );
1687 if ( matchData.strMatcher ) // an empty searchstring matches always
1688 q.setStrMatcher( matchData.strMatcher );
1690 if ( ! q.empty() ) // there are matches.
1692 // now check any predicate:
1693 const AttrMatchData::Predicate & predicate( matchData.predicate );
1696 for_( it, q.begin(), q.end() )
1698 if ( predicate( it ) )
1706 base_r.nextSkipSolvable();
1711 /** Repositories include in the search. */
1712 std::set<Repository> _repos;
1713 DefaultIntegral<bool,false> _neverMatchRepo;
1714 /** Resolvable kinds to include. */
1715 std::set<ResKind> _kinds;
1716 /** Edition filter. */
1719 /** Installed status filter flags. \see PoolQuery::StatusFilter */
1721 /** StrMatcher per attribtue. */
1722 AttrMatchList _attrMatchList;
1724 ///////////////////////////////////////////////////////////////////
1726 void PoolQueryIterator::increment()
1728 // matcher restarts if at end! It is called from the ctor
1729 // to get the 1st match. But if the end is reached, it should
1730 // be deleted, otherwise we'd start over again.
1734 _matches.reset(); // invalidate old matches
1735 if ( ! _matcher->advance( base_reference() ) )
1739 const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
1747 static const Matches _none;
1751 _matches.reset( new Matches );
1752 _matcher->matchDetail( base_reference(), *_matches );
1756 std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
1759 if ( ! obj.matchesEmpty() )
1761 for_( it, obj.matchesBegin(), obj.matchesEnd() )
1763 str << endl << " " << it->inSolvAttr() << "\t" << it->asString();
1769 ///////////////////////////////////////////////////////////////////
1770 } //namespace detail
1771 ///////////////////////////////////////////////////////////////////
1773 detail::PoolQueryIterator PoolQuery::begin() const
1775 return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
1778 /////////////////////////////////////////////////////////////////
1780 ///////////////////////////////////////////////////////////////////