initial implementation of serialize/recovery PoolQuery (needed by FATE #120118)
[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 <list>
14 #include <vector>
15 #include <algorithm>
16
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/PtrTypes.h"
19 #include "zypp/base/DefaultIntegral.h"
20 #include "zypp/PoolQuery.h"
21 #include "zypp/base/UserRequestException.h"
22
23 #include "zypp/sat/Pool.h"
24 #include "zypp/sat/Solvable.h"
25 #include "zypp/sat/SolvAttr.h"
26
27 extern "C"
28 {
29 #include "satsolver/repo.h"
30 }
31
32 using namespace std;
33
34 ///////////////////////////////////////////////////////////////////
35 namespace zypp
36 { /////////////////////////////////////////////////////////////////
37
38   struct PoolQuery::Impl
39   {
40
41     Impl()
42       : _flags( 0 | SEARCH_NOCASE | SEARCH_SUBSTRING )
43       , _status_flags(ALL)
44     {}
45
46     ~Impl()
47     {
48       //MIL << std::endl;
49     }
50
51   public:
52
53     static int repo_search_cb(void *cbdata, ::Solvable *s, ::Repodata *data, ::Repokey *key, ::KeyValue *kv)
54     {
55       PoolQuery *me = (PoolQuery*) cbdata;
56
57       bool r = false;
58
59       sat::Solvable solvable(s - sat::Pool::instance().get()->solvables);
60
61       // now filter by kind here (we cant do it before)
62       if ( ! me->_pimpl->_kinds.empty() )
63       {
64         // the user wants to filter by kind.
65         if ( find( me->_pimpl->_kinds.begin(),
66                    me->_pimpl->_kinds.end(),
67                    solvable.kind() )
68              == me->_pimpl->_kinds.end() )
69         {
70           // we did not find the kind in the list
71           // so this is not a result.
72           return SEARCH_NEXT_SOLVABLE;
73         }
74       }
75
76       if (me->_pimpl->_fnc)
77         r = me->_pimpl->_fnc( makeResObject(solvable) );
78       
79       if (!r)
80         return SEARCH_STOP;
81       return SEARCH_NEXT_SOLVABLE;
82     }
83
84     vector<string> _repos;
85     vector<string> _names;
86     vector<Resolvable::Kind> _kinds;
87     int _flags;
88     int _status_flags;
89     mutable PoolQuery::ProcessResolvable _fnc;
90   private:
91     friend Impl * rwcowClone<Impl>( const Impl * rhs );
92     /** clone for RWCOW_pointer */
93     Impl * clone() const
94     { return new Impl( *this ); }
95   };
96   ///////////////////////////////////////////////////////////////////
97
98   /** \relates PoolQuery::Impl Stream output */
99   inline std::ostream & operator<<( std::ostream & str, const PoolQuery::Impl & obj )
100   {
101     return str << "PoolQuery::Impl";
102   }
103
104   ///////////////////////////////////////////////////////////////////
105   //
106   //    CLASS NAME : PoolQuery
107   //
108   ///////////////////////////////////////////////////////////////////
109
110   PoolQuery::PoolQuery()
111     : _pimpl(new Impl())
112   {}
113
114   PoolQuery::~PoolQuery()
115   {}
116
117   void PoolQuery::addKind(const Resolvable::Kind &kind)
118   { _pimpl->_kinds.push_back(kind); }
119
120   void PoolQuery::setCaseSensitive(const bool value)
121   {
122     if (value)
123       _pimpl->_flags = (_pimpl->_flags &  ~SEARCH_NOCASE);
124     else
125       _pimpl->_flags = (_pimpl->_flags | SEARCH_NOCASE);
126   }
127
128   void PoolQuery::setMatchExact(const bool value)
129   {
130     if (value)
131     {
132       _pimpl->_flags = (_pimpl->_flags | SEARCH_STRING);
133       _pimpl->_flags = (_pimpl->_flags &  ~SEARCH_REGEX);
134       _pimpl->_flags = (_pimpl->_flags &  ~SEARCH_SUBSTRING);
135       _pimpl->_flags = (_pimpl->_flags &  ~SEARCH_GLOB);
136     }
137     else
138     {
139       _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRING);
140     }
141   }
142
143   void PoolQuery::addRepo(const std::string &repoalias)
144   {  _pimpl->_repos.push_back(repoalias);  }
145
146   void PoolQuery::setFlags(int flags)
147   { _pimpl->_flags = flags; }
148
149   void PoolQuery::setInstalledOnly()
150   {
151     _pimpl->_status_flags = (_pimpl->_status_flags | INSTALLED_ONLY);
152   }
153
154   void PoolQuery::setUninstalledOnly()
155   {
156     _pimpl->_status_flags = (_pimpl->_status_flags | UNINSTALLED_ONLY);
157   }
158
159   void PoolQuery::setStatusFilterFlags( int flags )
160   {
161     _pimpl->_status_flags = (_pimpl->_status_flags | flags);
162   }
163   
164   void PoolQuery::execute(const string &term, ProcessResolvable fnc) const
165   {
166     _pimpl->_fnc = fnc;
167
168     sat::Pool pool(sat::Pool::instance());
169     for ( sat::Pool::RepositoryIterator itr = pool.reposBegin();
170           itr != pool.reposEnd();
171           ++itr )
172     {
173       // filter by installed uninstalled
174       if ( ( _pimpl->_status_flags & INSTALLED_ONLY ) && (itr->name() != sat::Pool::instance().systemRepoName()) )
175         continue;
176
177       if ( ( _pimpl->_status_flags & UNINSTALLED_ONLY ) && (itr->name() == sat::Pool::instance().systemRepoName()) )
178         continue;
179
180       // is this repo in users repos?
181       bool included = ( find(_pimpl->_repos.begin(), _pimpl->_repos.end(), itr->name()) != _pimpl->_repos.end() );
182
183       // only look in user repos filter if the filter is not empty
184       // in this case we search in all
185       if ( _pimpl->_repos.empty() || included  )
186       {
187         repo_search( itr->get(), 0, 0, term.c_str(), _pimpl->_flags, Impl::repo_search_cb, (void*) (this));
188       }
189
190     }
191   }
192   
193   /******************************************************************
194   **
195   **    FUNCTION NAME : operator<<
196   **    FUNCTION TYPE : ostream &
197   */
198   ostream & operator<<( ostream & str, const PoolQuery & obj )
199   {
200     return str;
201   }
202   
203
204   /**
205    * represents all atributes in PoolQuery except SolvAtributes, which is
206    * used as is (not needed extend anythink if someone add new solv attr)
207    */
208   struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
209   {
210     private:
211       friend class IdStringType<PoolQueryAttr>;
212       IdString _str;
213
214     public:
215     
216     //noAttr
217     PoolQueryAttr():isSolvAttr(false){}
218
219     explicit PoolQueryAttr( const char* cstr_r )
220         : _str( cstr_r ),isSolvAttr(false){}
221
222     explicit PoolQueryAttr( const std::string & str_r )
223         : _str( str_r ),isSolvAttr(false)
224     {
225       if( _str==noAttr ){
226         sat::SolvAttr sa(str_r);
227         if( sa != sat::SolvAttr::noAttr )
228         {
229           isSolvAttr = true; 
230         }
231       }
232     }
233
234     //unknown atributes
235     static const PoolQueryAttr noAttr;
236
237     // own attributes
238     static const PoolQueryAttr nameAttr;
239     static const PoolQueryAttr repoAttr;
240     static const PoolQueryAttr kindAttr;
241
242     // exported attributes from SolvAtributes
243     bool isSolvAttr;
244   };
245
246   const PoolQueryAttr PoolQueryAttr::noAttr;
247
248   const PoolQueryAttr PoolQueryAttr::nameAttr( "name" );
249   const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
250   const PoolQueryAttr PoolQueryAttr::kindAttr( "kind" );
251
252   //\TODO maybe ctor with stream can be usefull
253   bool PoolQuery::recover( istream &str, char delim )
254   {
255     bool finded_something = false; //indicates some atributes is finded
256     string s;
257     do {
258       if ( str.eof() )
259         break;
260
261       getline( str, s, delim );
262
263       if ((!s.empty()) && s[0]=='#') //comment
264       {
265         continue;
266       }
267
268       string::size_type pos = s.find(':');
269       if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
270       {
271         if (finded_something) //is first blank line after record?
272         {
273           break;
274         }
275         else
276         {
277           continue;
278         }
279       }
280
281       finded_something = true;
282
283       string atrName(str::trim(string(s,0,pos))); // trimmed name of atribute
284       string atrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
285
286       PoolQueryAttr attribute( atrName );
287
288       if ( attribute==PoolQueryAttr::nameAttr)
289       {
290         //setName...maybe some regex test
291         break;
292       }
293       else if ( attribute==PoolQueryAttr::repoAttr )
294       {
295         addRepo( atrValue );
296       }
297       else if ( attribute==PoolQueryAttr::kindAttr )
298       {
299         addKind( Resolvable::Kind(atrValue) );
300       }
301       else if ( attribute==PoolQueryAttr::noAttr )
302       {
303         if (attribute.isSolvAttr)
304         {
305           //setAtribute
306         }
307         else
308         {
309           //log unknwon atribute
310         }
311       }
312       else
313       {
314         //some forget handle new atribute
315         ;
316       }
317       
318     } while ( true );
319
320     return finded_something;
321   }
322
323   void PoolQuery::serialize( ostream &str, char delim )
324   {
325     //separating delim
326     str << delim; 
327     //iterate thrue all settings and write it
328     
329     for_( it, _pimpl->_repos.begin(), _pimpl->_repos.end() )
330     {
331       str << "repo: " << *it << delim ;
332     }
333
334     for_( it, _pimpl->_kinds.begin(), _pimpl->_kinds.end() )
335     {
336       str << "kind: " << it->idStr() << delim ;
337     }
338
339     //separating delim - protection
340     str << delim; 
341
342   }
343      
344
345   /////////////////////////////////////////////////////////////////
346 } // namespace zypp
347 ///////////////////////////////////////////////////////////////////
348