Fixed pools package index wrongly including source packages.
[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/sat/Pool.h"
23 #include "zypp/Repository.h"
24 #include "zypp/OnMediaLocation.h"
25
26 using std::endl;
27
28 ///////////////////////////////////////////////////////////////////
29 namespace zypp
30 { /////////////////////////////////////////////////////////////////
31   ///////////////////////////////////////////////////////////////////
32   namespace sat
33   { /////////////////////////////////////////////////////////////////
34
35     Solvable::SplitIdent::SplitIdent( IdString ident_r )
36     {
37       if ( ! ident_r )
38         return;
39
40       const char * ident = ident_r.c_str();
41       const char * sep = ::strchr( ident, ':' );
42
43       // no ':' in package names (hopefully)
44       if ( ! sep )
45       {
46         _kind = ResKind::package;
47         _name = ident_r.asString();
48         return;
49       }
50
51       // save name
52       _name = sep+1;
53       // quick check for well known kinds
54       if ( sep-ident >= 4 )
55       {
56         switch ( ident[3] )
57         {
58 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) _kind = ResKind::K
59           //             ----v
60           case 'c': OUTS( patch, 5 );       return; break;
61           case 'd': OUTS( product, 7 );     return; break;
62           case 'i': OUTS( script, 6 );      return; break;
63           case 'k': OUTS( package, 7 );     return; break;
64           case 'm': OUTS( atom, 4 );        return; break;
65           case 'p': OUTS( srcpackage, 10 ); return; break;
66           case 's': OUTS( message, 7 );     return; break;
67           case 't': OUTS( pattern, 7 );     return; break;
68 #undef OUTS
69         }
70       }
71
72       // an unknown kind
73       _kind = ResKind( std::string( ident, sep-ident ) );
74     }
75
76     /////////////////////////////////////////////////////////////////
77
78     const Solvable Solvable::noSolvable;
79
80     /////////////////////////////////////////////////////////////////
81
82     ::_Solvable * Solvable::get() const
83     { return myPool().getSolvable( _id ); }
84
85 #define NO_SOLVABLE_RETURN( VAL ) \
86     ::_Solvable * _solvable( get() ); \
87     if ( ! _solvable ) return VAL
88
89     Solvable Solvable::nextInPool() const
90     { return Solvable( myPool().getNextId( _id ) ); }
91
92     Solvable Solvable::nextInRepo() const
93     {
94       NO_SOLVABLE_RETURN( noSolvable );
95       for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
96       {
97         ::_Solvable * nextS( myPool().getSolvable( next ) );
98         if ( nextS && nextS->repo == _solvable->repo )
99         {
100           return Solvable( next );
101         }
102       }
103       return noSolvable;
104     }
105
106     Repository Solvable::repository() const
107     {
108       NO_SOLVABLE_RETURN( Repository::noRepository );
109       return Repository( _solvable->repo );
110     }
111
112     bool Solvable::isSystem() const
113     {
114       NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
115       return Repository( _solvable->repo ).isSystemRepo();
116     }
117
118     IdString Solvable::ident() const
119     {
120       NO_SOLVABLE_RETURN( IdString() );
121       return IdString( _solvable->name );
122     }
123
124     std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
125     {
126       NO_SOLVABLE_RETURN( std::string() );
127       const char * s = ::solvable_lookup_str( _solvable, attr.id() );
128       return s ? s : std::string();
129     }
130
131     std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
132     {
133       NO_SOLVABLE_RETURN( std::string() );
134       const char * s = 0;
135       if ( lang_r == Locale::noCode )
136       {
137         s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
138       }
139       else
140       {
141         s = ::solvable_lookup_str_lang( _solvable, attr.id(), lang_r.code().c_str() );
142       }
143       return s ? s : std::string();
144    }
145
146     unsigned Solvable::lookupNumAttribute( const SolvAttr & attr ) const
147     {
148       NO_SOLVABLE_RETURN( 0 );
149       return ::solvable_lookup_num( _solvable, attr.id(), 0 );
150     }
151
152     bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
153     {
154       NO_SOLVABLE_RETURN( false );
155       return ::solvable_lookup_bool( _solvable, attr.id() );
156     }
157
158     detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
159     {
160       NO_SOLVABLE_RETURN( detail::noId );
161       return ::solvable_lookup_id( _solvable, attr.id() );
162     }
163
164     CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
165     {
166       NO_SOLVABLE_RETURN( CheckSum() );
167       detail::IdType chksumtype = 0;
168       const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
169       if ( ! s )
170         return CheckSum();
171       switch ( chksumtype )
172       {
173         case REPOKEY_TYPE_MD5:    return CheckSum::md5( s );
174         case REPOKEY_TYPE_SHA1:   return CheckSum::sha1( s );
175         case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
176       }
177       return CheckSum( std::string(), s ); // try to autodetect
178     }
179
180     OnMediaLocation Solvable::lookupLocation() const
181     //std::string Solvable::lookupLocation( unsigned & medianr ) const
182     {
183       NO_SOLVABLE_RETURN( OnMediaLocation() );
184       // medianumber and path
185       unsigned medianr;
186       char * file = ::solvable_get_location( _solvable, &medianr );
187       if ( ! file )
188         return OnMediaLocation();
189
190       OnMediaLocation ret;
191
192       Pathname path;
193       if ( repository().info().type().toEnum() == repo::RepoType::YAST2_e )
194       {
195 #warning STILL HARDCODED /suse PREFIX in location
196         // (ma@) loading a susetags repo search for a solvable with attribute
197         // susetags:datadir. this is the prefix. store it in RepoInfo(?).
198         path = "suse";
199       }
200       ret.setLocation    ( path/file, medianr );
201       ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ), ByteCount::K ) );
202       ret.setChecksum    ( lookupCheckSumAttribute( SolvAttr::checksum ) );
203       // Not needed/available for solvables?
204       //ret.setOpenSize    ( ByteCount( lookupNumAttribute( SolvAttr::opensize ), ByteCount::K ) );
205       //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
206       return ret;
207     }
208
209     ResKind Solvable::kind() const
210     {
211       NO_SOLVABLE_RETURN( ResKind() );
212       // detect srcpackages by 'arch'
213       switch ( _solvable->arch )
214       {
215         case ARCH_SRC:
216         case ARCH_NOSRC:
217           return ResKind::srcpackage;
218           break;
219       }
220
221       const char * ident = IdString( _solvable->name ).c_str();
222       const char * sep = ::strchr( ident, ':' );
223
224       // no ':' in package names (hopefully)
225       if ( ! sep )
226         return ResKind::package;
227
228       // quick check for well known kinds
229       if ( sep-ident >= 4 )
230       {
231         switch ( ident[3] )
232         {
233 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
234           //             ----v
235           case 'c': OUTS( patch, 5 );       break;
236           case 'd': OUTS( product, 7 );     break;
237           case 'i': OUTS( script, 6 );      break;
238           case 'k': OUTS( package, 7 );     break;
239           case 'm': OUTS( atom, 4 );        break;
240           case 'p': OUTS( srcpackage, 10 ); break;
241           case 's': OUTS( message, 7 );     break;
242           case 't': OUTS( pattern, 7 );     break;
243 #undef OUTS
244         }
245       }
246
247       // an unknown kind
248       return ResKind( std::string( ident, sep-ident ) );
249     }
250
251     bool Solvable::isKind( const ResKind & kind_r ) const
252     {
253       NO_SOLVABLE_RETURN( false );
254
255       // detect srcpackages by 'arch'
256       switch ( _solvable->arch )
257       {
258         case ARCH_SRC:
259         case ARCH_NOSRC:
260           return( kind_r == ResKind::srcpackage );
261           break;
262       }
263
264       // no ':' in package names (hopefully)
265       const char * ident = IdString( _solvable->name ).c_str();
266       if ( kind_r == ResKind::package )
267       {
268         return( ::strchr( ident, ':' ) == 0 );
269       }
270
271       // look for a 'kind:' prefix
272       const char * kind = kind_r.c_str();
273       unsigned     ksize = ::strlen( kind );
274       return( ::strncmp( ident, kind, ksize ) == 0
275               && ident[ksize] == ':' );
276     }
277
278     std::string Solvable::name() const
279     {
280       NO_SOLVABLE_RETURN( std::string() );
281       const char * ident = IdString( _solvable->name ).c_str();
282       const char * sep = ::strchr( ident, ':' );
283       return( sep ? sep+1 : ident );
284     }
285
286     Edition Solvable::edition() const
287     {
288       NO_SOLVABLE_RETURN( Edition() );
289       return Edition( _solvable->evr );
290     }
291
292     Arch Solvable::arch() const
293     {
294       NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
295       switch ( _solvable->arch )
296       {
297         case ARCH_SRC:
298         case ARCH_NOSRC:
299           return Arch_noarch; //ArchId( ARCH_NOARCH );
300           break;
301       }
302       return Arch( IdString(_solvable->arch).asString() );
303       //return ArchId( _solvable->arch );
304     }
305
306     IdString Solvable::vendor() const
307     {
308       NO_SOLVABLE_RETURN( IdString() );
309       return IdString( _solvable->vendor );
310     }
311
312     Capabilities Solvable::operator[]( Dep which_r ) const
313     {
314       switch( which_r.inSwitch() )
315       {
316         case Dep::PROVIDES_e:    return provides();    break;
317         case Dep::REQUIRES_e:    return requires();    break;
318         case Dep::CONFLICTS_e:   return conflicts();   break;
319         case Dep::OBSOLETES_e:   return obsoletes();   break;
320         case Dep::RECOMMENDS_e:  return recommends();  break;
321         case Dep::SUGGESTS_e:    return suggests();    break;
322         case Dep::FRESHENS_e:    return freshens();    break;
323         case Dep::ENHANCES_e:    return enhances();    break;
324         case Dep::SUPPLEMENTS_e: return supplements(); break;
325         case Dep::PREREQUIRES_e: return prerequires(); break;
326       }
327       return Capabilities();
328     }
329
330     inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
331     {
332       return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
333     }
334     Capabilities Solvable::provides() const
335     {
336       NO_SOLVABLE_RETURN( Capabilities() );
337       return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
338     }
339     Capabilities Solvable::requires() const
340     {
341       NO_SOLVABLE_RETURN( Capabilities() );
342       return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
343     }
344     Capabilities Solvable::conflicts() const
345     {
346       NO_SOLVABLE_RETURN( Capabilities() );
347       return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
348     }
349     Capabilities Solvable::obsoletes() const
350     {
351       NO_SOLVABLE_RETURN( Capabilities() );
352       return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
353     }
354     Capabilities Solvable::recommends() const
355     {
356       NO_SOLVABLE_RETURN( Capabilities() );
357       return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
358     }
359     Capabilities Solvable::suggests() const
360     {
361       NO_SOLVABLE_RETURN( Capabilities() );
362       return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
363     }
364     Capabilities Solvable::freshens() const
365     {
366       NO_SOLVABLE_RETURN( Capabilities() );
367       return _getCapabilities( _solvable->repo->idarraydata, _solvable->freshens );
368     }
369     Capabilities Solvable::enhances() const
370     {
371       NO_SOLVABLE_RETURN( Capabilities() );
372       return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
373     }
374     Capabilities Solvable::supplements() const
375     {
376       NO_SOLVABLE_RETURN( Capabilities() );
377       return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
378     }
379     Capabilities Solvable::prerequires() const
380     {
381       NO_SOLVABLE_RETURN( Capabilities() );
382       // prerequires are a subset of requires
383        ::Offset offs = _solvable->requires;
384        return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
385                    : Capabilities();
386     }
387
388     ///////////////////////////////////////////////////////////////////
389     namespace
390     { /////////////////////////////////////////////////////////////////
391       /** Expand \ref Capability and call \c fnc_r for each namescpace:language
392        * dependency. Return #invocations of fnc_r, negative if fnc_r returned
393        * false to indicate abort.
394        */
395       int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
396       {
397         CapDetail detail( cap_r );
398         if ( detail.kind() == CapDetail::EXPRESSION )
399         {
400           switch ( detail.capRel() )
401           {
402             case CapDetail::CAP_AND:
403             case CapDetail::CAP_OR:
404                 // expand
405             {
406               int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
407               if ( res < 0 )
408                 return res; // negative on abort.
409               int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
410               if ( res2 < 0 )
411                 return -res + res2; // negative on abort.
412               return res + res2;
413             }
414             break;
415
416             case CapDetail::CAP_NAMESPACE:
417               if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
418               {
419                 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
420               }
421               break;
422
423             case CapDetail::REL_NONE:
424             case CapDetail::CAP_WITH:
425               break; // unwanted
426           }
427         }
428         return 0;
429       }
430
431        /** Expand \ref Capability and call \c fnc_r for each namescpace:language
432        * dependency. Return #invocations of fnc_r, negative if fnc_r returned
433        * false to indicate abort.
434        */
435       inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
436       {
437         int cnt = 0;
438         for_( cit, cap_r.begin(), cap_r.end() )
439         {
440           int res = invokeOnEachSupportedLocale( *cit, fnc_r );
441           if ( res < 0 )
442             return -cnt + res; // negative on abort.
443           cnt += res;
444         }
445         return cnt;
446       }
447       //@}
448
449       // Functor returning false if a Locale is in the set.
450       struct NoMatchIn
451       {
452         NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
453
454         bool operator()( const Locale & locale_r ) const
455         {
456           return _locales.find( locale_r ) == _locales.end();
457         }
458
459         const LocaleSet & _locales;
460       };
461
462     } /////////////////////////////////////////////////////////////////
463
464     bool Solvable::supportsLocales() const
465     {
466       // false_c stops on 1st Locale.
467       return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
468     }
469
470     bool Solvable::supportsLocale( const Locale & locale_r ) const
471     {
472       // not_equal_to stops on == Locale.
473       return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
474     }
475
476     bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
477     {
478       if ( locales_r.empty() )
479         return false;
480       // NoMatchIn stops if Locale is included.
481       return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
482     }
483
484     bool Solvable::supportsRequestedLocales() const
485     { return supportsLocale( myPool().getRequestedLocales() ); }
486
487     void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
488     {
489       invokeOnEachSupportedLocale( supplements(),
490                                    functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
491     }
492
493     /******************************************************************
494     **
495     **  FUNCTION NAME : operator<<
496     **  FUNCTION TYPE : std::ostream &
497     */
498     std::ostream & operator<<( std::ostream & str, const Solvable & obj )
499     {
500       if ( ! obj )
501         return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
502
503       return str << "(" << obj.id() << ")"
504           << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
505           << '-' << obj.edition() << '.' << obj.arch() << "("
506           << obj.repository().name() << ")";
507     }
508
509     /******************************************************************
510     **
511     **  FUNCTION NAME : dumpOn
512     **  FUNCTION TYPE : std::ostream &
513     */
514     std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
515     {
516       str << obj;
517       if ( obj )
518       {
519 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
520         OUTS(PROVIDES);
521         OUTS(PREREQUIRES);
522         OUTS(REQUIRES);
523         OUTS(CONFLICTS);
524         OUTS(OBSOLETES);
525         OUTS(RECOMMENDS);
526         OUTS(SUGGESTS);
527         OUTS(FRESHENS);
528         OUTS(ENHANCES);
529         OUTS(SUPPLEMENTS);
530 #undef OUTS
531       }
532       return str;
533     }
534
535     /////////////////////////////////////////////////////////////////
536   } // namespace sat
537   ///////////////////////////////////////////////////////////////////
538   /////////////////////////////////////////////////////////////////
539 } // namespace zypp
540 ///////////////////////////////////////////////////////////////////