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/Algorithm.h"
19 #include "zypp/base/String.h"
20 #include "zypp/repo/RepoException.h"
22 #include "zypp/sat/Pool.h"
23 #include "zypp/sat/Solvable.h"
25 #include "zypp/PoolQuery.h"
29 #include "satsolver/repo.h"
33 using namespace zypp::sat;
35 ///////////////////////////////////////////////////////////////////
37 { /////////////////////////////////////////////////////////////////
39 ///////////////////////////////////////////////////////////////////
41 // CLASS NAME : PoolQuery::Impl
47 : _flags( SEARCH_ALL_REPOS | SEARCH_NOCASE | SEARCH_SUBSTRING )
58 const_iterator begin() const;
59 const_iterator end() const;
61 string asString() const;
65 string createRegex(const StrContainer & container) const;
68 /** Raw search strings. */
69 StrContainer _strings;
70 /** Compiled search strings. */
71 mutable string _rcstrings;
72 /** Compiled regex struct */
73 mutable str::regex _regex;
76 /** Regex-compiled attributes */
77 mutable AttrCompiledStrMap _rcattrs;
78 mutable AttrRegexMap _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 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 ); }
110 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
112 bool operator()(const string & str)
118 PoolQuery::StrContainer & _cont;
124 bool operator()(const string & str)
131 void PoolQuery::Impl::compile() const
135 // 'different' - will have to iterate through all and match by ourselves (slow)
136 // 'same' - will pass the compiled string to dataiterator_init
137 // 'one-attr' - will pass it to dataiterator_init
138 // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
143 // create regex; store in _rcstrings; if more strings flag regex;
146 _rcstrings = createRegex(_strings);
147 if (_strings.size() > 1)
148 _cflags = (_cflags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;//setMatchRegex();
152 // else if _attrs is not empty but it contains just one attr
153 // for all _strings and _attr[key] strings
154 // create regex; store in _rcattrs; flag 'one-attr'; if more strings flag regex;
155 else if (_attrs.size() == 1)
158 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
159 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
160 _rcstrings = createRegex(joined);
161 _rcattrs.insert(pair<sat::SolvAttr, string>(_attrs.begin()->first, string()));
164 // // MULTIPLE ATTRIBUTES
167 // check whether there are any per-attribute strings
168 bool attrvals_empty = true;
169 for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
170 if (!ai->second.empty())
171 for(StrContainer::const_iterator it = ai->second.begin();
172 it != ai->second.end(); it++)
175 attrvals_empty = false;
176 goto attremptycheckend;
180 // chceck whether the per-attribute strings are all the same
181 bool attrvals_thesame = true;
182 AttrRawStrMap::const_iterator ai = _attrs.begin();
183 const StrContainer & set1 = ai->second;
185 for (; ai != _attrs.end(); ++ai)
189 set1.begin(), set1.end(),
190 ai->second.begin(), ai->second.end(),
191 inserter(result, result.begin())/*, ltstr()*/);
194 attrvals_thesame = false;
199 // // THE SAME STRINGS FOR DIFFERENT ATTRS
200 // else if _attrs is not empty but it does not contain strings
201 // for each key in _attrs take all _strings
202 // create regex; store in _rcattrs and _rcstrings; flag 'same'; if more strings flag regex;
203 if (attrvals_empty || attrvals_thesame)
208 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
209 _rcstrings = createRegex(joined);
213 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
214 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
215 _rcstrings = createRegex(joined);
217 // copy the _attrs keys to _rcattrs
218 for_(ai, _attrs.begin(), _attrs.end())
219 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, string()));
221 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
222 /* We feed multiple lines eventually (e.g. authors or descriptions), so set REG_NEWLINE. */
223 _regex = str::regex(_rcstrings, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | (_cflags & SEARCH_NOCASE ? REG_ICASE : 0));
226 // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
227 // if _attrs is not empty and it contains non-empty vectors with non-empty strings
228 // for each key in _attrs take all _strings + all _attrs[key] strings
229 // create regex; store in _rcattrs; flag 'different'; if more strings flag regex;
232 for_(ai, _attrs.begin(), _attrs.end())
235 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
236 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
237 string s = createRegex(joined);
238 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, s));
240 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
242 str::regex regex(s, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | (_cflags & SEARCH_NOCASE ? REG_ICASE : 0));
243 _rattrs.insert(pair<sat::SolvAttr, str::regex>(ai->first, regex));
249 // tell the Dataiterator to search only in one repo if only one specified
250 if (_repos.size() == 1)
251 _cflags &= ~SEARCH_ALL_REPOS;
255 DBG << asString() << endl;
259 * Converts '*' and '?' wildcards within str into their regex equivalents.
261 static string wildcards2regex(const string & str)
263 string regexed = str;
265 str::regex all("\\*"); // regex to search for '*'
266 str::regex one("\\?"); // regex to search for '?'
267 string r_all(".*"); // regex equivalent of '*'
268 string r_one("."); // regex equivalent of '?'
269 string::size_type pos;
271 // replace all "*" in input with ".*"
272 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
273 regexed = regexed.replace(pos, 1, r_all);
275 // replace all "?" in input with "."
276 for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
277 regexed = regexed.replace(pos, 1, r_one);
279 DBG << " -> " << regexed << endl;
284 //! macro for word boundary tags for regexes
285 #define WB (_match_word ? string("\\b") : string())
287 string PoolQuery::Impl::createRegex(const StrContainer & container) const
291 if (container.empty())
294 if (container.size() == 1)
297 return ".*" + WB + *container.begin() + WB + ".*";
299 return *container.begin();
304 bool use_wildcards = (_cflags & SEARCH_STRINGMASK) == SEARCH_GLOB;
305 StrContainer::const_iterator it = container.begin();
309 tmp = wildcards2regex(*it);
313 if (!(_cflags & SEARCH_STRING)) // not match exact
314 tmp += ".*" + WB + tmp;
315 rstr = "(?=" + tmp + ")";
319 if (_cflags & SEARCH_STRING) // match exact
329 for (; it != container.end(); ++it)
332 tmp = wildcards2regex(*it);
336 if (!(_cflags & SEARCH_STRING)) // not match exact
337 tmp += ".*" + WB + tmp;
338 rstr += "(?=" + tmp + ")";
348 if (!(_cflags & SEARCH_STRING)) // not match exact
354 if (_cflags & SEARCH_STRING) // match exact
364 PoolQuery::const_iterator PoolQuery::Impl::begin() const
368 // if only one repository has been specified, find it in the pool
369 sat::Pool pool(sat::Pool::instance());
370 sat::Pool::RepositoryIterator itr = pool.reposBegin();
371 if (!(_cflags & SEARCH_ALL_REPOS) && _repos.size() == 1)
373 string theone = *_repos.begin();
374 for (; itr->info().alias() != theone && itr != pool.reposEnd(); ++itr);
375 if (itr == pool.reposEnd())
377 RepoInfo info; info.setAlias(theone);
378 ERR << "Repository not found in sat pool." << endl;
379 ZYPP_THROW(repo::RepoNotFoundException(info));
383 DBG << "_cflags:" << _cflags << endl;
385 scoped_ptr< ::_Dataiterator> _rdit( new ::Dataiterator );
386 // needed while LookupAttr::iterator::dip_equal does ::memcmp:
387 ::memset( _rdit.get(), 0, sizeof(::_Dataiterator) );
389 if (_rcattrs.empty())
391 ::dataiterator_init(_rdit.get(),
392 _cflags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), // repository \todo fix this
393 0, // search all solvables
394 0, // attribute id - only if 1 attr key specified
395 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
398 else if (_rcattrs.size() == 1)
400 ::dataiterator_init(_rdit.get(),
401 _cflags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), // repository \todo fix this
402 0, // search all solvables
403 _rcattrs.begin()->first.id(), // keyname - attribute id - only if 1 attr key specified
404 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
409 ::dataiterator_init(_rdit.get(),
410 _cflags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), /* repository - switch to next at the end of current one in increment() */
411 0, /*search all resolvables */
412 0, /*keyname - if only 1 attr key specified, pass it here, otherwise do more magic */
413 0, //qs.empty() ? 0 : qs.c_str(), /* create regex, pass it here */
417 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX && _rdit->regex_err != 0)
418 ZYPP_THROW(Exception(str::form(
419 _("Invalid regular expression '%s': regcomp returned %d"),
420 _rcstrings.c_str(), _rdit->regex_err)));
422 PoolQuery::const_iterator it(_rdit, this);
427 PoolQuery::const_iterator PoolQuery::Impl::end() const
429 INT << "end" << endl;
430 return PoolQuery::const_iterator();
434 string PoolQuery::Impl::asString() const
438 o << "compiled: " << _compiled << endl;
441 for(Kinds::const_iterator it = _kinds.begin();
442 it != _kinds.end(); ++it)
447 for(StrContainer::const_iterator it = _repos.begin();
448 it != _repos.end(); ++it)
452 o << "string match flags:" << endl;
453 o << "* string/substring/glob/regex: " << (_cflags & SEARCH_STRINGMASK) << endl;
454 o << "* SEARCH_NOCASE: " << ((_cflags & SEARCH_NOCASE) ? "yes" : "no") << endl;
455 o << "* SEARCH_ALL_REPOS: " << ((_cflags & SEARCH_ALL_REPOS) ? "yes" : "no") << endl;
456 o << "status filter flags:" << _status_flags << endl;
461 for(StrContainer::const_iterator it = _strings.begin();
462 it != _strings.end(); ++it)
466 o << "attributes: " << endl;
467 for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
469 o << "* " << ai->first << ": ";
470 for(StrContainer::const_iterator vi = ai->second.begin();
471 vi != ai->second.end(); ++vi)
478 o << "compiled strings: " << _rcstrings << endl;
479 o << "compiled attributes:" << endl;
480 for (AttrCompiledStrMap::const_iterator ai = _rcattrs.begin(); ai != _rcattrs.end(); ++ai)
481 o << "* " << ai->first << ": " << ai->second << endl;
486 /** \relates PoolQuery::Impl Stream output *//*
487 inline std::ostream & operator<<( std::ostream & str, const PoolQuery::Impl & obj )
489 return str << "PoolQuery::Impl";
492 ///////////////////////////////////////////////////////////////////
494 ///////////////////////////////////////////////////////////////////
496 { /////////////////////////////////////////////////////////////////
498 ///////////////////////////////////////////////////////////////////
500 // CLASS NAME : PoolQuery::ResultIterator
502 ///////////////////////////////////////////////////////////////////
504 PoolQueryIterator::PoolQueryIterator()
505 : _sid(0), _has_next(false), _do_matching(false)
506 { this->base_reference() = LookupAttr::iterator(); }
509 PoolQueryIterator::PoolQueryIterator(
510 scoped_ptr< ::_Dataiterator> & dip_r,
511 const PoolQuery::Impl * pqimpl)
514 , _do_matching(pqimpl->_rcattrs.size() > 1)
515 , _flags(pqimpl->_cflags)
516 , _str(pqimpl->_rcstrings)
517 , _regex(pqimpl->_regex)
518 , _attrs_str(pqimpl->_rcattrs)
519 , _attrs_regex(pqimpl->_rattrs)
520 , _repos(pqimpl->_repos)
521 , _kinds(pqimpl->_kinds)
522 , _status_flags(pqimpl->_status_flags)
524 this->base_reference() = LookupAttr::iterator(dip_r, true); //!\todo pass chain_repos
525 _has_next = (*base_reference() != sat::detail::noId);
529 PoolQueryIterator::PoolQueryIterator(const PoolQueryIterator & rhs)
531 , _has_next(rhs._has_next)
532 , _do_matching(rhs._do_matching)
536 , _attrs_str(rhs._attrs_str)
537 , _attrs_regex(rhs._attrs_regex)
540 , _status_flags(rhs._status_flags)
541 { base_reference() = LookupAttr::iterator(rhs.base()); }
544 PoolQueryIterator::~PoolQueryIterator()
548 PoolQueryIterator & PoolQueryIterator::operator=( const PoolQueryIterator & rhs )
550 base_reference() = rhs.base();
552 _has_next = rhs._has_next;
553 _do_matching = rhs._do_matching;
557 _attrs_str = rhs._attrs_str;
558 _attrs_regex = rhs._attrs_regex;
561 _status_flags = rhs._status_flags;
566 void PoolQueryIterator::increment()
571 bool got_match = false;
574 DBG << "last: " << _sid << endl;
575 while (_has_next && !(got_match = matchSolvable()));
578 // no more solvables and the last did not match
579 if (!got_match && !_has_next)
581 base_reference() = LookupAttr::iterator();
585 DBG << "next: " << _sid << endl;
588 bool PoolQueryIterator::matchSolvable()
590 _sid = base().get()->solvid;
592 bool new_solvable = true;
593 bool matches = !_do_matching;
594 bool drop_by_kind_status = false;
595 bool drop_by_repo = false;
602 drop_by_repo = false;
603 if(!_repos.empty() &&
604 _repos.find(base().get()->repo->name) == _repos.end())
610 drop_by_kind_status = false;
612 // whether to drop an uninstalled (repo) solvable
613 if ( (_status_flags & PoolQuery::INSTALLED_ONLY) &&
614 base().get()->repo->name != sat::Pool::instance().systemRepoName() )
616 drop_by_kind_status = true;
620 // whether to drop an installed (target) solvable
621 if ((_status_flags & PoolQuery::UNINSTALLED_ONLY) &&
622 base().get()->repo->name == sat::Pool::instance().systemRepoName())
624 drop_by_kind_status = true;
628 // whether to drop unwanted kind
631 sat::Solvable s(_sid);
632 // the user wants to filter by kind.
633 if (_kinds.find(s.kind()) == _kinds.end())
634 drop_by_kind_status = true;
640 matches = matches && !drop_by_kind_status && !drop_by_repo;
643 if (_do_matching && !drop_by_kind_status)
647 SolvAttr attr(base().get()->key->name);
648 PoolQuery::AttrCompiledStrMap::const_iterator ai = _attrs_str.find(attr);
649 if (ai != _attrs_str.end())
651 if ((_flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
653 const regex_t * regex_p;
656 PoolQuery::AttrRegexMap::iterator rai = _attrs_regex.find(attr);
657 if (rai != _attrs_regex.end())
658 regex_p = rai->second.get();
661 ERR << "no compiled regex found for " << attr << endl;
666 regex_p = _regex.get();
667 matches = ::dataiterator_match(base().get(), _flags, regex_p);
671 const string & sstr =
672 _str.empty() ? ai->second : _str;
673 matches = ::dataiterator_match(base().get(), _flags, sstr.c_str());
677 /* After calling dataiterator_match (with any string matcher set)
678 the kv.str member will be filled with something sensible. */
679 /* INT << "value: " << base().get()->kv.str << endl
680 << " mstr: " << sstr << endl; */
687 base_reference().nextSkipRepo();
688 drop_by_repo = false;
690 else if (drop_by_kind_status)
692 base_reference().nextSkipSolvable();
693 drop_by_kind_status = false;
696 // copy the iterator to forward check for the next attribute ***
697 _tmpit = base_reference();
698 _has_next = (*(++_tmpit) != sat::detail::noId);
702 // *** now increment. Had it not be done this way,
703 // the LookupAttr::iterator could have reached the end() while
704 // trying to reach a matching attribute or the next solvable
705 // thus resulting to a problem in the equal() method
707 new_solvable = base().get()->solvid != _sid;
709 // no more attributes in this repo, return
711 return matches; // did the last solvable match conditions?
713 while (!new_solvable);
718 ///////////////////////////////////////////////////////////////////
720 ///////////////////////////////////////////////////////////////////
722 ///////////////////////////////////////////////////////////////////
724 // CLASS NAME : PoolQuery
726 ///////////////////////////////////////////////////////////////////
728 PoolQuery::PoolQuery()
733 PoolQuery::~PoolQuery()
737 void PoolQuery::addRepo(const std::string &repoalias)
739 _pimpl->_repos.insert(repoalias);
740 _pimpl->_flags &= ~SEARCH_ALL_REPOS;
744 void PoolQuery::addKind(const ResKind & kind)
745 { _pimpl->_kinds.insert(kind); }
748 void PoolQuery::addString(const string & value)
749 { _pimpl->_strings.insert(value); }
752 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
753 { _pimpl->_attrs[attr].insert(value); }
756 void PoolQuery::setCaseSensitive(const bool value)
759 _pimpl->_flags &= ~SEARCH_NOCASE;
761 _pimpl->_flags |= SEARCH_NOCASE;
765 void PoolQuery::setMatchSubstring()
766 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_SUBSTRING; }
767 void PoolQuery::setMatchExact()
768 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_STRING; }
769 void PoolQuery::setMatchRegex()
770 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX; }
771 void PoolQuery::setMatchGlob()
772 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_GLOB; }
773 void PoolQuery::setMatchWord()
775 _pimpl->_match_word = true;
776 _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
779 void PoolQuery::setFlags(int flags)
780 { _pimpl->_flags = flags; }
783 void PoolQuery::setInstalledOnly()
784 { _pimpl->_status_flags = INSTALLED_ONLY; }
785 void PoolQuery::setUninstalledOnly()
786 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
787 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
788 { _pimpl->_status_flags = flags; }
791 void PoolQuery::setRequireAll(const bool require_all)
792 { _pimpl->_require_all = require_all; }
795 const PoolQuery::StrContainer &
796 PoolQuery::strings() const
797 { return _pimpl->_strings; }
799 const PoolQuery::AttrRawStrMap &
800 PoolQuery::attributes() const
801 { return _pimpl->_attrs; }
803 const PoolQuery::StrContainer &
804 PoolQuery::attribute(const sat::SolvAttr & attr) const
806 static const PoolQuery::StrContainer nocontainer;
807 AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
808 return it != _pimpl->_attrs.end() ? it->second : nocontainer;
811 const PoolQuery::Kinds &
812 PoolQuery::kinds() const
813 { return _pimpl->_kinds; }
815 const PoolQuery::StrContainer &
816 PoolQuery::repos() const
817 { return _pimpl->_repos; }
819 bool PoolQuery::caseSensitive() const
820 { return _pimpl->_flags & SEARCH_NOCASE; }
822 bool PoolQuery::matchExact() const
823 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_STRING; }
824 bool PoolQuery::matchSubstring() const
825 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_SUBSTRING; }
826 bool PoolQuery::matchGlob() const
827 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_GLOB; }
828 bool PoolQuery::matchRegex() const
829 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_REGEX; }
830 int PoolQuery::matchType() const
831 { return _pimpl->_flags & SEARCH_STRINGMASK; }
833 bool PoolQuery::matchWord() const
834 { return _pimpl->_match_word; }
836 bool PoolQuery::requireAll() const
837 { return _pimpl->_require_all; }
839 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
840 { return _pimpl->_status_flags; }
842 PoolQuery::const_iterator PoolQuery::begin() const
843 { return _pimpl->begin(); }
846 PoolQuery::const_iterator PoolQuery::end() const
847 { return _pimpl->end(); }
850 bool PoolQuery::empty()
851 { return _pimpl->begin() == _pimpl->end(); }
853 //! \todo collect the result, reuse if not dirty
854 PoolQuery::size_type PoolQuery::size()
857 for(const_iterator it = _pimpl->begin(); it != _pimpl->end(); ++it, ++count);
862 void PoolQuery::execute(ProcessResolvable fnc)
863 { invokeOnEach(_pimpl->begin(), _pimpl->end(), fnc); }
866 ///////////////////////////////////////////////////////////////////
868 // CLASS NAME : PoolQuery::Attr
871 * represents all atributes in PoolQuery except SolvAtributes, which are
872 * used as is (not needed extend anything if someone adds new solv attr)
874 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
877 friend class IdStringType<PoolQueryAttr>;
884 explicit PoolQueryAttr( const char* cstr_r )
888 explicit PoolQueryAttr( const std::string & str_r )
893 static const PoolQueryAttr noAttr;
896 static const PoolQueryAttr repoAttr;
897 static const PoolQueryAttr kindAttr;
898 static const PoolQueryAttr stringAttr;
899 static const PoolQueryAttr stringTypeAttr;
900 static const PoolQueryAttr requireAllAttr;
901 static const PoolQueryAttr caseSensitiveAttr;
902 static const PoolQueryAttr installStatusAttr;
905 const PoolQueryAttr PoolQueryAttr::noAttr;
907 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
908 const PoolQueryAttr PoolQueryAttr::kindAttr( "kind" );
909 const PoolQueryAttr PoolQueryAttr::stringAttr( "global_string" );
910 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("string_type");
911 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
912 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
913 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
915 class StringTypeAttr : public IdStringType<PoolQueryAttr>
917 friend class IdStringType<StringTypeAttr>;
922 explicit StringTypeAttr( const char* cstr_r )
924 explicit StringTypeAttr( const std::string & str_r )
927 static const StringTypeAttr noAttr;
929 static const StringTypeAttr exactAttr;
930 static const StringTypeAttr substringAttr;
931 static const StringTypeAttr regexAttr;
932 static const StringTypeAttr globAttr;
933 static const StringTypeAttr wordAttr;
935 const StringTypeAttr StringTypeAttr::noAttr;
937 const StringTypeAttr StringTypeAttr::exactAttr("exact");
938 const StringTypeAttr StringTypeAttr::substringAttr("substring");
939 const StringTypeAttr StringTypeAttr::regexAttr("regex");
940 const StringTypeAttr StringTypeAttr::globAttr("glob");
941 const StringTypeAttr StringTypeAttr::wordAttr("word");
943 ///////////////////////////////////////////////////////////////////
946 //\TODO maybe ctor with stream can be usefull
947 bool PoolQuery::recover( istream &str, char delim )
949 bool finded_something = false; //indicates some atributes is finded
955 getline( str, s, delim );
957 if ((!s.empty()) && s[0]=='#') //comment
962 string::size_type pos = s.find(':');
963 if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
965 if (finded_something) //is first blank line after record?
975 finded_something = true;
977 string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
978 string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
980 PoolQueryAttr attribute( attrName );
982 if ( attribute==PoolQueryAttr::repoAttr )
984 addRepo( attrValue );
986 else if ( attribute==PoolQueryAttr::kindAttr )
988 addKind( ResKind(attrValue) );
990 else if ( attribute==PoolQueryAttr::stringAttr )
992 addString( attrValue );
994 else if ( attribute==PoolQueryAttr::stringTypeAttr )
996 StringTypeAttr s(attrValue);
997 if( s == StringTypeAttr::regexAttr )
1001 else if ( s == StringTypeAttr::globAttr )
1005 else if ( s == StringTypeAttr::exactAttr )
1009 else if ( s == StringTypeAttr::substringAttr )
1011 setMatchSubstring();
1013 else if ( s == StringTypeAttr::wordAttr )
1017 else if ( s == StringTypeAttr::noAttr )
1019 WAR << "unknown string type " << attrValue << endl;
1023 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
1026 else if ( attribute==PoolQueryAttr::requireAllAttr )
1028 if ( str::strToTrue(attrValue) )
1030 setRequireAll(true);
1032 else if ( !str::strToFalse(attrValue) )
1034 setRequireAll(false);
1038 WAR << "unknown boolean value " << attrValue << endl;
1041 else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
1043 if ( str::strToTrue(attrValue) )
1045 setCaseSensitive(true);
1047 else if ( !str::strToFalse(attrValue) )
1049 setCaseSensitive(false);
1053 WAR << "unknown boolean value " << attrValue << endl;
1056 else if ( attribute==PoolQueryAttr::installStatusAttr )
1058 if( attrValue == "all" )
1060 setStatusFilterFlags( ALL );
1062 else if( attrValue == "installed" )
1066 else if( attrValue == "not-installed" )
1068 setUninstalledOnly();
1072 WAR << "Unknown value for install status " << attrValue << endl;
1075 else if ( attribute==PoolQueryAttr::noAttr )
1077 WAR << "empty attribute name" << endl;
1081 string s = attrName;
1082 boost::replace_all( s,"_",":" );
1084 addAttribute(a,attrValue);
1089 return finded_something;
1092 void PoolQuery::serialize( ostream &str, char delim ) const
1096 //iterate thrue all settings and write it
1097 static const zypp::PoolQuery q; //not save default options, so create default query example
1099 for_( it, repos().begin(), repos().end() )
1101 str << "repo: " << *it << delim ;
1104 for_( it, kinds().begin(), kinds().end() )
1106 str << "kind: " << it->idStr() << delim ;
1109 if (matchType()!=q.matchType())
1111 switch( matchType() )
1114 str << "string_type: exact" << delim;
1116 case SEARCH_SUBSTRING:
1117 str << "string_type: substring" << delim;
1120 str << "string_type: glob" << delim;
1123 str << "string_type: regex" << delim;
1126 WAR << "unknown match type " << matchType() << endl;
1130 if( caseSensitive() != q.caseSensitive() )
1132 str << "case_sensitive: ";
1133 if (caseSensitive())
1135 str << "on" << delim;
1139 str << "off" << delim;
1143 if( requireAll() != q.requireAll() )
1145 str << "require_all: ";
1148 str << "on" << delim;
1152 str << "off" << delim;
1156 if( statusFilterFlags() != q.statusFilterFlags() )
1158 switch( statusFilterFlags() )
1161 str << "install_status: all" << delim;
1163 case INSTALLED_ONLY:
1164 str << "install_status: installed" << delim;
1166 case UNINSTALLED_ONLY:
1167 str << "install_status: not-installed" << delim;
1172 for_( it, strings().begin(), strings().end() )
1174 str << "global_string: " << *it << delim;
1177 for_( it, attributes().begin(), attributes().end() )
1179 string s = it->first.asString();
1180 boost::replace_all(s,":","_");
1181 for_( it2,it->second.begin(),it->second.end() )
1183 str << s <<": "<< *it2 << delim;
1187 //separating delim - protection
1193 string PoolQuery::asString() const
1194 { return _pimpl->asString(); }
1197 ostream & operator<<( ostream & str, const PoolQuery & obj )
1198 { return str << obj.asString(); }
1200 //internal matching two containers O(n^2)
1201 template <class Container>
1202 bool equalContainers(const Container& a, const Container& b)
1204 if (a.size()!=b.size())
1207 for_(it,a.begin(),a.end())
1209 bool finded = false;
1210 for_( it2, b.begin(),b.end() )
1225 bool PoolQuery::operator==(const PoolQuery& a) const
1227 if (!_pimpl->_compiled)
1229 if (!a._pimpl->_compiled)
1230 a._pimpl->compile();
1231 if( matchType()!=a.matchType() )
1233 if( a.matchWord()!=matchWord())
1235 if( a.requireAll()!=requireAll() )
1237 if(!equalContainers(a.kinds(), kinds()))
1239 if(!equalContainers(a.repos(), repos()))
1241 if(a._pimpl->_rcstrings!=_pimpl->_rcstrings)
1243 if(!equalContainers(a._pimpl->_rcattrs, _pimpl->_rcattrs))
1245 if(a._pimpl->_cflags!= _pimpl->_cflags)
1252 /////////////////////////////////////////////////////////////////
1254 ///////////////////////////////////////////////////////////////////