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/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 /** Regex-compiled search strings. */
71 mutable string _rcstrings;
72 mutable regex_t _regex;
75 /** Regex-compiled attributes */
76 mutable CompiledAttrMap _rcattrs;
77 mutable map<sat::SolvAttr, regex_t> _rattrs;
79 /** Repos to search. */
81 /** Kinds to search */
84 /** Sat solver search flags */
86 /** Backup of search flags. compile() may change the flags if needed, so
87 * in order to reuse the query, the original flags need to be stored
88 * at the start of compile() */
90 /** Sat solver status flags */
97 /** Sat solver Dataiterator structure */
98 mutable ::_Dataiterator _rdit;
100 mutable bool _compiled;
102 /** Function for processing found solvables. Used in execute(). */
103 mutable PoolQuery::ProcessResolvable _fnc;
106 friend Impl * rwcowClone<Impl>( const Impl * rhs );
107 /** clone for RWCOW_pointer */
109 { return new Impl( *this ); }
113 compileRegex(regex_t * regex, const string & str, bool nocase)
115 /* We feed multiple lines eventually (e.g. authors or descriptions),
116 so set REG_NEWLINE. */
117 if (regcomp(regex, str.c_str(),
118 REG_EXTENDED | REG_NOSUB | REG_NEWLINE | (nocase ? REG_ICASE : 0)) != 0)
119 ZYPP_THROW(Exception(
120 str::form(_("Invalid regular expression '%s'"), str.c_str())));
125 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
127 bool operator()(const string & str)
133 PoolQuery::StrContainer & _cont;
139 bool operator()(const string & str)
146 void PoolQuery::Impl::compile() const
150 // 'different' - will have to iterate through all and match by ourselves (slow)
151 // 'same' - will pass the compiled string to dataiterator_init
152 // 'one-attr' - will pass it to dataiterator_init
153 // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
158 // create regex; store in _rcstrings; if more strings flag regex;
161 _rcstrings = createRegex(_strings);
162 if (_strings.size() > 1)
163 _cflags = (_cflags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;//setMatchRegex();
167 // else if _attrs is not empty but it contains just one attr
168 // for all _strings and _attr[key] strings
169 // create regex; store in _rcattrs; flag 'one-attr'; if more strings flag regex;
170 else if (_attrs.size() == 1)
173 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
174 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
175 _rcstrings = createRegex(joined);
176 _rcattrs.insert(pair<sat::SolvAttr, string>(_attrs.begin()->first, string()));
179 // // MULTIPLE ATTRIBUTES
182 // check whether there are any per-attribute strings
183 bool attrvals_empty = true;
184 for (AttrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
185 if (!ai->second.empty())
186 for(StrContainer::const_iterator it = ai->second.begin();
187 it != ai->second.end(); it++)
190 attrvals_empty = false;
191 goto attremptycheckend;
195 // chceck whether the per-attribute strings are all the same
196 bool attrvals_thesame = true;
197 AttrMap::const_iterator ai = _attrs.begin();
198 const StrContainer & set1 = ai->second;
200 for (; ai != _attrs.end(); ++ai)
204 set1.begin(), set1.end(),
205 ai->second.begin(), ai->second.end(),
206 inserter(result, result.begin())/*, ltstr()*/);
209 attrvals_thesame = false;
214 // // THE SAME STRINGS FOR DIFFERENT ATTRS
215 // else if _attrs is not empty but it does not contain strings
216 // for each key in _attrs take all _strings
217 // create regex; store in _rcattrs and _rcstrings; flag 'same'; if more strings flag regex;
218 if (attrvals_empty || attrvals_thesame)
223 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
224 _rcstrings = createRegex(joined);
228 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
229 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
230 _rcstrings = createRegex(joined);
232 // copy the _attrs keys to _rcattrs
233 for_(ai, _attrs.begin(), _attrs.end())
234 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, string()));
236 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
237 compileRegex(&_regex, _rcstrings, _cflags & SEARCH_NOCASE);
240 // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
241 // if _attrs is not empty and it contains non-empty vectors with non-empty strings
242 // for each key in _attrs take all _strings + all _attrs[key] strings
243 // create regex; store in _rcattrs; flag 'different'; if more strings flag regex;
246 for_(ai, _attrs.begin(), _attrs.end())
249 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
250 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
251 string s = createRegex(joined);
252 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, s));
254 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
257 compileRegex(®ex, s, _cflags & SEARCH_NOCASE);
258 _rattrs.insert(pair<sat::SolvAttr, regex_t>(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;
274 * Converts '*' and '?' wildcards within str into their regex equivalents.
276 static string wildcards2regex(const string & str)
278 string regexed = str;
280 str::regex all("\\*"); // regex to search for '*'
281 str::regex one("\\?"); // regex to search for '?'
282 string r_all(".*"); // regex equivalent of '*'
283 string r_one("."); // regex equivalent of '?'
284 string::size_type pos;
286 // replace all "*" in input with ".*"
287 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
288 regexed = regexed.replace(pos, 1, r_all);
290 // replace all "?" in input with "."
291 for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
292 regexed = regexed.replace(pos, 1, r_one);
294 DBG << " -> " << regexed << endl;
299 //! macro for word boundary tags for regexes
300 #define WB (_match_word ? string("\\b") : string())
302 string PoolQuery::Impl::createRegex(const StrContainer & container) const
306 if (container.empty())
309 if (container.size() == 1)
312 return ".*" + WB + *container.begin() + WB + ".*";
314 return *container.begin();
319 bool use_wildcards = (_cflags & SEARCH_STRINGMASK) == SEARCH_GLOB;
320 StrContainer::const_iterator it = container.begin();
324 tmp = wildcards2regex(*it);
328 if (!(_cflags & SEARCH_STRING)) // not match exact
329 tmp += ".*" + WB + tmp;
330 rstr = "(?=" + tmp + ")";
334 if (_cflags & SEARCH_STRING) // match exact
344 for (; it != container.end(); ++it)
347 tmp = wildcards2regex(*it);
351 if (!(_cflags & SEARCH_STRING)) // not match exact
352 tmp += ".*" + WB + tmp;
353 rstr += "(?=" + tmp + ")";
363 if (!(_cflags & SEARCH_STRING)) // not match exact
369 if (_cflags & SEARCH_STRING) // match exact
379 PoolQuery::const_iterator PoolQuery::Impl::begin() const
383 // if only one repository has been specified, find it in the pool
384 sat::Pool pool(sat::Pool::instance());
385 sat::Pool::RepositoryIterator itr = pool.reposBegin();
386 if (!(_cflags & SEARCH_ALL_REPOS) && _repos.size() == 1)
388 string theone = *_repos.begin();
389 for (; itr->info().alias() != theone && itr != pool.reposEnd(); ++itr);
390 if (itr == pool.reposEnd())
392 RepoInfo info; info.setAlias(theone);
393 ERR << "Repository not found in sat pool." << endl;
394 ZYPP_THROW(repo::RepoNotFoundException(info));
398 DBG << "_cflags:" << _cflags << endl;
400 if (_rcattrs.empty())
402 ::dataiterator_init(&_rdit,
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,
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,
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(
430 str::form(_("Invalid regular expression '%s'"), _rcstrings.c_str())));
432 PoolQuery::const_iterator it(this);
437 PoolQuery::const_iterator PoolQuery::Impl::end() const
439 INT << "end" << endl;
440 return PoolQuery::const_iterator();
444 string PoolQuery::Impl::asString() const
448 o << "compiled: " << _compiled << endl;
451 for(Kinds::const_iterator it = _kinds.begin();
452 it != _kinds.end(); ++it)
457 for(StrContainer::const_iterator it = _repos.begin();
458 it != _repos.end(); ++it)
462 o << "string match flags:" << endl;
463 o << "* string/substring/glob/regex: " << (_cflags & SEARCH_STRINGMASK) << endl;
464 o << "* SEARCH_NOCASE: " << ((_cflags & SEARCH_NOCASE) ? "yes" : "no") << endl;
465 o << "* SEARCH_ALL_REPOS: " << ((_cflags & SEARCH_ALL_REPOS) ? "yes" : "no") << endl;
466 o << "status filter flags:" << _status_flags << endl;
471 for(StrContainer::const_iterator it = _strings.begin();
472 it != _strings.end(); ++it)
476 o << "attributes: " << endl;
477 for(AttrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
479 o << "* " << ai->first << ": ";
480 for(StrContainer::const_iterator vi = ai->second.begin();
481 vi != ai->second.end(); ++vi)
488 o << "compiled strings: " << _rcstrings << endl;
489 o << "compiled attributes:" << endl;
490 for (CompiledAttrMap::const_iterator ai = _rcattrs.begin(); ai != _rcattrs.end(); ++ai)
491 o << "* " << ai->first << ": " << ai->second << endl;
496 /** \relates PoolQuery::Impl Stream output *//*
497 inline std::ostream & operator<<( std::ostream & str, const PoolQuery::Impl & obj )
499 return str << "PoolQuery::Impl";
502 ///////////////////////////////////////////////////////////////////
504 ///////////////////////////////////////////////////////////////////
506 { /////////////////////////////////////////////////////////////////
508 ///////////////////////////////////////////////////////////////////
510 // CLASS NAME : PoolQuery::ResultIterator
512 ///////////////////////////////////////////////////////////////////
514 PoolQueryIterator::PoolQueryIterator(const PoolQuery::Impl * pqimpl)
515 : PoolQueryIterator::iterator_adaptor_(pqimpl ? &pqimpl->_rdit : 0)
516 , _rdit(pqimpl ? &pqimpl->_rdit : 0)
520 , _do_matching(false)
521 , _pool((sat::Pool::instance()))
523 if (_pqimpl->_rcattrs.size() > 1)
527 void PoolQueryIterator::increment()
532 bool got_match = false;
535 DBG << "last: " << _sid << endl;
536 while (_has_next && !(got_match = matchSolvable()));
539 // no more solvables and the last did not match
540 if (!got_match && !_has_next)
542 base_reference() = 0;
546 DBG << "next: " << _sid << endl;
549 bool PoolQueryIterator::matchSolvable()
551 _sid = _rdit->solvid;
553 bool new_solvable = true;
554 bool matches = !_do_matching;
556 bool drop_by_kind_status = false;
557 bool drop_by_repo = false;
560 //! \todo FIXME Dataiterator returning resolvables belonging to current repo?
561 in_repo = _sid >= _rdit->repo->start;
563 if (in_repo && new_solvable)
567 drop_by_repo = false;
568 if (!_pqimpl->_repos.empty() &&
569 _pqimpl->_repos.find(_rdit->repo->name) == _pqimpl->_repos.end())
575 drop_by_kind_status = false;
577 // whether to drop an uninstalled (repo) solvable
578 if ( (_pqimpl->_status_flags & PoolQuery::INSTALLED_ONLY) &&
579 _rdit->repo->name != _pool.systemRepoName() )
581 drop_by_kind_status = true;
585 // whether to drop an installed (target) solvable
586 if ((_pqimpl->_status_flags & PoolQuery::UNINSTALLED_ONLY) &&
587 _rdit->repo->name == _pool.systemRepoName())
589 drop_by_kind_status = true;
593 // whether to drop unwanted kind
594 if (!_pqimpl->_kinds.empty())
596 sat::Solvable s(_sid);
597 // the user wants to filter by kind.
598 if (_pqimpl->_kinds.find(s.kind()) == _pqimpl->_kinds.end())
599 drop_by_kind_status = true;
605 matches = matches && !drop_by_kind_status && !drop_by_repo;
608 if (_do_matching && !drop_by_kind_status)
610 if (!matches && in_repo)
612 SolvAttr attr(_rdit->key->name);
613 PoolQuery::CompiledAttrMap::const_iterator ai = _pqimpl->_rcattrs.find(attr);
614 if (ai != _pqimpl->_rcattrs.end())
616 if ((_pqimpl->_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
618 const regex_t * regex;
619 if (_pqimpl->_rcstrings.empty())
621 map<sat::SolvAttr, regex_t>::const_iterator rai = _pqimpl->_rattrs.find(attr);
622 if (rai != _pqimpl->_rattrs.end())
623 regex = &rai->second;
626 ERR << "no compiled regex found for " << attr << endl;
631 regex = &_pqimpl->_regex;
632 matches = ::dataiterator_match(_rdit, _pqimpl->_cflags, regex);
636 const string & sstr =
637 _pqimpl->_rcstrings.empty() ? ai->second : _pqimpl->_rcstrings;
638 matches = ::dataiterator_match(_rdit, _pqimpl->_cflags, sstr.c_str());
642 /* After calling dataiterator_match (with any string matcher set)
643 the kv.str member will be filled with something sensible. */
644 /* INT << "value: " << _rdit->kv.str << endl
645 << " mstr: " << sstr << endl;*/
652 Repository nextRepo(Repository(_rdit->repo).nextInPool());
653 ::dataiterator_skip_repo(_rdit);
655 ::dataiterator_jump_to_repo(_rdit, nextRepo.get());
656 drop_by_repo = false;
658 else if (drop_by_kind_status)
660 ::dataiterator_skip_solvable(_rdit);
661 drop_by_kind_status = false;
664 if ((_has_next = ::dataiterator_step(_rdit)))
666 new_solvable = _rdit->solvid != _sid;
668 _sid = _rdit->solvid;
670 // no more attributes in this repo, return
673 // check for more repos to jump to
674 if (!_pqimpl->_repos.empty())
676 Repository nextRepo(Repository(_rdit->repo).nextInPool());
679 ::dataiterator_jump_to_repo(_rdit, nextRepo.get());
680 _has_next = ::dataiterator_step(_rdit);
684 // did the last solvable match conditions?
685 return matches && in_repo;
688 while (!new_solvable || !in_repo);
693 ///////////////////////////////////////////////////////////////////
695 ///////////////////////////////////////////////////////////////////
697 ///////////////////////////////////////////////////////////////////
699 // CLASS NAME : PoolQuery
701 ///////////////////////////////////////////////////////////////////
703 PoolQuery::PoolQuery()
708 PoolQuery::~PoolQuery()
712 void PoolQuery::addRepo(const std::string &repoalias)
714 _pimpl->_repos.insert(repoalias);
715 _pimpl->_flags &= ~SEARCH_ALL_REPOS;
719 void PoolQuery::addKind(const Resolvable::Kind &kind)
720 { _pimpl->_kinds.insert(kind); }
723 void PoolQuery::addString(const string & value)
724 { _pimpl->_strings.insert(value); }
727 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
728 { _pimpl->_attrs[attr].insert(value); }
731 void PoolQuery::setCaseSensitive(const bool value)
734 _pimpl->_flags &= ~SEARCH_NOCASE;
736 _pimpl->_flags |= SEARCH_NOCASE;
740 void PoolQuery::setMatchSubstring()
741 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_SUBSTRING; }
742 void PoolQuery::setMatchExact()
743 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_STRING; }
744 void PoolQuery::setMatchRegex()
745 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX; }
746 void PoolQuery::setMatchGlob()
747 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_GLOB; }
748 void PoolQuery::setMatchWord()
750 _pimpl->_match_word = true;
751 _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
754 void PoolQuery::setFlags(int flags)
755 { _pimpl->_flags = flags; }
758 void PoolQuery::setInstalledOnly()
759 { _pimpl->_status_flags = INSTALLED_ONLY; }
760 void PoolQuery::setUninstalledOnly()
761 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
762 void PoolQuery::setStatusFilterFlags( int flags )
763 { _pimpl->_status_flags = flags; }
766 void PoolQuery::setRequireAll(const bool require_all)
767 { _pimpl->_require_all = require_all; }
770 const PoolQuery::StrContainer &
771 PoolQuery::strings() const
772 { return _pimpl->_strings; }
774 const PoolQuery::AttrMap &
775 PoolQuery::attributes() const
776 { return _pimpl->_attrs; }
778 const PoolQuery::Kinds &
779 PoolQuery::kinds() const
780 { return _pimpl->_kinds; }
782 const PoolQuery::StrContainer &
783 PoolQuery::repos() const
784 { return _pimpl->_repos; }
786 bool PoolQuery::caseSensitive() const
787 { return _pimpl->_flags & SEARCH_NOCASE; }
789 bool PoolQuery::matchExact() const
790 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_STRING; }
791 bool PoolQuery::matchSubstring() const
792 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_SUBSTRING; }
793 bool PoolQuery::matchGlob() const
794 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_GLOB; }
795 bool PoolQuery::matchRegex() const
796 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_REGEX; }
797 int PoolQuery::matchType() const
798 { return _pimpl->_flags & SEARCH_STRINGMASK; }
800 bool PoolQuery::matchWord() const
801 { return _pimpl->_match_word; }
803 bool PoolQuery::requireAll() const
804 { return _pimpl->_require_all; }
808 PoolQuery::const_iterator PoolQuery::begin() const
809 { return _pimpl->begin(); }
812 PoolQuery::const_iterator PoolQuery::end() const
813 { return _pimpl->end(); }
816 bool PoolQuery::empty()
817 { return _pimpl->begin() == _pimpl->end(); }
819 //! \todo collect the result, reuse if not dirty
820 PoolQuery::size_type PoolQuery::size()
823 for(const_iterator it = _pimpl->begin(); it != _pimpl->end(); ++it, ++count);
828 void PoolQuery::execute(ProcessResolvable fnc)
829 { invokeOnEach(_pimpl->begin(), _pimpl->end(), fnc); }
832 ///////////////////////////////////////////////////////////////////
834 // CLASS NAME : PoolQuery::Attr
837 * represents all atributes in PoolQuery except SolvAtributes, which are
838 * used as is (not needed extend anything if someone adds new solv attr)
840 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
843 friend class IdStringType<PoolQueryAttr>;
850 PoolQueryAttr():isSolvAttr(false){}
852 explicit PoolQueryAttr( const char* cstr_r )
853 : _str( cstr_r ),isSolvAttr(false){}
855 explicit PoolQueryAttr( const std::string & str_r )
856 : _str( str_r ),isSolvAttr(false)
860 boost::replace_all(s,"_",":");
861 sa = sat::SolvAttr(s);
862 if( sa != sat::SolvAttr::noAttr )
869 const sat::SolvAttr& solvAttr() { return sa;}
872 static const PoolQueryAttr noAttr;
875 static const PoolQueryAttr repoAttr;
876 static const PoolQueryAttr kindAttr;
878 // exported attributes from SolvAtributes
882 const PoolQueryAttr PoolQueryAttr::noAttr;
884 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
885 const PoolQueryAttr PoolQueryAttr::kindAttr( "kind" );
887 ///////////////////////////////////////////////////////////////////
890 //\TODO maybe ctor with stream can be usefull
891 bool PoolQuery::recover( istream &str, char delim )
893 bool finded_something = false; //indicates some atributes is finded
899 getline( str, s, delim );
901 if ((!s.empty()) && s[0]=='#') //comment
906 string::size_type pos = s.find(':');
907 if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
909 if (finded_something) //is first blank line after record?
919 finded_something = true;
921 string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
922 string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
924 PoolQueryAttr attribute( attrName );
926 if ( attribute==PoolQueryAttr::repoAttr )
928 addRepo( attrValue );
930 else if ( attribute==PoolQueryAttr::kindAttr )
932 addKind( Resolvable::Kind(attrValue) );
934 else if ( attribute==PoolQueryAttr::noAttr )
936 if (attribute.isSolvAttr)
938 addAttribute(attribute.solvAttr(),attrValue);
942 WAR << "unknown attribute " << attrName << endl;
947 WAR << "forget recover some attribute defined as PoolQuery attribute: " << attrName << endl;
952 return finded_something;
955 void PoolQuery::serialize( ostream &str, char delim ) const
959 //iterate thrue all settings and write it
961 for_( it, _pimpl->_repos.begin(), _pimpl->_repos.end() )
963 str << "repo: " << *it << delim ;
966 for_( it, _pimpl->_kinds.begin(), _pimpl->_kinds.end() )
968 str << "kind: " << it->idStr() << delim ;
971 //separating delim - protection
977 string PoolQuery::asString() const
978 { return _pimpl->asString(); }
981 ostream & operator<<( ostream & str, const PoolQuery & obj )
982 { return str << obj.asString(); }
984 //internal matching two containers O(n^2)
985 template <class Container>
986 bool equalContainers(const Container& a, const Container& b)
988 if (a.size()!=b.size())
991 for_(it,a.begin(),a.end())
994 for_( it2, b.begin(),b.end() )
1009 bool PoolQuery::operator==(const PoolQuery& a) const
1011 if (!_pimpl->_compiled)
1013 if (!a._pimpl->_compiled)
1014 a._pimpl->compile();
1015 if( matchType()!=a.matchType() )
1017 if( a.matchWord()!=matchWord())
1019 if( a.requireAll()!=requireAll() )
1021 if(!equalContainers(a.kinds(), kinds()))
1023 if(!equalContainers(a.repos(), repos()))
1025 if(a._pimpl->_rcstrings!=_pimpl->_rcstrings)
1027 if(!equalContainers(a._pimpl->_rcattrs, _pimpl->_rcattrs))
1029 if(a._pimpl->_cflags!= _pimpl->_cflags)
1036 /////////////////////////////////////////////////////////////////
1038 ///////////////////////////////////////////////////////////////////