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"
21 #include "zypp/sat/Pool.h"
22 #include "zypp/sat/Solvable.h"
24 #include "zypp/PoolQuery.h"
28 #include "satsolver/repo.h"
31 #undef ZYPP_BASE_LOGGER_LOGGROUP
32 #define ZYPP_BASE_LOGGER_LOGGROUP "PoolQuery"
35 using namespace zypp::sat;
37 ///////////////////////////////////////////////////////////////////
39 { /////////////////////////////////////////////////////////////////
41 ///////////////////////////////////////////////////////////////////
43 // CLASS NAME : PoolQuery::Impl
49 : _flags( SEARCH_ALL_REPOS | SEARCH_NOCASE | SEARCH_SUBSTRING | SEARCH_SKIP_KIND )
60 const_iterator begin() const;
61 const_iterator end() const;
63 string asString() const;
67 string createRegex(const StrContainer & container) const;
70 /** Raw search strings. */
71 StrContainer _strings;
72 /** Compiled search strings. */
73 mutable string _rcstrings;
74 /** Compiled regex struct */
75 mutable str::regex _regex;
78 /** Regex-compiled attributes */
79 mutable AttrCompiledStrMap _rcattrs;
80 mutable AttrRegexMap _rattrs;
82 /** Repos to search. */
84 /** Kinds to search */
87 /** Sat solver search flags */
89 /** Backup of search flags. compile() may change the flags if needed, so
90 * in order to reuse the query, the original flags need to be stored
91 * at the start of compile() */
93 /** Sat solver status flags */
94 StatusFilter _status_flags;
100 mutable bool _compiled;
103 friend Impl * rwcowClone<Impl>( const Impl * rhs );
104 /** clone for RWCOW_pointer */
106 { return new Impl( *this ); }
112 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
114 bool operator()(const string & str)
120 PoolQuery::StrContainer & _cont;
126 bool operator()(const string & str)
133 void PoolQuery::Impl::compile() const
137 // 'different' - will have to iterate through all and match by ourselves (slow)
138 // 'same' - will pass the compiled string to dataiterator_init
139 // 'one-attr' - will pass it to dataiterator_init
140 // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
145 // create regex; store in _rcstrings; if more strings flag regex;
148 _rcstrings = createRegex(_strings);
149 if (_strings.size() > 1)
150 _cflags = (_cflags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;//setMatchRegex();
154 // else if _attrs is not empty but it contains just one attr
155 // for all _strings and _attr[key] strings
156 // create regex; store in _rcattrs; flag 'one-attr'; if more strings flag regex;
157 else if (_attrs.size() == 1)
160 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
161 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
162 _rcstrings = createRegex(joined);
163 _rcattrs.insert(pair<sat::SolvAttr, string>(_attrs.begin()->first, string()));
164 // switch to regex for multiple strings
165 if (joined.size() > 1)
166 _cflags = (_cflags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
167 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
168 /* We feed multiple lines eventually (e.g. authors or descriptions), so set REG_NEWLINE. */
169 _regex = str::regex(_rcstrings, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | (_cflags & SEARCH_NOCASE ? REG_ICASE : 0));
172 // // MULTIPLE ATTRIBUTES
175 // check whether there are any per-attribute strings
176 bool attrvals_empty = true;
177 for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
178 if (!ai->second.empty())
179 for(StrContainer::const_iterator it = ai->second.begin();
180 it != ai->second.end(); it++)
183 attrvals_empty = false;
184 goto attremptycheckend;
188 // chceck whether the per-attribute strings are all the same
189 bool attrvals_thesame = true;
190 AttrRawStrMap::const_iterator ai = _attrs.begin();
191 const StrContainer & set1 = ai->second;
193 for (; ai != _attrs.end(); ++ai)
197 set1.begin(), set1.end(),
198 ai->second.begin(), ai->second.end(),
199 inserter(result, result.begin())/*, ltstr()*/);
202 attrvals_thesame = false;
207 // // THE SAME STRINGS FOR DIFFERENT ATTRS
208 // else if _attrs is not empty but it does not contain strings
209 // for each key in _attrs take all _strings
210 // create regex; store in _rcattrs and _rcstrings; flag 'same'; if more strings flag regex;
211 if (attrvals_empty || attrvals_thesame)
216 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
217 _rcstrings = createRegex(joined);
221 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
222 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
223 _rcstrings = createRegex(joined);
225 // copy the _attrs keys to _rcattrs
226 for_(ai, _attrs.begin(), _attrs.end())
227 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, string()));
229 // switch to regex for multiple strings
230 if (joined.size() > 1)
231 _cflags = (_cflags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
233 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
234 /* We feed multiple lines eventually (e.g. authors or descriptions), so set REG_NEWLINE. */
235 _regex = str::regex(_rcstrings, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | (_cflags & SEARCH_NOCASE ? REG_ICASE : 0));
238 // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
239 // if _attrs is not empty and it contains non-empty vectors with non-empty strings
240 // for each key in _attrs take all _strings + all _attrs[key] strings
241 // create regex; store in _rcattrs; flag 'different'; if more strings flag regex;
244 for_(ai, _attrs.begin(), _attrs.end())
247 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
248 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
249 string s = createRegex(joined);
250 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, s));
252 // switch to regex for multiple strings
253 if (joined.size() > 1)
254 _cflags = (_cflags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
255 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
257 str::regex regex(s, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | (_cflags & SEARCH_NOCASE ? REG_ICASE : 0));
258 _rattrs.insert(pair<sat::SolvAttr, str::regex>(ai->first, regex));
264 // tell the Dataiterator to search only in one repo if only one specified
265 if (_repos.size() == 1)
266 _cflags &= ~SEARCH_ALL_REPOS;
270 DBG << asString() << endl;
275 * Converts '*' and '?' wildcards within str into their regex equivalents.
277 static string wildcards2regex(const string & str)
279 string regexed = str;
281 string r_all(".*"); // regex equivalent of '*'
282 string r_one("."); // regex equivalent of '?'
283 string::size_type pos;
285 // replace all "*" in input with ".*"
286 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
287 regexed = regexed.replace(pos, 1, r_all);
289 // replace all "?" in input with "."
290 for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
291 regexed = regexed.replace(pos, 1, r_one);
296 //! macro for word boundary tags for regexes
297 #define WB (_match_word ? string("\\b") : string())
299 string PoolQuery::Impl::createRegex(const StrContainer & container) const
303 if (container.empty())
306 if (container.size() == 1)
308 return WB + *container.begin() + WB;
313 bool use_wildcards = (_cflags & SEARCH_STRINGMASK) == SEARCH_GLOB;
314 StrContainer::const_iterator it = container.begin();
318 tmp = wildcards2regex(*it);
324 if ((_cflags & SEARCH_STRINGMASK) != SEARCH_STRING) // not match exact
325 tmp += ".*" + WB + tmp;
326 rstr = "(?=" + tmp + ")";
330 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_STRING || // match exact
331 (_cflags & SEARCH_STRINGMASK) == SEARCH_GLOB) // match glob
334 rstr += WB + "(" + tmp;
339 for (; it != container.end(); ++it)
342 tmp = wildcards2regex(*it);
348 if ((_cflags & SEARCH_STRINGMASK) != SEARCH_STRING) // not match exact
349 tmp += ".*" + WB + tmp;
350 rstr += "(?=" + tmp + ")";
360 if ((_cflags & SEARCH_STRINGMASK) != SEARCH_STRING) // not match exact
366 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_STRING || // match exact
367 (_cflags & SEARCH_STRINGMASK) == SEARCH_GLOB) // match glob
375 PoolQuery::const_iterator PoolQuery::Impl::begin() const
379 sat::Pool pool(sat::Pool::instance());
380 // no pool or no repos
381 if (!pool.get() || pool.reposEmpty())
384 // if only one repository has been specified, find it in the pool
386 if (!(_cflags & SEARCH_ALL_REPOS) && _repos.size() == 1)
388 string theone = *_repos.begin();
389 repo = pool.reposFind(theone);
390 if (repo == Repository::noRepository)
392 DBG << "Repository '" << theone << "' not found in sat pool." << endl;
397 if ((_cflags & SEARCH_ALL_REPOS) || repo == Repository::noRepository)
398 repo = *pool.reposBegin();
400 DBG << "_cflags:" << _cflags << endl;
402 scoped_ptr< ::_Dataiterator> _rdit( new ::Dataiterator );
403 // needed while LookupAttr::iterator::dip_equal does ::memcmp:
404 ::memset( _rdit.get(), 0, sizeof(::_Dataiterator) );
406 // initialize the Dataiterator for different cases
407 if (_rcattrs.empty())
409 ::dataiterator_init(_rdit.get(),
410 repo.get(), // either the first repo or the repo to search
411 0, // search all solvables
412 0, // attribute id - only if 1 attr key specified
413 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
416 else if (_rcattrs.size() == 1)
418 ::dataiterator_init(_rdit.get(),
419 repo.get(), // either the first repo or the repo to search
420 0, // search all solvables
421 _rcattrs.begin()->first.id(), // keyname - attribute id - only if 1 attr key specified
422 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
427 ::dataiterator_init(_rdit.get(),
428 repo.get(), // either the first repo or the repo to search
429 0, /*search all resolvables */
430 0, /*keyname - if only 1 attr key specified, pass it here, otherwise do more magic */
431 0, //qs.empty() ? 0 : qs.c_str(), /* create regex, pass it here */
435 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX && _rdit->regex_err != 0)
436 ZYPP_THROW(Exception(str::form(
437 _("Invalid regular expression '%s': regcomp returned %d"),
438 _rcstrings.c_str(), _rdit->regex_err)));
440 PoolQuery::const_iterator it(_rdit, this);
446 PoolQuery::const_iterator PoolQuery::Impl::end() const
448 return PoolQuery::const_iterator();
452 string PoolQuery::Impl::asString() const
456 o << "compiled: " << _compiled << endl;
459 for(Kinds::const_iterator it = _kinds.begin();
460 it != _kinds.end(); ++it)
465 for(StrContainer::const_iterator it = _repos.begin();
466 it != _repos.end(); ++it)
470 o << "string match flags:" << endl;
471 o << "* string/substring/glob/regex: " << (_cflags & SEARCH_STRINGMASK) << endl;
472 o << "* SEARCH_NOCASE: " << ((_cflags & SEARCH_NOCASE) ? "yes" : "no") << endl;
473 o << "* SEARCH_ALL_REPOS: " << ((_cflags & SEARCH_ALL_REPOS) ? "yes" : "no") << endl;
474 o << "status filter flags:" << _status_flags << endl;
479 for(StrContainer::const_iterator it = _strings.begin();
480 it != _strings.end(); ++it)
484 o << "attributes: " << endl;
485 for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
487 o << "* " << ai->first << ": ";
488 for(StrContainer::const_iterator vi = ai->second.begin();
489 vi != ai->second.end(); ++vi)
496 o << "compiled strings: " << _rcstrings << endl;
497 o << "compiled attributes:" << endl;
498 for (AttrCompiledStrMap::const_iterator ai = _rcattrs.begin(); ai != _rcattrs.end(); ++ai)
499 o << "* " << ai->first << ": " << ai->second << endl;
504 /** \relates PoolQuery::Impl Stream output *//*
505 inline std::ostream & operator<<( std::ostream & str, const PoolQuery::Impl & obj )
507 return str << "PoolQuery::Impl";
510 ///////////////////////////////////////////////////////////////////
512 ///////////////////////////////////////////////////////////////////
514 { /////////////////////////////////////////////////////////////////
516 ///////////////////////////////////////////////////////////////////
518 // CLASS NAME : PoolQuery::ResultIterator
520 ///////////////////////////////////////////////////////////////////
522 PoolQueryIterator::PoolQueryIterator()
523 : _sid(0), _has_next(false), _do_matching(false)
524 { this->base_reference() = LookupAttr::iterator(); }
527 PoolQueryIterator::PoolQueryIterator(
528 scoped_ptr< ::_Dataiterator> & dip_r,
529 const PoolQuery::Impl * pqimpl)
532 , _do_matching(pqimpl->_rcattrs.size() > 1)
533 , _flags(pqimpl->_cflags)
534 , _str(pqimpl->_rcstrings)
535 , _regex(pqimpl->_regex)
536 , _attrs_str(pqimpl->_rcattrs)
537 , _attrs_regex(pqimpl->_rattrs)
538 , _repos(pqimpl->_repos)
539 , _kinds(pqimpl->_kinds)
540 , _status_flags(pqimpl->_status_flags)
542 this->base_reference() = LookupAttr::iterator(dip_r, true); //!\todo pass chain_repos
543 _has_next = (*base_reference() != sat::detail::noId);
547 PoolQueryIterator::PoolQueryIterator(const PoolQueryIterator & rhs)
549 , _has_next(rhs._has_next)
550 , _do_matching(rhs._do_matching)
554 , _attrs_str(rhs._attrs_str)
555 , _attrs_regex(rhs._attrs_regex)
558 , _status_flags(rhs._status_flags)
559 { base_reference() = LookupAttr::iterator(rhs.base()); }
562 PoolQueryIterator::~PoolQueryIterator()
566 PoolQueryIterator & PoolQueryIterator::operator=( const PoolQueryIterator & rhs )
568 base_reference() = rhs.base();
570 _has_next = rhs._has_next;
571 _do_matching = rhs._do_matching;
575 _attrs_str = rhs._attrs_str;
576 _attrs_regex = rhs._attrs_regex;
579 _status_flags = rhs._status_flags;
584 void PoolQueryIterator::increment()
589 bool got_match = false;
591 while (_has_next && !(got_match = matchSolvable()));
593 // no more solvables and the last did not match
594 if (!got_match && !_has_next)
596 base_reference() = LookupAttr::iterator();
601 bool PoolQueryIterator::matchSolvable()
603 _sid = base().get()->solvid;
605 bool new_solvable = true;
606 bool matches = !_do_matching;
607 bool drop_by_kind_status = false;
608 bool drop_by_repo = false;
615 drop_by_repo = false;
616 if(!_repos.empty() &&
617 _repos.find(base().get()->repo->name) == _repos.end())
623 drop_by_kind_status = false;
625 // whether to drop an uninstalled (repo) solvable
626 if ( (_status_flags & PoolQuery::INSTALLED_ONLY) &&
627 base().get()->repo->name != sat::Pool::instance().systemRepoName() )
629 drop_by_kind_status = true;
633 // whether to drop an installed (target) solvable
634 if ((_status_flags & PoolQuery::UNINSTALLED_ONLY) &&
635 base().get()->repo->name == sat::Pool::instance().systemRepoName())
637 drop_by_kind_status = true;
641 // whether to drop unwanted kind
644 sat::Solvable s(_sid);
645 // the user wants to filter by kind.
646 if (_kinds.find(s.kind()) == _kinds.end())
647 drop_by_kind_status = true;
653 matches = matches && !drop_by_kind_status && !drop_by_repo;
656 if (_do_matching && !drop_by_kind_status)
660 SolvAttr attr(base().get()->key->name);
661 PoolQuery::AttrCompiledStrMap::const_iterator ai = _attrs_str.find(attr);
662 if (ai != _attrs_str.end())
664 if ((_flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
666 const regex_t * regex_p;
669 PoolQuery::AttrRegexMap::iterator rai = _attrs_regex.find(attr);
670 if (rai != _attrs_regex.end())
671 regex_p = rai->second.get();
674 ERR << "no compiled regex found for " << attr << endl;
679 regex_p = _regex.get();
681 matches = ::dataiterator_match(base().get(), _flags, regex_p);
685 const string & sstr =
686 _str.empty() ? ai->second : _str;
687 matches = ::dataiterator_match(base().get(), _flags, sstr.c_str());
691 /* After calling dataiterator_match (with any string matcher set)
692 the kv.str member will be filled with something sensible. */
693 /*INT << "value: " << base().get()->kv.str << endl
694 << " str: " << _str << endl;*/
701 base_reference().nextSkipRepo();
702 drop_by_repo = false;
704 else if (drop_by_kind_status)
706 base_reference().nextSkipSolvable();
707 drop_by_kind_status = false;
710 // copy the iterator to forward check for the next attribute ***
711 _tmpit = base_reference();
712 _has_next = (*(++_tmpit) != sat::detail::noId);
716 // *** now increment. Had it not be done this way,
717 // the LookupAttr::iterator could have reached the end() while
718 // trying to reach a matching attribute or the next solvable
719 // thus resulting to a problem in the equal() method
721 new_solvable = base().get()->solvid != _sid;
723 // no more attributes in this repo, return
725 return matches; // did the last solvable match conditions?
727 while (!new_solvable);
732 ///////////////////////////////////////////////////////////////////
734 ///////////////////////////////////////////////////////////////////
736 ///////////////////////////////////////////////////////////////////
738 // CLASS NAME : PoolQuery
740 ///////////////////////////////////////////////////////////////////
742 PoolQuery::PoolQuery()
747 PoolQuery::~PoolQuery()
751 void PoolQuery::addRepo(const std::string &repoalias)
753 _pimpl->_repos.insert(repoalias);
754 _pimpl->_flags &= ~SEARCH_ALL_REPOS;
758 void PoolQuery::addKind(const ResKind & kind)
759 { _pimpl->_kinds.insert(kind); }
762 void PoolQuery::addString(const string & value)
763 { _pimpl->_strings.insert(value); }
766 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
767 { _pimpl->_attrs[attr].insert(value); }
770 void PoolQuery::setCaseSensitive(const bool value)
773 _pimpl->_flags &= ~SEARCH_NOCASE;
775 _pimpl->_flags |= SEARCH_NOCASE;
779 void PoolQuery::setMatchSubstring()
780 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_SUBSTRING; }
781 void PoolQuery::setMatchExact()
782 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_STRING; }
783 void PoolQuery::setMatchRegex()
784 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX; }
785 void PoolQuery::setMatchGlob()
786 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_GLOB; }
787 void PoolQuery::setMatchWord()
789 _pimpl->_match_word = true;
790 _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
793 void PoolQuery::setFlags(int flags)
794 { _pimpl->_flags = flags; }
797 void PoolQuery::setInstalledOnly()
798 { _pimpl->_status_flags = INSTALLED_ONLY; }
799 void PoolQuery::setUninstalledOnly()
800 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
801 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
802 { _pimpl->_status_flags = flags; }
805 void PoolQuery::setRequireAll(const bool require_all)
806 { _pimpl->_require_all = require_all; }
809 const PoolQuery::StrContainer &
810 PoolQuery::strings() const
811 { return _pimpl->_strings; }
813 const PoolQuery::AttrRawStrMap &
814 PoolQuery::attributes() const
815 { return _pimpl->_attrs; }
817 const PoolQuery::StrContainer &
818 PoolQuery::attribute(const sat::SolvAttr & attr) const
820 static const PoolQuery::StrContainer nocontainer;
821 AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
822 return it != _pimpl->_attrs.end() ? it->second : nocontainer;
825 const PoolQuery::Kinds &
826 PoolQuery::kinds() const
827 { return _pimpl->_kinds; }
829 const PoolQuery::StrContainer &
830 PoolQuery::repos() const
831 { return _pimpl->_repos; }
833 bool PoolQuery::caseSensitive() const
834 { return !(_pimpl->_flags & SEARCH_NOCASE); }
836 bool PoolQuery::matchExact() const
837 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_STRING; }
838 bool PoolQuery::matchSubstring() const
839 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_SUBSTRING; }
840 bool PoolQuery::matchGlob() const
841 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_GLOB; }
842 bool PoolQuery::matchRegex() const
843 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_REGEX; }
844 int PoolQuery::matchType() const
845 { return _pimpl->_flags & SEARCH_STRINGMASK; }
847 bool PoolQuery::matchWord() const
848 { return _pimpl->_match_word; }
850 bool PoolQuery::requireAll() const
851 { return _pimpl->_require_all; }
853 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
854 { return _pimpl->_status_flags; }
856 PoolQuery::const_iterator PoolQuery::begin() const
857 { return _pimpl->begin(); }
860 PoolQuery::const_iterator PoolQuery::end() const
861 { return _pimpl->end(); }
864 bool PoolQuery::empty() const
866 try { return _pimpl->begin() == _pimpl->end(); }
867 catch (const Exception & ex) {}
872 PoolQuery::size_type PoolQuery::size() const
877 for(const_iterator it = _pimpl->begin(); it != _pimpl->end(); ++it, ++count);
879 catch (const Exception & ex) {}
885 void PoolQuery::execute(ProcessResolvable fnc)
886 { invokeOnEach(_pimpl->begin(), _pimpl->end(), fnc); }
889 ///////////////////////////////////////////////////////////////////
891 // CLASS NAME : PoolQuery::Attr
894 * represents all atributes in PoolQuery except SolvAtributes, which are
895 * used as is (not needed extend anything if someone adds new solv attr)
897 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
900 friend class IdStringType<PoolQueryAttr>;
907 explicit PoolQueryAttr( const char* cstr_r )
911 explicit PoolQueryAttr( const std::string & str_r )
916 static const PoolQueryAttr noAttr;
919 static const PoolQueryAttr repoAttr;
920 static const PoolQueryAttr kindAttr;
921 static const PoolQueryAttr stringAttr;
922 static const PoolQueryAttr stringTypeAttr;
923 static const PoolQueryAttr requireAllAttr;
924 static const PoolQueryAttr caseSensitiveAttr;
925 static const PoolQueryAttr installStatusAttr;
928 const PoolQueryAttr PoolQueryAttr::noAttr;
930 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
931 const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
932 const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
933 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
934 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
935 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
936 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
938 class StringTypeAttr : public IdStringType<PoolQueryAttr>
940 friend class IdStringType<StringTypeAttr>;
945 explicit StringTypeAttr( const char* cstr_r )
947 explicit StringTypeAttr( const std::string & str_r )
950 static const StringTypeAttr noAttr;
952 static const StringTypeAttr exactAttr;
953 static const StringTypeAttr substringAttr;
954 static const StringTypeAttr regexAttr;
955 static const StringTypeAttr globAttr;
956 static const StringTypeAttr wordAttr;
958 const StringTypeAttr StringTypeAttr::noAttr;
960 const StringTypeAttr StringTypeAttr::exactAttr("exact");
961 const StringTypeAttr StringTypeAttr::substringAttr("substring");
962 const StringTypeAttr StringTypeAttr::regexAttr("regex");
963 const StringTypeAttr StringTypeAttr::globAttr("glob");
964 const StringTypeAttr StringTypeAttr::wordAttr("word");
966 ///////////////////////////////////////////////////////////////////
969 //\TODO maybe ctor with stream can be usefull
970 bool PoolQuery::recover( istream &str, char delim )
972 bool finded_something = false; //indicates some atributes is finded
978 getline( str, s, delim );
980 if ((!s.empty()) && s[0]=='#') //comment
985 string::size_type pos = s.find(':');
986 if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
988 if (finded_something) //is first blank line after record?
998 finded_something = true;
1000 string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
1001 string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
1003 PoolQueryAttr attribute( attrName );
1005 if ( attribute==PoolQueryAttr::repoAttr )
1007 addRepo( attrValue );
1009 else if ( attribute==PoolQueryAttr::kindAttr )
1011 addKind( ResKind(attrValue) );
1013 else if ( attribute==PoolQueryAttr::stringAttr )
1015 addString( attrValue );
1017 else if ( attribute==PoolQueryAttr::stringTypeAttr )
1019 StringTypeAttr s(attrValue);
1020 if( s == StringTypeAttr::regexAttr )
1024 else if ( s == StringTypeAttr::globAttr )
1028 else if ( s == StringTypeAttr::exactAttr )
1032 else if ( s == StringTypeAttr::substringAttr )
1034 setMatchSubstring();
1036 else if ( s == StringTypeAttr::wordAttr )
1040 else if ( s == StringTypeAttr::noAttr )
1042 WAR << "unknown string type " << attrValue << endl;
1046 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
1049 else if ( attribute==PoolQueryAttr::requireAllAttr )
1051 if ( str::strToTrue(attrValue) )
1053 setRequireAll(true);
1055 else if ( !str::strToFalse(attrValue) )
1057 setRequireAll(false);
1061 WAR << "unknown boolean value " << attrValue << endl;
1064 else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
1066 if ( str::strToTrue(attrValue) )
1068 setCaseSensitive(true);
1070 else if ( !str::strToFalse(attrValue) )
1072 setCaseSensitive(false);
1076 WAR << "unknown boolean value " << attrValue << endl;
1079 else if ( attribute==PoolQueryAttr::installStatusAttr )
1081 if( attrValue == "all" )
1083 setStatusFilterFlags( ALL );
1085 else if( attrValue == "installed" )
1089 else if( attrValue == "not-installed" )
1091 setUninstalledOnly();
1095 WAR << "Unknown value for install status " << attrValue << endl;
1098 else if ( attribute==PoolQueryAttr::noAttr )
1100 WAR << "empty attribute name" << endl;
1104 string s = attrName;
1105 str::replace_all( s,"_",":" );
1107 addAttribute(a,attrValue);
1112 return finded_something;
1115 void PoolQuery::serialize( ostream &str, char delim ) const
1119 //iterate thrue all settings and write it
1120 static const zypp::PoolQuery q; //not save default options, so create default query example
1122 for_( it, repos().begin(), repos().end() )
1124 str << "repo: " << *it << delim ;
1127 for_( it, kinds().begin(), kinds().end() )
1129 str << PoolQueryAttr::kindAttr.asString() << ": "
1130 << it->idStr() << delim ;
1133 if (matchType()!=q.matchType())
1135 switch( matchType() )
1138 str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
1140 case SEARCH_SUBSTRING:
1141 str << PoolQueryAttr::stringTypeAttr.asString()
1142 << ": substring" << delim;
1145 str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
1148 str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
1151 WAR << "unknown match type " << matchType() << endl;
1155 if( caseSensitive() != q.caseSensitive() )
1157 str << "case_sensitive: ";
1158 if (caseSensitive())
1160 str << "on" << delim;
1164 str << "off" << delim;
1168 if( requireAll() != q.requireAll() )
1170 str << "require_all: ";
1173 str << "on" << delim;
1177 str << "off" << delim;
1181 if( statusFilterFlags() != q.statusFilterFlags() )
1183 switch( statusFilterFlags() )
1186 str << "install_status: all" << delim;
1188 case INSTALLED_ONLY:
1189 str << "install_status: installed" << delim;
1191 case UNINSTALLED_ONLY:
1192 str << "install_status: not-installed" << delim;
1197 for_( it, strings().begin(), strings().end() )
1199 str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
1202 for_( it, attributes().begin(), attributes().end() )
1204 string s = it->first.asString();
1205 str::replace_all(s,":","_");
1206 for_( it2,it->second.begin(),it->second.end() )
1208 str << s <<": "<< *it2 << delim;
1212 //separating delim - protection
1218 string PoolQuery::asString() const
1219 { return _pimpl->asString(); }
1222 ostream & operator<<( ostream & str, const PoolQuery & obj )
1223 { return str << obj.asString(); }
1225 //internal matching two containers O(n^2)
1226 template <class Container>
1227 bool equalContainers(const Container& a, const Container& b)
1229 if (a.size()!=b.size())
1232 for_(it,a.begin(),a.end())
1234 bool finded = false;
1235 for_( it2, b.begin(),b.end() )
1250 bool PoolQuery::operator==(const PoolQuery& a) const
1252 if (!_pimpl->_compiled)
1254 if (!a._pimpl->_compiled)
1255 a._pimpl->compile();
1256 if( matchType()!=a.matchType() )
1258 if( a.matchWord()!=matchWord())
1260 if( a.requireAll()!=requireAll() )
1262 if(!equalContainers(a.kinds(), kinds()))
1264 if(!equalContainers(a.repos(), repos()))
1266 if(a._pimpl->_rcstrings!=_pimpl->_rcstrings)
1268 if(!equalContainers(a._pimpl->_rcattrs, _pimpl->_rcattrs))
1270 if(a._pimpl->_cflags!= _pimpl->_cflags)
1277 /////////////////////////////////////////////////////////////////
1279 ///////////////////////////////////////////////////////////////////