- PoolQuery backup
[platform/upstream/libzypp.git] / zypp / PoolQuery.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/PoolQuery.cc
10  *
11 */
12 #include <iostream>
13 #include <sstream>
14 #include <list>
15 #include <vector>
16 #include <algorithm>
17
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/PtrTypes.h"
20 #include "zypp/base/DefaultIntegral.h"
21 #include "zypp/base/Regex.h"
22 #include "zypp/base/Algorithm.h"
23 #include "zypp/base/UserRequestException.h"
24 #include "zypp/repo/RepoException.h"
25
26 #include "zypp/sat/Pool.h"
27 #include "zypp/sat/Solvable.h"
28 #include "zypp/sat/SolvAttr.h"
29 #include "zypp/sat/detail/PoolImpl.h"
30
31 #include "zypp/PoolQuery.h"
32
33 using namespace std;
34 using namespace zypp::sat;
35
36 ///////////////////////////////////////////////////////////////////
37 namespace zypp
38 { /////////////////////////////////////////////////////////////////
39
40   ///////////////////////////////////////////////////////////////////
41   //
42   //  CLASS NAME : PoolQuery::Impl
43   //
44   class PoolQuery::Impl
45   {
46   public:
47     Impl()
48       : _flags( SEARCH_ALL_REPOS | SEARCH_NOCASE | SEARCH_SUBSTRING )
49       , _status_flags(ALL)
50       , _match_word(false), _use_wildcards(false)
51       , _require_all(false)
52       , _compiled(false)
53     {}
54
55     ~Impl()
56     {}
57
58   public:
59 /*
60     static int repo_search_cb(void *cbdata, ::Solvable *s, ::Repodata *data, ::Repokey *key, ::KeyValue *kv)
61     {
62       PoolQuery *me = (PoolQuery*) cbdata;
63
64       bool r = false;
65
66       sat::Solvable solvable(s - sat::Pool::instance().get()->solvables);
67
68       // now filter by kind here (we cant do it before)
69       if ( ! me->_pimpl->_kinds.empty() )
70       {
71         // the user wants to filter by kind.
72         if ( find( me->_pimpl->_kinds.begin(),
73                    me->_pimpl->_kinds.end(),
74                    solvable.kind() )
75              == me->_pimpl->_kinds.end() )
76         {
77           // we did not find the kind in the list
78           // so this is not a result.
79           return SEARCH_NEXT_SOLVABLE;
80         }
81       }
82
83       if (me->_pimpl->_fnc)
84         r = me->_pimpl->_fnc( solvable );//makeResObject(solvable) );
85       
86       if (!r)
87         return SEARCH_STOP;
88       return SEARCH_NEXT_SOLVABLE;
89     }
90   */  
91     ResultIterator begin();
92     ResultIterator end();
93     
94     string asString() const;
95     
96   private:
97     void compile();
98     string createRegex(vector<string> & container);
99
100   public:
101     /** Raw search strings. */
102     vector<string> _strings;
103     /** Regex-compiled search strings. */
104     string _rcstrings;
105     /** Raw attributes */
106     AttrMap _attrs;
107     /** Regex-compiled attributes */
108     CompiledAttrMap _rcattrs;
109
110     /** Repos to search. */
111     vector<string> _repos;
112     /** Kinds to search */
113     vector<Resolvable::Kind> _kinds;
114
115     /** Sat solver search flags */
116     int _flags;
117     /** Backup of search flags. compile() may change the flags if needed, so
118      * in order to reuse the query, the original flags need to be stored
119      * at the start of compile() */
120     int _flags_old;
121     /** Sat solver status flags */
122     int _status_flags;
123
124     bool _match_word;
125     bool _use_wildcards;
126
127     bool _require_all;
128
129     /** Sat solver Dataiterator structure */
130     RepoDataIterator _rdit;
131
132     bool _compiled;
133
134     /** Function for processing found solvables. Used in execute(). */
135     mutable PoolQuery::ProcessResolvable _fnc;
136   private:
137     friend Impl * rwcowClone<Impl>( const Impl * rhs );
138     /** clone for RWCOW_pointer */
139     Impl * clone() const
140     { return new Impl( *this ); }
141   };
142 /*
143   template <class _OutputIterator>
144   struct CollectNonEmpty
145   {
146     CollectNonEmpty( _OutputIterator iter_r ) : _iter( iter_r ) {}
147
148     template<class _Tp>
149     bool operator()( const _Tp & value_r ) const
150     {
151       if (value_r.empty())
152         return true;
153       *_iter++ = value_r;
154       return true;
155     }
156
157     private:
158       mutable _OutputIterator _iter;
159   };
160 */
161   void PoolQuery::Impl::compile()
162   {
163     // backup the flags
164     _flags_old = _flags;
165
166     // 'different'         - will have to iterate through all and match by ourselves (slow)
167     // 'same'              - will pass the compiled string to dataiterator_init
168     // 'one-attr'          - will pass it to dataiterator_init
169     // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
170     
171     // // NO ATTRIBUTE
172     // else
173     //   for all _strings
174     //     create regex; store in _rcstrings; if more strings flag regex;
175     if (_attrs.empty())
176     {
177       _rcstrings = createRegex(_strings);
178       if (_strings.size() > 1)
179         _flags = (_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;//setMatchRegex();
180     }
181
182     // // ONE ATTRIBUTE 
183     // else if _attrs is not empty but it contains just one attr
184     //   for all _strings and _attr[key] strings
185     //     create regex; store in _rcattrs; flag 'one-attr'; if more strings flag regex;
186     else if (_attrs.size() == 1)
187     {
188       vector<string> joined;
189       for(vector<string>::const_iterator it = _strings.begin(); it != _strings.end(); ++it)
190         if (!it->empty())
191           joined.push_back(*it);
192       for(vector<string>::const_iterator it = _attrs.begin()->second.begin(); it != _attrs.begin()->second.end(); ++it)
193         if (!it->empty())
194           joined.push_back(*it);
195       _rcstrings = createRegex(joined);
196       _rcattrs.insert(pair<sat::SolvAttr, string>(_attrs.begin()->first, string()));
197     }
198
199
200     // // MULTIPLE ATTRIBUTES
201     else
202     {
203       bool attrvals_empty = true;
204       for (AttrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
205         if (!ai->second.empty())
206           for(vector<string>::const_iterator it = ai->second.begin();
207               it != ai->second.end(); it++)
208             if (!it->empty())
209             {
210               attrvals_empty = false;
211               goto attremptycheckend;
212             }
213
214 attremptycheckend:
215
216       bool attrvals_thesame = true;
217       for (AttrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
218       {
219         
220       }
221
222       // // THE SAME STRINGS FOR DIFFERENT ATTRS
223       // else if _attrs is not empty but it does not contain strings
224       //   for each key in _attrs take all _strings
225       //     create regex; store in _rcattrs and _rcstrings; flag 'same'; if more strings flag regex;
226       if (attrvals_empty || attrvals_thesame)
227       {
228         if (attrvals_empty)
229         {
230           // compile the search string
231           vector<string> joined;
232           for(vector<string>::const_iterator it = _strings.begin(); it != _strings.end(); ++it)
233             if (!it->empty())
234               joined.push_back(*it);
235           _rcstrings = createRegex(joined);
236
237           // copy the _attrs keys to _rcattrs
238           for (AttrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
239             _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, string()));
240         }
241       }
242       // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
243       // if _attrs is not empty and it contains non-empty vectors with non-empty strings
244       //   for each key in _attrs take all _strings + all _attrs[key] strings
245       //     create regex; store in _rcattrs; flag 'different'; if more strings flag regex;
246       else
247       {
248         
249       }
250     }
251
252     // tell the Dataiterator to search only in one repo if only one specified
253     if (_repos.size() == 1)
254       _flags &= ~SEARCH_ALL_REPOS;
255
256     _compiled = true;
257     
258     DBG << asString() << endl;
259   }
260
261   /**
262    * Converts '*' and '?' wildcards within str into their regex equivalents.
263    */
264   static string wildcards2regex(const string & str)
265   {
266     string regexed = str;
267
268     str::regex all("\\*"); // regex to search for '*'
269     str::regex one("\\?"); // regex to search for '?'
270     string r_all(".*"); // regex equivalent of '*'
271     string r_one(".");  // regex equivalent of '?'
272     string::size_type pos;
273
274     // replace all "*" in input with ".*"
275     for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
276       regexed = regexed.replace(pos, 1, r_all);
277
278     // replace all "?" in input with "."
279     for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
280       regexed = regexed.replace(pos, 1, r_one);
281
282     DBG << " -> " << regexed << endl;
283
284     return regexed;
285   }
286
287 //! macro for word boundary tags for regexes
288 #define WB (_match_word ? string("\\b") : string())
289
290   string PoolQuery::Impl::createRegex(vector<string> & container)
291   {
292     string rstr;
293
294     if (container.empty())
295       return rstr;
296
297     if (container.size() == 1)
298     {
299       rstr = *container.begin();
300
301       if (!_use_wildcards && ((_flags & SEARCH_STRINGMASK) != SEARCH_REGEX))
302         return rstr;
303
304       if (_use_wildcards)
305       {
306         rstr = wildcards2regex(rstr);
307       
308         if (_flags & SEARCH_STRING) // match exact
309           rstr = "^" + rstr + "$";
310       }
311
312       rstr = ".*" + WB + rstr + WB + ".*";
313
314       return rstr;
315     }
316
317     // multiple strings
318
319     vector<string>::const_iterator it = container.begin();
320     string tmp;
321
322     if (_use_wildcards)
323       tmp = wildcards2regex(*it);
324
325     if (_require_all)
326     {
327       if (!(_flags & SEARCH_STRING)) // not match exact
328         tmp += ".*" + WB + tmp;
329       rstr = "(?=" + tmp + ")";
330     }
331     else
332     {
333       if (_flags & SEARCH_STRING) // match exact
334         rstr = "^";
335       else
336         rstr = ".*" + WB;
337
338       rstr += "(" + tmp;
339     }
340
341     ++it;
342
343     for (; it != container.end(); ++it)
344     {
345       if (_use_wildcards)
346         tmp = wildcards2regex(*it);
347
348       if (_require_all)
349       {
350         if (!(_flags & SEARCH_STRING)) // not match exact
351           tmp += ".*" + WB + tmp;
352         rstr += "(?=" + tmp + ")";
353       }
354       else
355       {
356         rstr += "|" + tmp;
357       }
358     }
359
360     if (_require_all)
361     {
362       if (!(_flags & SEARCH_STRING)) // not match exact
363         rstr += WB + ".*";
364     }
365     else
366     {
367       rstr += ")";
368       if (_flags & SEARCH_STRING) // match exact
369         rstr += "$";
370       else
371         rstr += WB + ".*";
372     }
373
374     return rstr;
375   }
376
377
378   PoolQuery::ResultIterator PoolQuery::Impl::begin()
379   {
380     compile();
381
382     // if only one repository has been specified, find it in the pool
383     sat::Pool pool(sat::Pool::instance());
384     sat::Pool::RepositoryIterator itr = pool.reposBegin();
385     if (!(_flags & SEARCH_ALL_REPOS) && _repos.size() == 1)
386     {
387       string theone = *_repos.begin();
388       for (; itr->info().alias() != theone && itr != pool.reposEnd(); ++itr);
389       if (itr == pool.reposEnd())
390       {
391         RepoInfo info; info.setAlias(theone);
392         ERR << "Repository not found in sat pool." <<  endl;
393         ZYPP_THROW(repo::RepoNotFoundException(info));
394       }
395     }
396
397     DBG << "_flags:" << _flags << endl;
398
399     if (_rcattrs.empty())
400     {
401     ::dataiterator_init(&_rdit,
402       _flags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), // repository \todo fix this
403       0,                                           // search all solvables
404       0,                                           // attribute id - only if 1 attr key specified
405       _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
406       _flags);
407     }
408     else if (_rcattrs.size() == 1)
409     {
410       ::dataiterator_init(&_rdit,
411         _flags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), // repository \todo fix this 
412         0,                                           // search all solvables
413         _rcattrs.begin()->first.id(),                // keyname - attribute id - only if 1 attr key specified
414         _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string 
415         _flags);
416     }
417     else
418     {
419       ::dataiterator_init(&_rdit,
420         _flags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), /* repository - switch to next at the end of current one in increment() */ 
421         0, /*search all resolvables */
422         0, /*keyname - if only 1 attr key specified, pass it here, otherwise do more magic */
423         0, //qs.empty() ? 0 : qs.c_str(), /* create regex, pass it here */
424         _flags);
425     }
426
427     ImplPtr p(this);
428     PoolQuery::ResultIterator it(p);
429     it.increment();
430     return it;
431   }
432
433   PoolQuery::ResultIterator PoolQuery::Impl::end()
434   {
435     INT << "end" << endl;
436     return PoolQuery::ResultIterator();
437   }
438
439
440   string PoolQuery::Impl::asString() const
441   {
442     ostringstream o;
443
444     o << "compiled: " << _compiled << endl;
445
446     o << "match flags:" << endl;
447     o << "* sat: " << (_flags & SEARCH_STRINGMASK) << endl; 
448     o << "* SEARCH_REGEX: " << ((_flags & SEARCH_STRINGMASK) == SEARCH_REGEX ? "yes" : "no") << endl;
449
450     // raw
451     
452     o << "strings: ";
453     for(vector<string>::const_iterator it = _strings.begin();
454         it != _strings.end(); ++it)
455       o << *it << " ";
456     o << endl;
457
458     o << "attributes: " << endl;
459     for(AttrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
460     {
461       o << "* " << ai->first << ": ";
462       for(vector<string>::const_iterator vi = ai->second.begin();
463           vi != ai->second.end(); ++vi)
464         o << *vi << " ";
465       o << endl;
466     }
467
468     // compiled
469
470     o << "regex compiled strings: " << _rcstrings << endl;
471     o << "regex compiled attributes:" << endl;
472     for (CompiledAttrMap::const_iterator ai = _rcattrs.begin(); ai != _rcattrs.end(); ++ai)
473       o << "* " << ai->first << ": " << ai->second << endl;
474
475     return o.str();
476   }
477
478   /** \relates PoolQuery::Impl Stream output *//*
479   inline std::ostream & operator<<( std::ostream & str, const PoolQuery::Impl & obj )
480   {
481     return str << "PoolQuery::Impl";
482   }
483   */
484   ///////////////////////////////////////////////////////////////////
485
486   ///////////////////////////////////////////////////////////////////
487   //
488   //  CLASS NAME : PoolQuery::ResultIterator
489   //
490   ///////////////////////////////////////////////////////////////////
491
492   PoolQuery::ResultIterator::ResultIterator(ImplPtr pqimpl)
493   : PoolQuery::ResultIterator::iterator_adaptor_(0)
494   , _pqimpl(pqimpl)
495   , _has_next(true)
496   , _attrs(pqimpl->_rcattrs)
497   , _do_matching(false)
498   , _pool((sat::Pool::instance()))
499   {
500     _rdit = &_pqimpl->_rdit;
501     base_reference() = _rdit;
502     _sid = 0; /*rdit > ID_EMPTY ? rdit->solvid : 0;*/
503
504     if (_attrs.size() > 1)
505       _do_matching = true;
506   }
507
508   void PoolQuery::ResultIterator::increment()
509   {
510     if (!_rdit)
511       return;
512
513     bool got_match = false;
514     if (_has_next)
515     {
516       DBG << "last: " << _sid << endl;
517       while (_has_next && !(got_match = matchSolvable()));
518     }
519
520     if (!got_match)
521     {
522       base_reference() = 0;
523       _sid = 0;
524     }
525
526     DBG << "next: " << _sid << endl;
527   }
528
529   bool PoolQuery::ResultIterator::matchSolvable()
530   {
531     _sid = _rdit->solvid;
532
533     bool matches = !_do_matching;
534     bool in_repo;
535     do
536     {
537       //! \todo FIXME Dataiterator returning resolvables belonging to current repo?
538       in_repo = _sid >= _rdit->repo->start; 
539
540       if (_do_matching)
541       {
542         if ( !matches && in_repo /*_sid >= 2 *//*_rdit->repo->start*/)
543         {
544           SolvAttr attr(_rdit->key->name);
545
546           CompiledAttrMap::const_iterator ai = _attrs.find(attr);
547           if (ai != _attrs.end())
548           {
549             // exact match
550             //matches = (ai->second == IdString(_rdit->kv.id).asString());
551             // substring
552             matches = (
553               IdString(_rdit->kv.id).asString().find
554                 (_pqimpl->_rcstrings.empty() ? ai->second : _pqimpl->_rcstrings)
555                 != string::npos);
556             if (matches)
557               INT << "value: " << IdString(_rdit->kv.id).asString() << endl
558                   << " mstr: " <<  (_pqimpl->_rcstrings.empty() ? ai->second : _pqimpl->_rcstrings) << endl; 
559             // regex
560           }
561         }
562       }
563
564       if ((_has_next = ::dataiterator_step(_rdit)))
565       {
566         if (!in_repo /*_sid < 2 *//*_rdit->repo->start*/)
567         {
568           INT << "repo start: " << _rdit->repo->start << endl;
569           _sid = _rdit->solvid;
570         }
571       }
572       else
573       {
574         return matches;
575       }
576     }
577     while (_rdit->solvid == _sid || !in_repo /*_sid < 2 *//*_rdit->repo->start*/);
578
579     return matches;
580   }
581
582   ///////////////////////////////////////////////////////////////////
583   //
584   //    CLASS NAME : PoolQuery
585   //
586   ///////////////////////////////////////////////////////////////////
587
588   PoolQuery::PoolQuery()
589     : _pimpl(new Impl())
590   {}
591
592
593   PoolQuery::~PoolQuery()
594   {}
595
596
597   void PoolQuery::addRepo(const std::string &repoalias)
598   {
599     _pimpl->_repos.push_back(repoalias);
600     _pimpl->_flags &= ~SEARCH_ALL_REPOS;
601   }
602
603
604   void PoolQuery::addKind(const Resolvable::Kind &kind)
605   { _pimpl->_kinds.push_back(kind); }
606
607
608   void PoolQuery::addString(const string & value)
609   { _pimpl->_strings.push_back(value); }
610
611
612   void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
613   { _pimpl->_attrs[attr].push_back(value); }
614
615
616   void PoolQuery::setCaseSensitive(const bool value)
617   {
618     if (value)
619       _pimpl->_flags &= ~SEARCH_NOCASE;
620     else
621       _pimpl->_flags |= SEARCH_NOCASE;
622   }
623
624
625   void PoolQuery::setMatchSubstring()
626   { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_SUBSTRING; }
627   void PoolQuery::setMatchExact()
628   { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_STRING; }
629   void PoolQuery::setMatchRegex()
630   { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX; }
631   void PoolQuery::setMatchWord()
632   {
633     _pimpl->_match_word = true;
634     _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
635   }
636
637
638   void PoolQuery::setFlags(int flags)
639   { _pimpl->_flags = flags; }
640
641
642   void PoolQuery::setInstalledOnly()
643   { _pimpl->_status_flags |= INSTALLED_ONLY; }
644   void PoolQuery::setUninstalledOnly()
645   { _pimpl->_status_flags |= UNINSTALLED_ONLY; }
646   void PoolQuery::setStatusFilterFlags( int flags )
647   { _pimpl->_status_flags |= flags; }
648
649
650   void PoolQuery::requireAll(const bool require_all)
651   { _pimpl->_require_all = require_all; }
652
653
654   PoolQuery::ResultIterator PoolQuery::begin()
655   { return _pimpl->begin(); }
656
657
658   PoolQuery::ResultIterator PoolQuery::end()
659   { return _pimpl->end(); }
660
661
662   bool PoolQuery::empty()
663   { return _pimpl->begin() == _pimpl->end(); }
664
665   //! \todo collect the result, reuse if not dirty
666   PoolQuery::size_type PoolQuery::size()
667   {
668     size_type count = 0;
669     for(ResultIterator it = _pimpl->begin(); it != _pimpl->end(); ++it, ++count);
670     return count;
671   }
672
673
674   void PoolQuery::execute(ProcessResolvable fnc)
675   {
676     invokeOnEach(_pimpl->begin(), _pimpl->end(), fnc);
677     /*
678     _pimpl->_fnc = fnc;
679     string term;
680     if (!_pimpl->_strings.empty())
681       term = *_pimpl->_strings.begin();
682
683     sat::Pool pool(sat::Pool::instance());
684     for ( sat::Pool::RepositoryIterator itr = pool.reposBegin();
685           itr != pool.reposEnd();
686           ++itr )
687     {
688       // filter by installed uninstalled
689       if ( ( _pimpl->_status_flags & INSTALLED_ONLY ) && (itr->name() != sat::Pool::instance().systemRepoName()) )
690         continue;
691
692       if ( ( _pimpl->_status_flags & UNINSTALLED_ONLY ) && (itr->name() == sat::Pool::instance().systemRepoName()) )
693         continue;
694
695       // is this repo in users repos?
696       bool included = ( find(_pimpl->_repos.begin(), _pimpl->_repos.end(), itr->name()) != _pimpl->_repos.end() );
697
698       // only look in user repos filter if the filter is not empty
699       // in this case we search in all
700       if ( _pimpl->_repos.empty() || included  )
701       {
702         repo_search( itr->get(), 0, 0, term.c_str(), _pimpl->_flags, Impl::repo_search_cb, (void*) (this));
703       }
704
705     }
706     */
707   }
708
709   ///////////////////////////////////////////////////////////////////
710   //
711   //  CLASS NAME : PoolQuery::Impl
712   //
713   /**
714    * represents all atributes in PoolQuery except SolvAtributes, which are
715    * used as is (not needed extend anything if someone adds new solv attr)
716    */
717   struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
718   {
719     private:
720       friend class IdStringType<PoolQueryAttr>;
721       IdString _str;
722
723     public:
724     
725     //noAttr
726     PoolQueryAttr():isSolvAttr(false){}
727
728     explicit PoolQueryAttr( const char* cstr_r )
729         : _str( cstr_r ),isSolvAttr(false){}
730
731     explicit PoolQueryAttr( const std::string & str_r )
732         : _str( str_r ),isSolvAttr(false)
733     {
734       if( _str==noAttr ){
735         sat::SolvAttr sa(str_r);
736         if( sa != sat::SolvAttr::noAttr )
737         {
738           isSolvAttr = true; 
739         }
740       }
741     }
742
743     //unknown atributes
744     static const PoolQueryAttr noAttr;
745
746     // own attributes
747     static const PoolQueryAttr nameAttr;
748     static const PoolQueryAttr repoAttr;
749     static const PoolQueryAttr kindAttr;
750
751     // exported attributes from SolvAtributes
752     bool isSolvAttr;
753   };
754
755   const PoolQueryAttr PoolQueryAttr::noAttr;
756
757   const PoolQueryAttr PoolQueryAttr::nameAttr( "name" );
758   const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
759   const PoolQueryAttr PoolQueryAttr::kindAttr( "kind" );
760
761   ///////////////////////////////////////////////////////////////////
762
763
764   //\TODO maybe ctor with stream can be usefull
765   bool PoolQuery::recover( istream &str, char delim )
766   {
767     bool finded_something = false; //indicates some atributes is finded
768     string s;
769     do {
770       if ( str.eof() )
771         break;
772
773       getline( str, s, delim );
774
775       if ((!s.empty()) && s[0]=='#') //comment
776       {
777         continue;
778       }
779
780       string::size_type pos = s.find(':');
781       if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
782       {
783         if (finded_something) //is first blank line after record?
784         {
785           break;
786         }
787         else
788         {
789           continue;
790         }
791       }
792
793       finded_something = true;
794
795       string atrName(str::trim(string(s,0,pos))); // trimmed name of atribute
796       string atrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
797
798       PoolQueryAttr attribute( atrName );
799
800       if ( attribute==PoolQueryAttr::nameAttr)
801       {
802         //setName...maybe some regex test
803         break;
804       }
805       else if ( attribute==PoolQueryAttr::repoAttr )
806       {
807         addRepo( atrValue );
808       }
809       else if ( attribute==PoolQueryAttr::kindAttr )
810       {
811         addKind( Resolvable::Kind(atrValue) );
812       }
813       else if ( attribute==PoolQueryAttr::noAttr )
814       {
815         if (attribute.isSolvAttr)
816         {
817           //setAtribute
818         }
819         else
820         {
821           //log unknwon atribute
822         }
823       }
824       else
825       {
826         //some forget handle new atribute
827         ;
828       }
829       
830     } while ( true );
831
832     return finded_something;
833   }
834
835
836   void PoolQuery::serialize( ostream &str, char delim ) const
837   {
838     //separating delim
839     str << delim; 
840     //iterate thrue all settings and write it
841     
842     for_( it, _pimpl->_repos.begin(), _pimpl->_repos.end() )
843     {
844       str << "repo: " << *it << delim ;
845     }
846
847     for_( it, _pimpl->_kinds.begin(), _pimpl->_kinds.end() )
848     {
849       str << "kind: " << it->idStr() << delim ;
850     }
851
852     //separating delim - protection
853     str << delim; 
854
855   }
856
857
858   string PoolQuery::asString() const
859   { return _pimpl->asString(); }
860
861
862   ostream & operator<<( ostream & str, const PoolQuery & obj )
863   { return str << obj.asString(); }
864
865
866   /////////////////////////////////////////////////////////////////
867 } // namespace zypp
868 ///////////////////////////////////////////////////////////////////
869