1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PoolQuery.cc
15 #include "zypp/base/Gettext.h"
16 #include "zypp/base/Logger.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/sat/AttrMatcher.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 /** Match data per attribtue.
44 * This includes the attribute itself, an optional \ref sat::AttrMatcher
45 * to restrict the query to certain string values, and an optional
46 * boolean \ref Predicate that may apply further restrictions that can
47 * not be expressed by the \ref attrMatcher.
49 * Example for such a \ref predicate would be an additional edition range
50 * check whan looking for dependencies. The \ref attrMatcher would
51 * find potential matches by looking at the dependencies name, the
52 * predicate will then check the edition ranges.
54 * As the \ref predicate takes an iterator pointing to the current
55 * match, it's also suitable for sub-structure (flexarray) inspection
56 * (\see \ref sat::LookupAttr::iterator::solvAttrSubEntry).
60 typedef function<bool(sat::LookupAttr::iterator)> Predicate;
62 static bool always( sat::LookupAttr::iterator ) { return true; }
63 static bool never( sat::LookupAttr::iterator ) { return false; }
65 AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r )
67 , attrMatcher( attrMatcher_r )
71 sat::AttrMatcher attrMatcher;
75 std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
77 return str << obj.attr << ": " << obj.attrMatcher << ( obj.predicate ? " (+predicate)" : "" );
80 typedef std::list<AttrMatchData> AttrMatchList;
82 } /////////////////////////////////////////////////////////////////
84 ///////////////////////////////////////////////////////////////////
86 ///////////////////////////////////////////////////////////////////
88 // CLASS NAME : PoolQuery::Impl
95 : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
105 /** String representation */
106 string asString() const;
108 /** \name Raw query options. */
110 /** Raw search strings. */
111 StrContainer _strings;
112 /** Raw attributes */
113 AttrRawStrMap _attrs;
115 /** Sat solver search flags */
120 /** Sat solver status flags */
121 StatusFilter _status_flags;
123 /** Edition condition operand */
125 /** Operator for edition condition */
128 /** Repos to search. */
131 /** Kinds to search */
136 /** Compile the regex.
137 * Basically building the \ref _attrMatchList from strings.
138 * \throws MatchException Any of the exceptions thrown by \ref AttrMatcher::compile.
140 void compile() const;
142 /** AttrMatcher per attribtue. */
143 mutable AttrMatchList _attrMatchList;
146 /** Pass flags from \ref compile, as they may have been changed. */
147 string createRegex( const StrContainer & container, const Match & flags ) const;
150 friend Impl * rwcowClone<Impl>( const Impl * rhs );
151 /** clone for RWCOW_pointer */
153 { return new Impl( *this ); }
159 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
161 bool operator()(const string & str)
167 PoolQuery::StrContainer & _cont;
173 bool operator()(const string & str)
179 void PoolQuery::Impl::compile() const
181 _attrMatchList.clear();
183 Match cflags( _flags );
184 if ( cflags.mode() == Match::OTHER) // this will never succeed...
185 ZYPP_THROW( MatchUnknownModeException( cflags ) );
187 /** Compiled search strings. */
191 // 'different' - will have to iterate through all and match by ourselves (slow)
192 // 'same' - will pass the compiled string to dataiterator_init
193 // 'one-attr' - will pass it to dataiterator_init
194 // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
199 // create regex; store in rcstrings; if more strings flag regex;
202 rcstrings = createRegex(_strings, cflags);
203 if (_strings.size() > 1) // switch to regex for multiple strings
204 cflags.setModeRegex();
205 _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
206 sat::AttrMatcher( rcstrings, cflags ) ) );
210 // else if _attrs is not empty but it contains just one attr
211 // for all _strings and _attr[key] strings
212 // create regex; flag 'one-attr'; if more strings flag regex;
213 else if (_attrs.size() == 1)
216 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
217 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
218 rcstrings = createRegex(joined, cflags);
219 if (joined.size() > 1) // switch to regex for multiple strings
220 cflags.setModeRegex();
221 _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
222 sat::AttrMatcher( rcstrings, cflags ) ) );
225 // // MULTIPLE ATTRIBUTES
228 // check whether there are any per-attribute strings
229 bool attrvals_empty = true;
230 for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
231 if (!ai->second.empty())
232 for(StrContainer::const_iterator it = ai->second.begin();
233 it != ai->second.end(); it++)
236 attrvals_empty = false;
237 goto attremptycheckend;
241 // chceck whether the per-attribute strings are all the same
242 bool attrvals_thesame = true;
243 AttrRawStrMap::const_iterator ai = _attrs.begin();
244 const StrContainer & set1 = ai->second;
246 for (; ai != _attrs.end(); ++ai)
250 set1.begin(), set1.end(),
251 ai->second.begin(), ai->second.end(),
252 inserter(result, result.begin())/*, ltstr()*/);
255 attrvals_thesame = false;
260 // // THE SAME STRINGS FOR DIFFERENT ATTRS
261 // else if _attrs is not empty but it does not contain strings
262 // for each key in _attrs take all _strings
263 // create regex; store in rcstrings; flag 'same'; if more strings flag regex;
264 if (attrvals_empty || attrvals_thesame)
269 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
270 rcstrings = createRegex(joined, cflags);
274 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
275 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
276 rcstrings = createRegex(joined, cflags);
278 if (joined.size() > 1) // switch to regex for multiple strings
279 cflags.setModeRegex();
280 // May use the same AttrMatcher for all
281 sat::AttrMatcher matcher( rcstrings, cflags );
282 for_( ai, _attrs.begin(), _attrs.end() )
284 _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
288 // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
289 // if _attrs is not empty and it contains non-empty vectors with non-empty strings
290 // for each key in _attrs take all _strings + all _attrs[key] strings
291 // create regex; flag 'different'; if more strings flag regex;
294 for_(ai, _attrs.begin(), _attrs.end())
297 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
298 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
299 string s = createRegex(joined, cflags);
300 if (joined.size() > 1) // switch to regex for multiple strings
301 cflags.setModeRegex();
302 _attrMatchList.push_back( AttrMatchData( ai->first,
303 sat::AttrMatcher( s, cflags ) ) );
308 // Check here, whether all involved regex compile.
309 for_( it, _attrMatchList.begin(), _attrMatchList.end() )
311 it->attrMatcher.compile(); // throws on error
313 //DBG << asString() << endl;
318 * Converts '*' and '?' wildcards within str into their regex equivalents.
320 static string wildcards2regex(const string & str)
322 string regexed = str;
324 string r_all(".*"); // regex equivalent of '*'
325 string r_one("."); // regex equivalent of '?'
326 string::size_type pos;
328 // replace all "*" in input with ".*"
329 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
330 regexed = regexed.replace(pos, 1, r_all);
332 // replace all "?" in input with "."
333 for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
334 regexed = regexed.replace(pos, 1, r_one);
339 string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const
341 //! macro for word boundary tags for regexes
342 #define WB (_match_word ? string("\\b") : string())
345 if (container.empty())
348 if (container.size() == 1)
350 return WB + *container.begin() + WB;
355 bool use_wildcards = flags.isModeGlob();
356 StrContainer::const_iterator it = container.begin();
360 tmp = wildcards2regex(*it);
366 if ( ! flags.isModeString() ) // not match exact
367 tmp += ".*" + WB + tmp;
368 rstr = "(?=" + tmp + ")";
372 if ( flags.isModeString() || flags.isModeGlob() )
374 rstr += WB + "(" + tmp;
379 for (; it != container.end(); ++it)
382 tmp = wildcards2regex(*it);
388 if ( ! flags.isModeString() ) // not match exact
389 tmp += ".*" + WB + tmp;
390 rstr += "(?=" + tmp + ")";
400 if ( ! flags.isModeString() ) // not match exact
406 if ( flags.isModeString() || flags.isModeGlob() )
414 string PoolQuery::Impl::asString() const
419 if ( _kinds.empty() )
423 for(Kinds::const_iterator it = _kinds.begin();
424 it != _kinds.end(); ++it)
430 if ( _repos.empty() )
434 for(StrContainer::const_iterator it = _repos.begin();
435 it != _repos.end(); ++it)
440 o << "version: "<< _op << " " << _edition.asString() << endl;
441 o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
444 o << "string match flags: " << Match(_flags) << endl;
448 for(StrContainer::const_iterator it = _strings.begin();
449 it != _strings.end(); ++it)
453 o << "attributes: " << endl;
454 for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
456 o << "* " << ai->first << ": ";
457 for(StrContainer::const_iterator vi = ai->second.begin();
458 vi != ai->second.end(); ++vi)
464 o << "last attribute matcher compiled: " << endl;
465 if ( _attrMatchList.empty() )
467 o << "not yet compiled" << endl;
471 for_( it, _attrMatchList.begin(), _attrMatchList.end() )
473 o << "* " << *it << endl;
479 ///////////////////////////////////////////////////////////////////
481 ///////////////////////////////////////////////////////////////////
483 // CLASS NAME : PoolQuery
485 ///////////////////////////////////////////////////////////////////
487 PoolQuery::PoolQuery()
491 PoolQuery::~PoolQuery()
494 void PoolQuery::addRepo(const std::string &repoalias)
496 if (repoalias.empty())
498 WAR << "ignoring an empty repository alias" << endl;
501 _pimpl->_repos.insert(repoalias);
505 void PoolQuery::addKind(const ResKind & kind)
506 { _pimpl->_kinds.insert(kind); }
509 void PoolQuery::addString(const string & value)
510 { _pimpl->_strings.insert(value); }
513 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
514 { _pimpl->_attrs[attr].insert(value); }
517 void PoolQuery::setEdition(const Edition & edition, const Rel & op)
519 _pimpl->_edition = edition;
523 void PoolQuery::setMatchSubstring() { _pimpl->_flags.setModeSubstring(); }
524 void PoolQuery::setMatchExact() { _pimpl->_flags.setModeString(); }
525 void PoolQuery::setMatchRegex() { _pimpl->_flags.setModeRegex(); }
526 void PoolQuery::setMatchGlob() { _pimpl->_flags.setModeGlob(); }
527 void PoolQuery::setMatchWord()
529 _pimpl->_match_word = true;
530 _pimpl->_flags.setModeRegex();
533 Match PoolQuery::flags() const
534 { return _pimpl->_flags; }
535 void PoolQuery::setFlags( const Match & flags )
536 { _pimpl->_flags = flags; }
539 void PoolQuery::setInstalledOnly()
540 { _pimpl->_status_flags = INSTALLED_ONLY; }
541 void PoolQuery::setUninstalledOnly()
542 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
543 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
544 { _pimpl->_status_flags = flags; }
547 void PoolQuery::setRequireAll(bool require_all)
548 { _pimpl->_require_all = require_all; }
551 const PoolQuery::StrContainer &
552 PoolQuery::strings() const
553 { return _pimpl->_strings; }
555 const PoolQuery::AttrRawStrMap &
556 PoolQuery::attributes() const
557 { return _pimpl->_attrs; }
559 const PoolQuery::StrContainer &
560 PoolQuery::attribute(const sat::SolvAttr & attr) const
562 static const PoolQuery::StrContainer nocontainer;
563 AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
564 return it != _pimpl->_attrs.end() ? it->second : nocontainer;
567 const Edition PoolQuery::edition() const
568 { return _pimpl->_edition; }
569 const Rel PoolQuery::editionRel() const
570 { return _pimpl->_op; }
573 const PoolQuery::Kinds &
574 PoolQuery::kinds() const
575 { return _pimpl->_kinds; }
577 const PoolQuery::StrContainer &
578 PoolQuery::repos() const
579 { return _pimpl->_repos; }
582 bool PoolQuery::caseSensitive() const
583 { return !_pimpl->_flags.test( Match::NOCASE ); }
584 void PoolQuery::setCaseSensitive( bool value )
585 { _pimpl->_flags.turn( Match::NOCASE, !value ); }
587 bool PoolQuery::filesMatchFullPath() const
588 { return _pimpl->_flags.test( Match::FILES ); }
589 void PoolQuery::setFilesMatchFullPath( bool value )
590 { _pimpl->_flags.turn( Match::FILES, value ); }
592 bool PoolQuery::matchExact() const { return _pimpl->_flags.isModeString(); }
593 bool PoolQuery::matchSubstring() const { return _pimpl->_flags.isModeSubstring(); }
594 bool PoolQuery::matchGlob() const { return _pimpl->_flags.isModeGlob(); }
595 bool PoolQuery::matchRegex() const { return _pimpl->_flags.isModeRegex(); }
597 bool PoolQuery::matchWord() const
598 { return _pimpl->_match_word; }
600 bool PoolQuery::requireAll() const
601 { return _pimpl->_require_all; }
603 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
604 { return _pimpl->_status_flags; }
606 bool PoolQuery::empty() const
608 try { return begin() == end(); }
609 catch (const Exception & ex) {}
613 PoolQuery::size_type PoolQuery::size() const
618 for_( it, begin(), end() )
622 catch (const Exception & ex) {}
626 void PoolQuery::execute(ProcessResolvable fnc)
627 { invokeOnEach( begin(), end(), fnc); }
630 ///////////////////////////////////////////////////////////////////
632 // CLASS NAME : PoolQuery::Attr
635 * represents all atributes in PoolQuery except SolvAtributes, which are
636 * used as is (not needed extend anything if someone adds new solv attr)
638 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
641 friend class IdStringType<PoolQueryAttr>;
648 explicit PoolQueryAttr( const char* cstr_r )
652 explicit PoolQueryAttr( const std::string & str_r )
657 static const PoolQueryAttr noAttr;
659 // PoolQuery's own attributes
660 static const PoolQueryAttr repoAttr;
661 static const PoolQueryAttr kindAttr;
662 static const PoolQueryAttr stringAttr;
663 static const PoolQueryAttr stringTypeAttr;
664 static const PoolQueryAttr requireAllAttr;
665 static const PoolQueryAttr caseSensitiveAttr;
666 static const PoolQueryAttr installStatusAttr;
667 static const PoolQueryAttr editionAttr;
670 const PoolQueryAttr PoolQueryAttr::noAttr;
672 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
673 const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
674 const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
675 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
676 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
677 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
678 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
679 const PoolQueryAttr PoolQueryAttr::editionAttr("version");
681 class StringTypeAttr : public IdStringType<PoolQueryAttr>
683 friend class IdStringType<StringTypeAttr>;
688 explicit StringTypeAttr( const char* cstr_r )
690 explicit StringTypeAttr( const std::string & str_r )
693 static const StringTypeAttr noAttr;
695 static const StringTypeAttr exactAttr;
696 static const StringTypeAttr substringAttr;
697 static const StringTypeAttr regexAttr;
698 static const StringTypeAttr globAttr;
699 static const StringTypeAttr wordAttr;
702 const StringTypeAttr StringTypeAttr::noAttr;
704 const StringTypeAttr StringTypeAttr::exactAttr("exact");
705 const StringTypeAttr StringTypeAttr::substringAttr("substring");
706 const StringTypeAttr StringTypeAttr::regexAttr("regex");
707 const StringTypeAttr StringTypeAttr::globAttr("glob");
708 const StringTypeAttr StringTypeAttr::wordAttr("word");
710 ///////////////////////////////////////////////////////////////////
713 //\TODO maybe ctor with stream can be usefull
714 bool PoolQuery::recover( istream &str, char delim )
716 bool finded_something = false; //indicates some atributes is finded
722 getline( str, s, delim );
724 if ((!s.empty()) && s[0]=='#') //comment
729 string::size_type pos = s.find(':');
730 if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
732 if (finded_something) //is first blank line after record?
742 finded_something = true;
744 string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
745 string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
747 PoolQueryAttr attribute( attrName );
749 MIL << "attribute name: " << attrName << endl;
751 if ( attribute==PoolQueryAttr::repoAttr )
753 addRepo( attrValue );
755 /* some backwards compatibility */
756 else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
758 addKind( ResKind(attrValue) );
760 else if ( attribute==PoolQueryAttr::stringAttr
761 || attribute=="global_string")
763 addString( attrValue );
765 else if ( attribute==PoolQueryAttr::stringTypeAttr
766 || attribute=="string_type" )
768 StringTypeAttr s(attrValue);
769 if( s == StringTypeAttr::regexAttr )
773 else if ( s == StringTypeAttr::globAttr )
777 else if ( s == StringTypeAttr::exactAttr )
781 else if ( s == StringTypeAttr::substringAttr )
785 else if ( s == StringTypeAttr::wordAttr )
789 else if ( s == StringTypeAttr::noAttr )
791 WAR << "unknown string type " << attrValue << endl;
795 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
798 else if ( attribute==PoolQueryAttr::requireAllAttr )
800 if ( str::strToTrue(attrValue) )
804 else if ( !str::strToFalse(attrValue) )
806 setRequireAll(false);
810 WAR << "unknown boolean value " << attrValue << endl;
813 else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
815 if ( str::strToTrue(attrValue) )
817 setCaseSensitive(true);
819 else if ( !str::strToFalse(attrValue) )
821 setCaseSensitive(false);
825 WAR << "unknown boolean value " << attrValue << endl;
828 else if ( attribute==PoolQueryAttr::installStatusAttr )
830 if( attrValue == "all" )
832 setStatusFilterFlags( ALL );
834 else if( attrValue == "installed" )
838 else if( attrValue == "not-installed" )
840 setUninstalledOnly();
844 WAR << "Unknown value for install status " << attrValue << endl;
847 else if ( attribute == PoolQueryAttr::editionAttr)
849 string::size_type pos;
851 if (attrValue.find_first_of("=<>!") == 0)
853 pos = attrValue.find_last_of("=<>");
854 rel = Rel(attrValue.substr(0, pos+1));
855 attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
858 setEdition(Edition(attrValue), rel);
860 else if ( attribute==PoolQueryAttr::noAttr )
862 WAR << "empty attribute name" << endl;
867 str::replaceAll( s,"_",":" );
869 addAttribute(a,attrValue);
874 return finded_something;
877 void PoolQuery::serialize( ostream &str, char delim ) const
881 //iterate thrue all settings and write it
882 static const zypp::PoolQuery q; //not save default options, so create default query example
884 for_( it, repos().begin(), repos().end() )
886 str << "repo: " << *it << delim ;
889 for_( it, kinds().begin(), kinds().end() )
891 str << PoolQueryAttr::kindAttr.asString() << ": "
892 << it->idStr() << delim ;
895 if (editionRel() != Rel::ANY && edition() != Edition::noedition)
896 str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
898 if (matchMode()!=q.matchMode())
900 switch( matchMode() )
903 str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
905 case Match::SUBSTRING:
906 str << PoolQueryAttr::stringTypeAttr.asString()
907 << ": substring" << delim;
910 str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
913 str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
916 WAR << "unknown match type " << matchMode() << endl;
920 if( caseSensitive() != q.caseSensitive() )
922 str << "case_sensitive: ";
925 str << "on" << delim;
929 str << "off" << delim;
933 if( requireAll() != q.requireAll() )
935 str << "require_all: ";
938 str << "on" << delim;
942 str << "off" << delim;
946 if( statusFilterFlags() != q.statusFilterFlags() )
948 switch( statusFilterFlags() )
951 str << "install_status: all" << delim;
954 str << "install_status: installed" << delim;
956 case UNINSTALLED_ONLY:
957 str << "install_status: not-installed" << delim;
962 for_( it, strings().begin(), strings().end() )
964 str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
967 for_( it, attributes().begin(), attributes().end() )
969 string s = it->first.asString();
970 str::replaceAll(s,":","_");
971 for_( it2,it->second.begin(),it->second.end() )
973 str << s <<": "<< *it2 << delim;
977 //separating delim - protection
981 string PoolQuery::asString() const
982 { return _pimpl->asString(); }
984 ostream & operator<<( ostream & str, const PoolQuery & obj )
985 { return str << obj.asString(); }
987 bool PoolQuery::operator==(const PoolQuery& a) const
989 if( flags() != a.flags() )
991 if( a.matchWord() != matchWord())
993 if( a.requireAll() != requireAll() )
995 if ( a.kinds() != kinds() )
997 if ( a.repos() != repos() )
999 if(a.edition() != edition())
1001 if(a.editionRel() != editionRel())
1007 ///////////////////////////////////////////////////////////////////
1009 { /////////////////////////////////////////////////////////////////
1011 ///////////////////////////////////////////////////////////////////
1013 // CLASS NAME : PoolQueryMatcher
1015 /** Store \ref PoolQuery settings and assist \ref PoolQueryIterator.
1017 * Basically the matcher performs a base query, which should preselect
1018 * candidates for a match. And has some filter conditions on top of it.
1019 * Query and fileter depend on the \ref PoolQuery settings.
1021 * Matcher must be stateless, as it is shared between multiple
1022 * \ref PoolQueryIterator instances.
1024 * If \ref base_iterator is at the \ref end, \ref advance moves it
1025 * to the first match. Otherwise advance moves to the next match, or
1026 * to the \ref end, if there is no more match.
1028 * \note The original implementation treated an empty search string as
1029 * <it>"match always"</it>. We stay compatible.
1031 class PoolQueryMatcher
1034 typedef sat::LookupAttr::iterator base_iterator;
1037 const base_iterator & end() const
1039 static base_iterator _end;
1043 bool advance( base_iterator & base_r ) const
1045 if ( base_r == end() )
1046 base_r = startNewQyery(); // first candidate
1048 ++base_r; // advance to next candidate
1050 while ( base_r != end() )
1052 if ( isAMatch( base_r ) )
1054 base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
1057 // No match: try next
1064 /** Ctor stores the \ref PoolQuery settings.
1065 * \throw MatchException Any of the exceptions thrown by \ref PoolQuery::Impl::compile.
1067 PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
1071 // Repo restriction:
1072 sat::Pool satpool( sat::Pool::instance() );
1073 for_( it, query_r->_repos.begin(), query_r->_repos.end() )
1075 Repository r( satpool.reposFind( *it ) );
1079 // Kind restriction:
1080 _kinds = query_r->_kinds;
1081 // Edition restriction:
1083 _edition = query_r->_edition;
1084 // Status restriction:
1085 _status_flags = query_r->_status_flags;
1087 _attrMatchList = query_r->_attrMatchList;
1094 /** Initialize a new base query. */
1095 base_iterator startNewQyery() const
1099 // Repo restriction:
1100 if ( _repos.size() == 1 )
1101 q.setRepo( *_repos.begin() );
1102 // else: handled in isAMatch.
1104 // Attribute restriction:
1105 if ( _attrMatchList.size() == 1 ) // all (SolvAttr::allAttr) or 1 attr
1107 const AttrMatchData & matchData( _attrMatchList.front() );
1108 q.setAttr( matchData.attr );
1109 if ( matchData.attrMatcher ) // empty searchstring matches always
1110 q.setAttrMatcher( matchData.attrMatcher );
1112 else // more than 1 attr (but not all)
1114 // no restriction, it's all handled in isAMatch.
1115 q.setAttr( sat::SolvAttr::allAttr );
1122 /** Check whether we are on a match.
1124 * The check covers the whole Solvable, not just the current
1125 * attribute \c base_r points to. If there's no match, also
1126 * prepare \c base_r to advance appropriately. If there is
1127 * a match, simply return \c true. \ref advance always moves
1128 * to the next Solvable if there was a match.
1130 * \note: Caller asserts we're not at \ref end.
1132 bool isAMatch( base_iterator & base_r ) const
1134 /////////////////////////////////////////////////////////////////////
1135 Repository inRepo( base_r.inRepo() );
1136 // Status restriction:
1138 && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
1140 base_r.nextSkipRepo();
1143 // Repo restriction:
1144 if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
1146 base_r.nextSkipRepo();
1149 /////////////////////////////////////////////////////////////////////
1150 sat::Solvable inSolvable( base_r.inSolvable() );
1151 // Kind restriction:
1152 if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
1154 base_r.nextSkipSolvable();
1158 // Edition restriction:
1159 if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
1161 base_r.nextSkipSolvable();
1164 /////////////////////////////////////////////////////////////////////
1165 // string and predicate matching:
1167 if ( _attrMatchList.size() == 1 )
1169 // String matching was done by the base iterator.
1170 // Now check any predicate:
1171 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
1172 if ( ! predicate || predicate( base_r ) )
1175 base_r.nextSkipSolvable();
1179 // Here: search all attributes ;(
1180 for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
1182 const AttrMatchData & matchData( *mi );
1183 sat::LookupAttr q( matchData.attr, inSolvable );
1184 if ( matchData.attrMatcher ) // an empty searchstring matches always
1185 q.setAttrMatcher( matchData.attrMatcher );
1187 if ( ! q.empty() ) // there are matches.
1189 // now check any predicate:
1190 const AttrMatchData::Predicate & predicate( matchData.predicate );
1193 for_( it, q.begin(), q.end() )
1195 if ( predicate( it ) )
1203 base_r.nextSkipSolvable();
1208 /** Repositories include in the search. */
1209 std::set<Repository> _repos;
1210 /** Resolvable kinds to include. */
1211 std::set<ResKind> _kinds;
1212 /** Edition filter. */
1215 /** Installed status filter flags. \see PoolQuery::StatusFilter */
1217 /** AttrMatcher per attribtue. */
1218 AttrMatchList _attrMatchList;
1220 ///////////////////////////////////////////////////////////////////
1222 void PoolQueryIterator::increment()
1224 // matcher restarts if at end! It is called from the ctor
1225 // to get the 1st match. But if the end is reached, it should
1226 // be deleted, otherwise we'd start over again.
1227 if ( _matcher && ! _matcher->advance( base_reference() ) )
1231 ///////////////////////////////////////////////////////////////////
1232 } //namespace detail
1233 ///////////////////////////////////////////////////////////////////
1235 detail::PoolQueryIterator PoolQuery::begin() const
1237 return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
1240 /////////////////////////////////////////////////////////////////
1242 ///////////////////////////////////////////////////////////////////