backup while cleaning up
[platform/upstream/libzypp.git] / zypp / sat / Solvable.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/sat/Solvable.cc
10  *
11 */
12 #include <iostream>
13
14 #include "zypp/base/Logger.h"
15 #include "zypp/base/Gettext.h"
16 #include "zypp/base/Exception.h"
17 #include "zypp/base/Functional.h"
18 #include "zypp/base/Collector.h"
19
20 #include "zypp/sat/detail/PoolImpl.h"
21 #include "zypp/sat/Solvable.h"
22 #include "zypp/Repository.h"
23
24 using std::endl;
25
26 ///////////////////////////////////////////////////////////////////
27 namespace zypp
28 { /////////////////////////////////////////////////////////////////
29   ///////////////////////////////////////////////////////////////////
30   namespace sat
31   { /////////////////////////////////////////////////////////////////
32
33     const Solvable Solvable::nosolvable;
34
35     /////////////////////////////////////////////////////////////////
36
37     ::_Solvable * Solvable::get() const
38     { return myPool().getSolvable( _id ); }
39
40 #define NO_SOLVABLE_RETURN( VAL ) \
41     ::_Solvable * _solvable( get() ); \
42     if ( ! _solvable ) return VAL
43
44     Solvable Solvable::nextInPool() const
45     { return Solvable( myPool().getNextId( _id ) ); }
46
47     Solvable Solvable::nextInRepo() const
48     {
49       NO_SOLVABLE_RETURN( nosolvable );
50       for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
51       {
52         ::_Solvable * nextS( myPool().getSolvable( next ) );
53         if ( nextS && nextS->repo == _solvable->repo )
54         {
55           return Solvable( next );
56         }
57       }
58       return nosolvable;
59     }
60
61     Repository Solvable::repository() const
62     {
63       NO_SOLVABLE_RETURN( Repository::noRepository );
64       return Repository( _solvable->repo );
65     }
66
67     bool Solvable::isSystem() const
68     { return repository().isSystemRepo(); }
69
70     IdString Solvable::ident() const
71     {
72       NO_SOLVABLE_RETURN( IdString() );
73       return IdString( _solvable->name );
74     }
75
76     std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
77     {
78       NO_SOLVABLE_RETURN( std::string() );
79       const char *s = ::repo_lookup_str( _solvable, attr.idStr().id() );
80       return  s ? s : std::string();
81     }
82
83     std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
84     {
85 #warning FIX RETRIEVIENG TRANSLATIONS
86       return lookupStrAttribute( attr );
87    }
88
89     unsigned Solvable::lookupNumAttribute( const SolvAttr & attr ) const
90     {
91       NO_SOLVABLE_RETURN( 0 );
92       return ::repo_lookup_num( _solvable, attr.idStr().id() );
93     }
94
95     bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
96     {
97       NO_SOLVABLE_RETURN( false );
98       return ::repo_lookup_num( _solvable, attr.idStr().id() );
99     }
100
101     std::string Solvable::lookupLocation(unsigned &medianr) const
102     {
103       NO_SOLVABLE_RETURN( std::string() );
104       unsigned int nr;
105       char *l = solvable_get_location(_solvable, &nr);
106       medianr = nr;
107 //     /* XXX This datadir should be part of RepoInfo.  */
108 //     if (repoInfo().type().toEnum() == repo::RepoType::YAST2_e)
109 //       filename = std::string("suse/") + filename;
110       return l ? std::string(l) : std::string();
111     }
112
113     ResKind Solvable::kind() const
114     {
115       NO_SOLVABLE_RETURN( ResKind() );
116       // detect srcpackages by 'arch'
117       switch ( _solvable->arch )
118       {
119         case ARCH_SRC:
120         case ARCH_NOSRC:
121           return ResKind::srcpackage;
122           break;
123       }
124
125       const char * ident = IdString( _solvable->name ).c_str();
126       const char * sep = ::strchr( ident, ':' );
127
128       // no ':' in package names (hopefully)
129       if ( ! sep )
130         return ResKind::package;
131
132       // quick check for well known kinds
133       if ( sep-ident >= 4 )
134       {
135         switch ( ident[3] )
136         {
137 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
138           //             ----v
139           case 'c': OUTS( patch, 5 );       break;
140           case 'd': OUTS( product, 7 );     break;
141           case 'i': OUTS( script, 6 );      break;
142           case 'k': OUTS( package, 7 );     break;
143           case 'm': OUTS( atom, 4 );        break;
144           case 'p': OUTS( srcpackage, 10 ); break;
145           case 's': OUTS( message, 7 );     break;
146           case 't': OUTS( pattern, 7 );     break;
147 #undef OUTS
148         }
149       }
150
151       // an unknown kind
152       return ResKind( std::string( ident, sep-ident ) );
153     }
154
155     bool Solvable::isKind( const ResKind & kind_r ) const
156     {
157       NO_SOLVABLE_RETURN( false );
158
159       // detect srcpackages by 'arch'
160       if ( kind_r == ResKind::srcpackage )
161       {
162         return( _solvable->arch == ARCH_SRC || _solvable->arch == ARCH_NOSRC );
163       }
164
165       // no ':' in package names (hopefully)
166       const char * ident = IdString( _solvable->name ).c_str();
167       if ( kind_r == ResKind::package )
168       {
169         return( ::strchr( ident, ':' ) == 0 );
170       }
171
172       // look for a 'kind:' prefix
173       const char * kind = kind_r.c_str();
174       unsigned     ksize = ::strlen( kind );
175       return( ::strncmp( ident, kind, ksize ) == 0
176               && ident[ksize] == ':' );
177     }
178
179     std::string Solvable::name() const
180     {
181       NO_SOLVABLE_RETURN( std::string() );
182       const char * ident = IdString( _solvable->name ).c_str();
183       const char * sep = ::strchr( ident, ':' );
184       return( sep ? sep+1 : ident );
185     }
186
187     Edition Solvable::edition() const
188     {
189       NO_SOLVABLE_RETURN( Edition() );
190       return Edition( _solvable->evr );
191     }
192
193     Arch Solvable::arch() const
194     {
195       NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
196       switch ( _solvable->arch )
197       {
198         case ARCH_SRC:
199         case ARCH_NOSRC:
200           return Arch_noarch; //ArchId( ARCH_NOARCH );
201           break;
202       }
203       return Arch( IdString(_solvable->arch).asString() );
204       //return ArchId( _solvable->arch );
205     }
206
207     IdString Solvable::vendor() const
208     {
209       NO_SOLVABLE_RETURN( IdString() );
210       return IdString( _solvable->vendor );
211     }
212
213     Capabilities Solvable::operator[]( Dep which_r ) const
214     {
215       switch( which_r.inSwitch() )
216       {
217         case Dep::PROVIDES_e:    return provides();    break;
218         case Dep::REQUIRES_e:    return requires();    break;
219         case Dep::CONFLICTS_e:   return conflicts();   break;
220         case Dep::OBSOLETES_e:   return obsoletes();   break;
221         case Dep::RECOMMENDS_e:  return recommends();  break;
222         case Dep::SUGGESTS_e:    return suggests();    break;
223         case Dep::FRESHENS_e:    return freshens();    break;
224         case Dep::ENHANCES_e:    return enhances();    break;
225         case Dep::SUPPLEMENTS_e: return supplements(); break;
226         case Dep::PREREQUIRES_e: return prerequires(); break;
227       }
228       return Capabilities();
229     }
230
231     inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
232     {
233       return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
234     }
235     Capabilities Solvable::provides() const
236     {
237       NO_SOLVABLE_RETURN( Capabilities() );
238       return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
239     }
240     Capabilities Solvable::requires() const
241     {
242       NO_SOLVABLE_RETURN( Capabilities() );
243       return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
244     }
245     Capabilities Solvable::conflicts() const
246     {
247       NO_SOLVABLE_RETURN( Capabilities() );
248       return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
249     }
250     Capabilities Solvable::obsoletes() const
251     {
252       NO_SOLVABLE_RETURN( Capabilities() );
253       return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
254     }
255     Capabilities Solvable::recommends() const
256     {
257       NO_SOLVABLE_RETURN( Capabilities() );
258       return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
259     }
260     Capabilities Solvable::suggests() const
261     {
262       NO_SOLVABLE_RETURN( Capabilities() );
263       return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
264     }
265     Capabilities Solvable::freshens() const
266     {
267       NO_SOLVABLE_RETURN( Capabilities() );
268       return _getCapabilities( _solvable->repo->idarraydata, _solvable->freshens );
269     }
270     Capabilities Solvable::enhances() const
271     {
272       NO_SOLVABLE_RETURN( Capabilities() );
273       return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
274     }
275     Capabilities Solvable::supplements() const
276     {
277       NO_SOLVABLE_RETURN( Capabilities() );
278       return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
279     }
280     Capabilities Solvable::prerequires() const
281     {
282       NO_SOLVABLE_RETURN( Capabilities() );
283       // prerequires are a subset of requires
284        ::Offset offs = _solvable->requires;
285        return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
286                    : Capabilities();
287     }
288
289     ///////////////////////////////////////////////////////////////////
290     namespace
291     { /////////////////////////////////////////////////////////////////
292       /** Expand \ref Capability and call \c fnc_r for each namescpace:language
293        * dependency. Return #invocations of fnc_r, negative if fnc_r returned
294        * false to indicate abort.
295        */
296       int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
297       {
298         CapDetail detail( cap_r );
299         if ( detail.kind() == CapDetail::EXPRESSION )
300         {
301           switch ( detail.capRel() )
302           {
303             case CapDetail::CAP_AND:
304             case CapDetail::CAP_OR:
305                 // expand
306             {
307               int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
308               if ( res < 0 )
309                 return res; // negative on abort.
310               int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
311               if ( res2 < 0 )
312                 return -res + res2; // negative on abort.
313               return res + res2;
314             }
315             break;
316
317             case CapDetail::CAP_NAMESPACE:
318               if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
319               {
320                 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
321               }
322               break;
323
324             case CapDetail::REL_NONE:
325             case CapDetail::CAP_WITH:
326               break; // unwanted
327           }
328         }
329         return 0;
330       }
331
332        /** Expand \ref Capability and call \c fnc_r for each namescpace:language
333        * dependency. Return #invocations of fnc_r, negative if fnc_r returned
334        * false to indicate abort.
335        */
336       inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
337       {
338         int cnt = 0;
339         for_( cit, cap_r.begin(), cap_r.end() )
340         {
341           int res = invokeOnEachSupportedLocale( *cit, fnc_r );
342           if ( res < 0 )
343             return -cnt + res; // negative on abort.
344           cnt += res;
345         }
346         return cnt;
347       }
348       //@}
349
350       // Functor returning false if a Locale is in the set.
351       struct NoMatchIn
352       {
353         NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
354
355         bool operator()( const Locale & locale_r ) const
356         {
357           return _locales.find( locale_r ) == _locales.end();
358         }
359
360         const LocaleSet & _locales;
361       };
362
363     } /////////////////////////////////////////////////////////////////
364
365     bool Solvable::supportsLocales() const
366     {
367       // false_c stops on 1st Locale.
368       return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
369     }
370
371     bool Solvable::supportsLocale( const Locale & locale_r ) const
372     {
373       // not_equal_to stops on == Locale.
374       return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
375     }
376
377     bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
378     {
379       if ( locales_r.empty() )
380         return false;
381       // NoMatchIn stops if Locale is included.
382       return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
383     }
384
385     bool Solvable::supportsRequestedLocales() const
386     { return supportsLocale( myPool().getRequestedLocales() ); }
387
388     void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
389     {
390       invokeOnEachSupportedLocale( supplements(),
391                                    functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
392     }
393
394     /******************************************************************
395     **
396     **  FUNCTION NAME : operator<<
397     **  FUNCTION TYPE : std::ostream &
398     */
399     std::ostream & operator<<( std::ostream & str, const Solvable & obj )
400     {
401       if ( ! obj )
402         return str << "sat::solvable()";
403
404       return str << "(" << obj.id() << ")"
405           << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
406           << '-' << obj.edition() << '.' << obj.arch() << "("
407           << obj.repository().name() << ")";
408     }
409
410     /******************************************************************
411     **
412     **  FUNCTION NAME : dumpOn
413     **  FUNCTION TYPE : std::ostream &
414     */
415     std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
416     {
417       str << obj;
418       if ( obj )
419       {
420 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
421         OUTS(PROVIDES);
422         OUTS(PREREQUIRES);
423         OUTS(REQUIRES);
424         OUTS(CONFLICTS);
425         OUTS(OBSOLETES);
426         OUTS(RECOMMENDS);
427         OUTS(SUGGESTS);
428         OUTS(FRESHENS);
429         OUTS(ENHANCES);
430         OUTS(SUPPLEMENTS);
431 #undef OUTS
432       }
433       return str;
434     }
435
436     /////////////////////////////////////////////////////////////////
437   } // namespace sat
438   ///////////////////////////////////////////////////////////////////
439   /////////////////////////////////////////////////////////////////
440 } // namespace zypp
441 ///////////////////////////////////////////////////////////////////