1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PoolQuery.cc
14 #include <boost/algorithm/string/replace.hpp>
16 #include "zypp/base/Gettext.h"
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/Regex.h"
19 #include "zypp/base/Algorithm.h"
20 #include "zypp/base/String.h"
21 #include "zypp/repo/RepoException.h"
23 #include "zypp/sat/Pool.h"
24 #include "zypp/sat/Solvable.h"
26 #include "zypp/PoolQuery.h"
30 #include "satsolver/repo.h"
34 using namespace zypp::sat;
36 ///////////////////////////////////////////////////////////////////
38 { /////////////////////////////////////////////////////////////////
40 ///////////////////////////////////////////////////////////////////
42 // CLASS NAME : PoolQuery::Impl
48 : _flags( SEARCH_ALL_REPOS | SEARCH_NOCASE | SEARCH_SUBSTRING )
59 const_iterator begin() const;
60 const_iterator end() const;
62 string asString() const;
66 string createRegex(const StrContainer & container) const;
69 /** Raw search strings. */
70 StrContainer _strings;
71 /** Regex-compiled search strings. */
72 mutable string _rcstrings;
73 mutable regex_t _regex;
76 /** Regex-compiled attributes */
77 mutable CompiledAttrMap _rcattrs;
78 mutable map<sat::SolvAttr, regex_t> _rattrs;
80 /** Repos to search. */
82 /** Kinds to search */
85 /** Sat solver search flags */
87 /** Backup of search flags. compile() may change the flags if needed, so
88 * in order to reuse the query, the original flags need to be stored
89 * at the start of compile() */
91 /** Sat solver status flags */
92 PoolQuery::StatusFilter _status_flags;
98 mutable bool _compiled;
101 friend Impl * rwcowClone<Impl>( const Impl * rhs );
102 /** clone for RWCOW_pointer */
104 { return new Impl( *this ); }
109 compileRegex(regex_t * regex, const string & str, bool nocase)
111 /* We feed multiple lines eventually (e.g. authors or descriptions),
112 so set REG_NEWLINE. */
113 if (regcomp(regex, str.c_str(),
114 REG_EXTENDED | REG_NOSUB | REG_NEWLINE | (nocase ? REG_ICASE : 0)) != 0)
115 ZYPP_THROW(Exception(
116 str::form(_("Invalid regular expression '%s'"), str.c_str())));
121 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
123 bool operator()(const string & str)
129 PoolQuery::StrContainer & _cont;
135 bool operator()(const string & str)
142 void PoolQuery::Impl::compile() const
146 // 'different' - will have to iterate through all and match by ourselves (slow)
147 // 'same' - will pass the compiled string to dataiterator_init
148 // 'one-attr' - will pass it to dataiterator_init
149 // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
154 // create regex; store in _rcstrings; if more strings flag regex;
157 _rcstrings = createRegex(_strings);
158 if (_strings.size() > 1)
159 _cflags = (_cflags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;//setMatchRegex();
163 // else if _attrs is not empty but it contains just one attr
164 // for all _strings and _attr[key] strings
165 // create regex; store in _rcattrs; flag 'one-attr'; if more strings flag regex;
166 else if (_attrs.size() == 1)
169 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
170 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
171 _rcstrings = createRegex(joined);
172 _rcattrs.insert(pair<sat::SolvAttr, string>(_attrs.begin()->first, string()));
175 // // MULTIPLE ATTRIBUTES
178 // check whether there are any per-attribute strings
179 bool attrvals_empty = true;
180 for (AttrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
181 if (!ai->second.empty())
182 for(StrContainer::const_iterator it = ai->second.begin();
183 it != ai->second.end(); it++)
186 attrvals_empty = false;
187 goto attremptycheckend;
191 // chceck whether the per-attribute strings are all the same
192 bool attrvals_thesame = true;
193 AttrMap::const_iterator ai = _attrs.begin();
194 const StrContainer & set1 = ai->second;
196 for (; ai != _attrs.end(); ++ai)
200 set1.begin(), set1.end(),
201 ai->second.begin(), ai->second.end(),
202 inserter(result, result.begin())/*, ltstr()*/);
205 attrvals_thesame = false;
210 // // THE SAME STRINGS FOR DIFFERENT ATTRS
211 // else if _attrs is not empty but it does not contain strings
212 // for each key in _attrs take all _strings
213 // create regex; store in _rcattrs and _rcstrings; flag 'same'; if more strings flag regex;
214 if (attrvals_empty || attrvals_thesame)
219 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
220 _rcstrings = createRegex(joined);
224 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
225 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
226 _rcstrings = createRegex(joined);
228 // copy the _attrs keys to _rcattrs
229 for_(ai, _attrs.begin(), _attrs.end())
230 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, string()));
232 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
233 compileRegex(&_regex, _rcstrings, _cflags & SEARCH_NOCASE);
236 // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
237 // if _attrs is not empty and it contains non-empty vectors with non-empty strings
238 // for each key in _attrs take all _strings + all _attrs[key] strings
239 // create regex; store in _rcattrs; flag 'different'; if more strings flag regex;
242 for_(ai, _attrs.begin(), _attrs.end())
245 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
246 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
247 string s = createRegex(joined);
248 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, s));
250 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
253 compileRegex(®ex, s, _cflags & SEARCH_NOCASE);
254 _rattrs.insert(pair<sat::SolvAttr, regex_t>(ai->first, regex));
260 // tell the Dataiterator to search only in one repo if only one specified
261 if (_repos.size() == 1)
262 _cflags &= ~SEARCH_ALL_REPOS;
266 DBG << asString() << endl;
270 * Converts '*' and '?' wildcards within str into their regex equivalents.
272 static string wildcards2regex(const string & str)
274 string regexed = str;
276 str::regex all("\\*"); // regex to search for '*'
277 str::regex one("\\?"); // regex to search for '?'
278 string r_all(".*"); // regex equivalent of '*'
279 string r_one("."); // regex equivalent of '?'
280 string::size_type pos;
282 // replace all "*" in input with ".*"
283 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
284 regexed = regexed.replace(pos, 1, r_all);
286 // replace all "?" in input with "."
287 for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
288 regexed = regexed.replace(pos, 1, r_one);
290 DBG << " -> " << regexed << endl;
295 //! macro for word boundary tags for regexes
296 #define WB (_match_word ? string("\\b") : string())
298 string PoolQuery::Impl::createRegex(const StrContainer & container) const
302 if (container.empty())
305 if (container.size() == 1)
308 return ".*" + WB + *container.begin() + WB + ".*";
310 return *container.begin();
315 bool use_wildcards = (_cflags & SEARCH_STRINGMASK) == SEARCH_GLOB;
316 StrContainer::const_iterator it = container.begin();
320 tmp = wildcards2regex(*it);
324 if (!(_cflags & SEARCH_STRING)) // not match exact
325 tmp += ".*" + WB + tmp;
326 rstr = "(?=" + tmp + ")";
330 if (_cflags & SEARCH_STRING) // match exact
340 for (; it != container.end(); ++it)
343 tmp = wildcards2regex(*it);
347 if (!(_cflags & SEARCH_STRING)) // not match exact
348 tmp += ".*" + WB + tmp;
349 rstr += "(?=" + tmp + ")";
359 if (!(_cflags & SEARCH_STRING)) // not match exact
365 if (_cflags & SEARCH_STRING) // match exact
375 PoolQuery::const_iterator PoolQuery::Impl::begin() const
379 // if only one repository has been specified, find it in the pool
380 sat::Pool pool(sat::Pool::instance());
381 sat::Pool::RepositoryIterator itr = pool.reposBegin();
382 if (!(_cflags & SEARCH_ALL_REPOS) && _repos.size() == 1)
384 string theone = *_repos.begin();
385 for (; itr->info().alias() != theone && itr != pool.reposEnd(); ++itr);
386 if (itr == pool.reposEnd())
388 RepoInfo info; info.setAlias(theone);
389 ERR << "Repository not found in sat pool." << endl;
390 ZYPP_THROW(repo::RepoNotFoundException(info));
394 DBG << "_cflags:" << _cflags << endl;
396 scoped_ptr< ::_Dataiterator> _rdit( new ::Dataiterator );
397 // needed while LookupAttr::iterator::dip_equal does ::memcmp:
398 ::memset( _rdit.get(), 0, sizeof(::_Dataiterator) );
400 if (_rcattrs.empty())
402 ::dataiterator_init(_rdit.get(),
403 _cflags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), // repository \todo fix this
404 0, // search all solvables
405 0, // attribute id - only if 1 attr key specified
406 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
409 else if (_rcattrs.size() == 1)
411 ::dataiterator_init(_rdit.get(),
412 _cflags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), // repository \todo fix this
413 0, // search all solvables
414 _rcattrs.begin()->first.id(), // keyname - attribute id - only if 1 attr key specified
415 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
420 ::dataiterator_init(_rdit.get(),
421 _cflags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), /* repository - switch to next at the end of current one in increment() */
422 0, /*search all resolvables */
423 0, /*keyname - if only 1 attr key specified, pass it here, otherwise do more magic */
424 0, //qs.empty() ? 0 : qs.c_str(), /* create regex, pass it here */
428 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX && _rdit->regex_err != 0)
429 ZYPP_THROW(Exception(str::form(
430 _("Invalid regular expression '%s': regcomp returned %d"),
431 _rcstrings.c_str(), _rdit->regex_err)));
433 PoolQuery::const_iterator it(_rdit, this);
438 PoolQuery::const_iterator PoolQuery::Impl::end() const
440 INT << "end" << endl;
441 return PoolQuery::const_iterator();
445 string PoolQuery::Impl::asString() const
449 o << "compiled: " << _compiled << endl;
452 for(Kinds::const_iterator it = _kinds.begin();
453 it != _kinds.end(); ++it)
458 for(StrContainer::const_iterator it = _repos.begin();
459 it != _repos.end(); ++it)
463 o << "string match flags:" << endl;
464 o << "* string/substring/glob/regex: " << (_cflags & SEARCH_STRINGMASK) << endl;
465 o << "* SEARCH_NOCASE: " << ((_cflags & SEARCH_NOCASE) ? "yes" : "no") << endl;
466 o << "* SEARCH_ALL_REPOS: " << ((_cflags & SEARCH_ALL_REPOS) ? "yes" : "no") << endl;
467 o << "status filter flags:" << _status_flags << endl;
472 for(StrContainer::const_iterator it = _strings.begin();
473 it != _strings.end(); ++it)
477 o << "attributes: " << endl;
478 for(AttrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
480 o << "* " << ai->first << ": ";
481 for(StrContainer::const_iterator vi = ai->second.begin();
482 vi != ai->second.end(); ++vi)
489 o << "compiled strings: " << _rcstrings << endl;
490 o << "compiled attributes:" << endl;
491 for (CompiledAttrMap::const_iterator ai = _rcattrs.begin(); ai != _rcattrs.end(); ++ai)
492 o << "* " << ai->first << ": " << ai->second << endl;
497 /** \relates PoolQuery::Impl Stream output *//*
498 inline std::ostream & operator<<( std::ostream & str, const PoolQuery::Impl & obj )
500 return str << "PoolQuery::Impl";
503 ///////////////////////////////////////////////////////////////////
505 ///////////////////////////////////////////////////////////////////
507 { /////////////////////////////////////////////////////////////////
509 ///////////////////////////////////////////////////////////////////
511 // CLASS NAME : PoolQuery::ResultIterator
513 ///////////////////////////////////////////////////////////////////
515 PoolQueryIterator::PoolQueryIterator()
516 : _sid(0), _has_next(false), _do_matching(false)
517 { this->base_reference() = LookupAttr::iterator(); }
520 PoolQueryIterator::PoolQueryIterator(
521 scoped_ptr< ::_Dataiterator> & dip_r,
522 const PoolQuery::Impl * pqimpl)
526 , _do_matching(_pqimpl->_rcattrs.size() > 1)
528 this->base_reference() = LookupAttr::iterator(dip_r, true); //!\todo pass chain_repos
529 _has_next = (*base_reference() != sat::detail::noId);
533 PoolQueryIterator::PoolQueryIterator(const PoolQueryIterator & rhs)
534 : _pqimpl(rhs._pqimpl)
536 , _has_next(rhs._has_next)
537 , _do_matching(rhs._do_matching)
538 { base_reference() = LookupAttr::iterator(rhs.base()); }
541 PoolQueryIterator::~PoolQueryIterator()
545 PoolQueryIterator & PoolQueryIterator::operator=( const PoolQueryIterator & rhs )
547 base_reference() = rhs.base();
548 _pqimpl = rhs._pqimpl; //! \todo FIXME
550 _has_next = rhs._has_next;
551 _do_matching = rhs._do_matching;
556 void PoolQueryIterator::increment()
561 bool got_match = false;
564 DBG << "last: " << _sid << endl;
565 while (_has_next && !(got_match = matchSolvable()));
568 // no more solvables and the last did not match
569 if (!got_match && !_has_next)
571 base_reference() = LookupAttr::iterator();
575 DBG << "next: " << _sid << endl;
578 bool PoolQueryIterator::matchSolvable()
580 _sid = base().get()->solvid;
582 bool new_solvable = true;
583 bool matches = !_do_matching;
585 bool drop_by_kind_status = false;
586 bool drop_by_repo = false;
589 //! \todo FIXME Dataiterator returning resolvables belonging to current repo?
590 in_repo = _sid >= base().get()->repo->start;
592 if (in_repo && new_solvable)
596 drop_by_repo = false;
597 if (!_pqimpl->_repos.empty() &&
598 _pqimpl->_repos.find(base().get()->repo->name) == _pqimpl->_repos.end())
604 drop_by_kind_status = false;
606 // whether to drop an uninstalled (repo) solvable
607 if ( (_pqimpl->_status_flags & PoolQuery::INSTALLED_ONLY) &&
608 base().get()->repo->name != sat::Pool::instance().systemRepoName() )
610 drop_by_kind_status = true;
614 // whether to drop an installed (target) solvable
615 if ((_pqimpl->_status_flags & PoolQuery::UNINSTALLED_ONLY) &&
616 base().get()->repo->name == sat::Pool::instance().systemRepoName())
618 drop_by_kind_status = true;
622 // whether to drop unwanted kind
623 if (!_pqimpl->_kinds.empty())
625 sat::Solvable s(_sid);
626 // the user wants to filter by kind.
627 if (_pqimpl->_kinds.find(s.kind()) == _pqimpl->_kinds.end())
628 drop_by_kind_status = true;
634 matches = matches && !drop_by_kind_status && !drop_by_repo;
637 if (_do_matching && !drop_by_kind_status)
639 if (!matches && in_repo)
641 SolvAttr attr(base().get()->key->name);
642 PoolQuery::CompiledAttrMap::const_iterator ai = _pqimpl->_rcattrs.find(attr);
643 if (ai != _pqimpl->_rcattrs.end())
645 if ((_pqimpl->_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
647 const regex_t * regex;
648 if (_pqimpl->_rcstrings.empty())
650 map<sat::SolvAttr, regex_t>::const_iterator rai = _pqimpl->_rattrs.find(attr);
651 if (rai != _pqimpl->_rattrs.end())
652 regex = &rai->second;
655 ERR << "no compiled regex found for " << attr << endl;
660 regex = &_pqimpl->_regex;
661 matches = ::dataiterator_match(base().get(), _pqimpl->_cflags, regex);
665 const string & sstr =
666 _pqimpl->_rcstrings.empty() ? ai->second : _pqimpl->_rcstrings;
667 matches = ::dataiterator_match(base().get(), _pqimpl->_cflags, sstr.c_str());
671 /* After calling dataiterator_match (with any string matcher set)
672 the kv.str member will be filled with something sensible. */
673 /* INT << "value: " << base().get()->kv.str << endl
674 << " mstr: " << sstr << endl;*/
681 base_reference().nextSkipRepo();
682 drop_by_repo = false;
684 else if (drop_by_kind_status)
686 base_reference().nextSkipSolvable();
687 drop_by_kind_status = false;
690 // copy the iterator to forward check for the next attribute ***
691 _tmpit = base_reference();
692 _has_next = (*(++_tmpit) != sat::detail::noId);
696 // *** now increment. Had it not be done this way,
697 // the LookupAttr::iterator could have reached the end() while
698 // trying to reach a matching attribute or the next solvable
699 // thus resulting to a problem in the equal() method
701 new_solvable = base().get()->solvid != _sid;
703 _sid = base().get()->solvid;
705 // no more attributes in this repo, return
707 return matches && in_repo; // did the last solvable match conditions?
709 while (!new_solvable || !in_repo);
714 ///////////////////////////////////////////////////////////////////
716 ///////////////////////////////////////////////////////////////////
718 ///////////////////////////////////////////////////////////////////
720 // CLASS NAME : PoolQuery
722 ///////////////////////////////////////////////////////////////////
724 PoolQuery::PoolQuery()
729 PoolQuery::~PoolQuery()
733 void PoolQuery::addRepo(const std::string &repoalias)
735 _pimpl->_repos.insert(repoalias);
736 _pimpl->_flags &= ~SEARCH_ALL_REPOS;
740 void PoolQuery::addKind(const Resolvable::Kind &kind)
741 { _pimpl->_kinds.insert(kind); }
744 void PoolQuery::addString(const string & value)
745 { _pimpl->_strings.insert(value); }
748 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
749 { _pimpl->_attrs[attr].insert(value); }
752 void PoolQuery::setCaseSensitive(const bool value)
755 _pimpl->_flags &= ~SEARCH_NOCASE;
757 _pimpl->_flags |= SEARCH_NOCASE;
761 void PoolQuery::setMatchSubstring()
762 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_SUBSTRING; }
763 void PoolQuery::setMatchExact()
764 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_STRING; }
765 void PoolQuery::setMatchRegex()
766 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX; }
767 void PoolQuery::setMatchGlob()
768 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_GLOB; }
769 void PoolQuery::setMatchWord()
771 _pimpl->_match_word = true;
772 _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
775 void PoolQuery::setFlags(int flags)
776 { _pimpl->_flags = flags; }
779 void PoolQuery::setInstalledOnly()
780 { _pimpl->_status_flags = INSTALLED_ONLY; }
781 void PoolQuery::setUninstalledOnly()
782 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
783 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
784 { _pimpl->_status_flags = flags; }
787 void PoolQuery::setRequireAll(const bool require_all)
788 { _pimpl->_require_all = require_all; }
791 const PoolQuery::StrContainer &
792 PoolQuery::strings() const
793 { return _pimpl->_strings; }
795 const PoolQuery::AttrMap &
796 PoolQuery::attributes() const
797 { return _pimpl->_attrs; }
799 const PoolQuery::Kinds &
800 PoolQuery::kinds() const
801 { return _pimpl->_kinds; }
803 const PoolQuery::StrContainer &
804 PoolQuery::repos() const
805 { return _pimpl->_repos; }
807 bool PoolQuery::caseSensitive() const
808 { return _pimpl->_flags & SEARCH_NOCASE; }
810 bool PoolQuery::matchExact() const
811 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_STRING; }
812 bool PoolQuery::matchSubstring() const
813 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_SUBSTRING; }
814 bool PoolQuery::matchGlob() const
815 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_GLOB; }
816 bool PoolQuery::matchRegex() const
817 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_REGEX; }
818 int PoolQuery::matchType() const
819 { return _pimpl->_flags & SEARCH_STRINGMASK; }
821 bool PoolQuery::matchWord() const
822 { return _pimpl->_match_word; }
824 bool PoolQuery::requireAll() const
825 { return _pimpl->_require_all; }
827 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
828 { return _pimpl->_status_flags; }
830 PoolQuery::const_iterator PoolQuery::begin() const
831 { return _pimpl->begin(); }
834 PoolQuery::const_iterator PoolQuery::end() const
835 { return _pimpl->end(); }
838 bool PoolQuery::empty()
839 { return _pimpl->begin() == _pimpl->end(); }
841 //! \todo collect the result, reuse if not dirty
842 PoolQuery::size_type PoolQuery::size()
845 for(const_iterator it = _pimpl->begin(); it != _pimpl->end(); ++it, ++count);
850 void PoolQuery::execute(ProcessResolvable fnc)
851 { invokeOnEach(_pimpl->begin(), _pimpl->end(), fnc); }
854 ///////////////////////////////////////////////////////////////////
856 // CLASS NAME : PoolQuery::Attr
859 * represents all atributes in PoolQuery except SolvAtributes, which are
860 * used as is (not needed extend anything if someone adds new solv attr)
862 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
865 friend class IdStringType<PoolQueryAttr>;
872 explicit PoolQueryAttr( const char* cstr_r )
876 explicit PoolQueryAttr( const std::string & str_r )
881 static const PoolQueryAttr noAttr;
884 static const PoolQueryAttr repoAttr;
885 static const PoolQueryAttr kindAttr;
886 static const PoolQueryAttr stringAttr;
887 static const PoolQueryAttr stringTypeAttr;
888 static const PoolQueryAttr requireAllAttr;
889 static const PoolQueryAttr caseSensitiveAttr;
890 static const PoolQueryAttr installStatusAttr;
893 const PoolQueryAttr PoolQueryAttr::noAttr;
895 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
896 const PoolQueryAttr PoolQueryAttr::kindAttr( "kind" );
897 const PoolQueryAttr PoolQueryAttr::stringAttr( "global_string" );
898 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("string_type");
899 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
900 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
901 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
903 class StringTypeAttr : public IdStringType<PoolQueryAttr>
905 friend class IdStringType<StringTypeAttr>;
910 explicit StringTypeAttr( const char* cstr_r )
912 explicit StringTypeAttr( const std::string & str_r )
915 static const StringTypeAttr noAttr;
917 static const StringTypeAttr exactAttr;
918 static const StringTypeAttr substringAttr;
919 static const StringTypeAttr regexAttr;
920 static const StringTypeAttr globAttr;
921 static const StringTypeAttr wordAttr;
923 const StringTypeAttr StringTypeAttr::noAttr;
925 const StringTypeAttr StringTypeAttr::exactAttr("exact");
926 const StringTypeAttr StringTypeAttr::substringAttr("substring");
927 const StringTypeAttr StringTypeAttr::regexAttr("regex");
928 const StringTypeAttr StringTypeAttr::globAttr("glob");
929 const StringTypeAttr StringTypeAttr::wordAttr("word");
931 ///////////////////////////////////////////////////////////////////
934 //\TODO maybe ctor with stream can be usefull
935 bool PoolQuery::recover( istream &str, char delim )
937 bool finded_something = false; //indicates some atributes is finded
943 getline( str, s, delim );
945 if ((!s.empty()) && s[0]=='#') //comment
950 string::size_type pos = s.find(':');
951 if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
953 if (finded_something) //is first blank line after record?
963 finded_something = true;
965 string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
966 string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
968 PoolQueryAttr attribute( attrName );
970 if ( attribute==PoolQueryAttr::repoAttr )
972 addRepo( attrValue );
974 else if ( attribute==PoolQueryAttr::kindAttr )
976 addKind( Resolvable::Kind(attrValue) );
978 else if ( attribute==PoolQueryAttr::stringAttr )
980 addString( attrValue );
982 else if ( attribute==PoolQueryAttr::stringTypeAttr )
984 StringTypeAttr s(attrValue);
985 if( s == StringTypeAttr::regexAttr )
989 else if ( s == StringTypeAttr::globAttr )
993 else if ( s == StringTypeAttr::exactAttr )
997 else if ( s == StringTypeAttr::substringAttr )
1001 else if ( s == StringTypeAttr::wordAttr )
1005 else if ( s == StringTypeAttr::noAttr )
1007 WAR << "unknown string type " << attrValue << endl;
1011 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
1014 else if ( attribute==PoolQueryAttr::requireAllAttr )
1016 if ( str::strToTrue(attrValue) )
1018 setRequireAll(true);
1020 else if ( !str::strToFalse(attrValue) )
1022 setRequireAll(false);
1026 WAR << "unknown boolean value " << attrValue << endl;
1029 else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
1031 if ( str::strToTrue(attrValue) )
1033 setCaseSensitive(true);
1035 else if ( !str::strToFalse(attrValue) )
1037 setCaseSensitive(false);
1041 WAR << "unknown boolean value " << attrValue << endl;
1044 else if ( attribute==PoolQueryAttr::installStatusAttr )
1046 if( attrValue == "all" )
1048 setStatusFilterFlags( ALL );
1050 else if( attrValue == "installed" )
1054 else if( attrValue == "not-installed" )
1056 setUninstalledOnly();
1060 WAR << "Unknown value for install status " << attrValue << endl;
1063 else if ( attribute==PoolQueryAttr::noAttr )
1065 WAR << "empty attribute name" << endl;
1069 string s = attrName;
1070 boost::replace_all( s,"_",":" );
1072 addAttribute(a,attrValue);
1077 return finded_something;
1080 void PoolQuery::serialize( ostream &str, char delim ) const
1084 //iterate thrue all settings and write it
1085 static const zypp::PoolQuery q; //not save default options, so create default query example
1087 for_( it, repos().begin(), repos().end() )
1089 str << "repo: " << *it << delim ;
1092 for_( it, kinds().begin(), kinds().end() )
1094 str << "kind: " << it->idStr() << delim ;
1097 if (matchType()!=q.matchType())
1099 switch( matchType() )
1102 str << "string_type: exact" << delim;
1104 case SEARCH_SUBSTRING:
1105 str << "string_type: substring" << delim;
1108 str << "string_type: glob" << delim;
1111 str << "string_type: regex" << delim;
1114 WAR << "unknown match type " << matchType() << endl;
1118 if( caseSensitive() != q.caseSensitive() )
1120 str << "case_sensitive: ";
1121 if (caseSensitive())
1123 str << "on" << delim;
1127 str << "off" << delim;
1131 if( requireAll() != q.requireAll() )
1133 str << "require_all: ";
1136 str << "on" << delim;
1140 str << "off" << delim;
1144 if( statusFilterFlags() != q.statusFilterFlags() )
1146 switch( statusFilterFlags() )
1149 str << "install_status: all" << delim;
1151 case INSTALLED_ONLY:
1152 str << "install_status: installed" << delim;
1154 case UNINSTALLED_ONLY:
1155 str << "install_status: not-installed" << delim;
1160 for_( it, strings().begin(), strings().end() )
1162 str << "global_string: " << *it << delim;
1165 for_( it, attributes().begin(), attributes().end() )
1167 string s = it->first.asString();
1168 boost::replace_all(s,":","_");
1169 for_( it2,it->second.begin(),it->second.end() )
1171 str << s <<": "<< *it2 << delim;
1175 //separating delim - protection
1181 string PoolQuery::asString() const
1182 { return _pimpl->asString(); }
1185 ostream & operator<<( ostream & str, const PoolQuery & obj )
1186 { return str << obj.asString(); }
1188 //internal matching two containers O(n^2)
1189 template <class Container>
1190 bool equalContainers(const Container& a, const Container& b)
1192 if (a.size()!=b.size())
1195 for_(it,a.begin(),a.end())
1197 bool finded = false;
1198 for_( it2, b.begin(),b.end() )
1213 bool PoolQuery::operator==(const PoolQuery& a) const
1215 if (!_pimpl->_compiled)
1217 if (!a._pimpl->_compiled)
1218 a._pimpl->compile();
1219 if( matchType()!=a.matchType() )
1221 if( a.matchWord()!=matchWord())
1223 if( a.requireAll()!=requireAll() )
1225 if(!equalContainers(a.kinds(), kinds()))
1227 if(!equalContainers(a.repos(), repos()))
1229 if(a._pimpl->_rcstrings!=_pimpl->_rcstrings)
1231 if(!equalContainers(a._pimpl->_rcattrs, _pimpl->_rcattrs))
1233 if(a._pimpl->_cflags!= _pimpl->_cflags)
1240 /////////////////////////////////////////////////////////////////
1242 ///////////////////////////////////////////////////////////////////