Parse zypp.conf multiversion option and make the setting available in pool and resolver.
[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/sat/LookupAttr.h"
24
25 #include "zypp/Repository.h"
26 #include "zypp/OnMediaLocation.h"
27 #include "zypp/ZConfig.h"
28
29 using std::endl;
30
31 ///////////////////////////////////////////////////////////////////
32 namespace zypp
33 { /////////////////////////////////////////////////////////////////
34   ///////////////////////////////////////////////////////////////////
35   namespace sat
36   { /////////////////////////////////////////////////////////////////
37
38     namespace
39     {
40       void _doSplit( IdString & _ident, ResKind & _kind, IdString & _name )
41       {
42         if ( ! _ident )
43           return;
44
45         const char * ident = _ident.c_str();
46         const char * sep = ::strchr( ident, ':' );
47
48         // no ':' in package names (hopefully)
49         if ( ! sep )
50         {
51           _kind = ResKind::package;
52           _name = _ident;
53           return;
54         }
55
56         // save name
57         _name = IdString( sep+1 );
58
59         // Quick check for well known kinds.
60         // NOTE: kind package and srcpackage do not
61         //       have namespaced ident!
62         if ( sep-ident >= 4 )
63         {
64           switch ( ident[3] )
65           {
66 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) _kind = ResKind::K
67           //             ----v
68             case 'c': OUTS( patch, 5 );       return; break;
69             case 'd': OUTS( product, 7 );     return; break;
70             case 'k': OUTS( package, 7 );     _ident = _name; return; break;
71             case 'p': OUTS( srcpackage, 10 ); _ident = _name; return; break;
72             case 't': OUTS( pattern, 7 );     return; break;
73 #undef OUTS
74           }
75         }
76
77         // an unknown kind
78         _kind = ResKind( std::string( ident, sep-ident ) );
79       }
80     }
81
82     Solvable::SplitIdent::SplitIdent( IdString ident_r )
83     : _ident( ident_r )
84     { _doSplit( _ident, _kind, _name ); }
85
86     Solvable::SplitIdent::SplitIdent( const char * ident_r )
87     : _ident( ident_r )
88     { _doSplit( _ident, _kind, _name ); }
89
90     Solvable::SplitIdent::SplitIdent( const std::string & ident_r )
91     : _ident( ident_r )
92     { _doSplit( _ident, _kind, _name ); }
93
94     Solvable::SplitIdent::SplitIdent( ResKind kind_r, IdString name_r )
95     : _kind( kind_r )
96     , _name( name_r )
97     {
98       if ( kind_r == ResKind::package || kind_r == ResKind::srcpackage )
99         _ident = _name;
100       else
101         _ident = IdString( str::form( "%s:%s", kind_r.c_str(), name_r.c_str() ) );
102     }
103
104     Solvable::SplitIdent::SplitIdent( ResKind kind_r, const C_Str & name_r )
105     : _kind( kind_r )
106     , _name( name_r )
107     {
108       if ( kind_r == ResKind::package || kind_r == ResKind::srcpackage )
109         _ident = _name;
110       else
111         _ident = IdString( str::form( "%s:%s", kind_r.c_str(), name_r.c_str() ) );
112     }
113
114     /////////////////////////////////////////////////////////////////
115
116     const Solvable Solvable::noSolvable;
117
118     /////////////////////////////////////////////////////////////////
119
120     ::_Solvable * Solvable::get() const
121     { return myPool().getSolvable( _id ); }
122
123 #define NO_SOLVABLE_RETURN( VAL ) \
124     ::_Solvable * _solvable( get() ); \
125     if ( ! _solvable ) return VAL
126
127     Solvable Solvable::nextInPool() const
128     { return Solvable( myPool().getNextId( _id ) ); }
129
130     Solvable Solvable::nextInRepo() const
131     {
132       NO_SOLVABLE_RETURN( noSolvable );
133       for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
134       {
135         ::_Solvable * nextS( myPool().getSolvable( next ) );
136         if ( nextS && nextS->repo == _solvable->repo )
137         {
138           return Solvable( next );
139         }
140       }
141       return noSolvable;
142     }
143
144     Repository Solvable::repository() const
145     {
146       NO_SOLVABLE_RETURN( Repository::noRepository );
147       return Repository( _solvable->repo );
148     }
149
150     bool Solvable::isSystem() const
151     {
152       NO_SOLVABLE_RETURN( _id == detail::systemSolvableId );
153       return myPool().isSystemRepo( _solvable->repo );
154     }
155
156     IdString Solvable::ident() const
157     {
158       NO_SOLVABLE_RETURN( IdString() );
159       return IdString( _solvable->name );
160     }
161
162     std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
163     {
164       NO_SOLVABLE_RETURN( std::string() );
165       const char * s = ::solvable_lookup_str( _solvable, attr.id() );
166       return s ? s : std::string();
167     }
168
169     std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
170     {
171       NO_SOLVABLE_RETURN( std::string() );
172       const char * s = 0;
173       if ( lang_r == Locale::noCode )
174       {
175         s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
176       }
177       else
178       {
179         s = ::solvable_lookup_str_lang( _solvable, attr.id(), lang_r.code().c_str() );
180       }
181       return s ? s : std::string();
182    }
183
184     unsigned Solvable::lookupNumAttribute( const SolvAttr & attr ) const
185     {
186       NO_SOLVABLE_RETURN( 0 );
187       return ::solvable_lookup_num( _solvable, attr.id(), 0 );
188     }
189
190     bool Solvable::lookupBoolAttribute( const SolvAttr & attr ) const
191     {
192       NO_SOLVABLE_RETURN( false );
193       return ::solvable_lookup_bool( _solvable, attr.id() );
194     }
195
196     detail::IdType Solvable::lookupIdAttribute( const SolvAttr & attr ) const
197     {
198       NO_SOLVABLE_RETURN( detail::noId );
199       return ::solvable_lookup_id( _solvable, attr.id() );
200     }
201
202     CheckSum Solvable::lookupCheckSumAttribute( const SolvAttr & attr ) const
203     {
204       NO_SOLVABLE_RETURN( CheckSum() );
205       detail::IdType chksumtype = 0;
206       const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
207       if ( ! s )
208         return CheckSum();
209       switch ( chksumtype )
210       {
211         case REPOKEY_TYPE_MD5:    return CheckSum::md5( s );
212         case REPOKEY_TYPE_SHA1:   return CheckSum::sha1( s );
213         case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
214       }
215       return CheckSum( std::string(), s ); // try to autodetect
216     }
217
218     ///////////////////////////////////////////////////////////////////
219     namespace
220     {
221       inline Pathname lookupDatadirIn( Repository repor_r )
222       {
223         static const sat::SolvAttr susetagsDatadir( "susetags:datadir" );
224         Pathname ret;
225         // First look for repo attribute "susetags:datadir". If not found,
226         // look into the solvables as Code11 satsolver placed it there.
227         sat::LookupRepoAttr datadir( susetagsDatadir, repor_r );
228         if ( ! datadir.empty() )
229           ret = datadir.begin().asString();
230         else
231         {
232           sat::LookupAttr datadir( susetagsDatadir, repor_r );
233           if ( ! datadir.empty() )
234             ret = datadir.begin().asString();
235         }
236         return ret;
237       }
238     }
239     ///////////////////////////////////////////////////////////////////
240
241     OnMediaLocation Solvable::lookupLocation() const
242     {
243       NO_SOLVABLE_RETURN( OnMediaLocation() );
244       // medianumber and path
245       unsigned medianr;
246       char * file = ::solvable_get_location( _solvable, &medianr );
247       if ( ! file )
248         return OnMediaLocation();
249
250       OnMediaLocation ret;
251
252       Pathname path;
253       switch ( repository().info().type().toEnum() )
254       {
255         case repo::RepoType::NONE_e:
256         {
257           path = lookupDatadirIn( repository() );
258           if ( ! path.empty() )
259             repository().info().setProbedType( repo::RepoType::YAST2_e );
260         }
261         break;
262
263         case repo::RepoType::YAST2_e:
264         {
265           path = lookupDatadirIn( repository() );
266           if ( path.empty() )
267             path = "suse";
268         }
269         break;
270
271         default:
272           break;
273       }
274       ret.setLocation    ( path/file, medianr );
275       ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ), ByteCount::K ) );
276       ret.setChecksum    ( lookupCheckSumAttribute( SolvAttr::checksum ) );
277       // Not needed/available for solvables?
278       //ret.setOpenSize    ( ByteCount( lookupNumAttribute( SolvAttr::opensize ), ByteCount::K ) );
279       //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
280       return ret;
281     }
282
283     ResKind Solvable::kind() const
284     {
285       NO_SOLVABLE_RETURN( ResKind() );
286       // detect srcpackages by 'arch'
287       switch ( _solvable->arch )
288       {
289         case ARCH_SRC:
290         case ARCH_NOSRC:
291           return ResKind::srcpackage;
292           break;
293       }
294
295       const char * ident = IdString( _solvable->name ).c_str();
296       const char * sep = ::strchr( ident, ':' );
297
298       // no ':' in package names (hopefully)
299       if ( ! sep )
300         return ResKind::package;
301
302       // quick check for well known kinds
303       if ( sep-ident >= 4 )
304       {
305         switch ( ident[3] )
306         {
307 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
308           //             ----v
309           case 'c': OUTS( patch, 5 );       break;
310           case 'd': OUTS( product, 7 );     break;
311           case 'k': OUTS( package, 7 );     break;
312           case 'p': OUTS( srcpackage, 10 ); break;
313           case 't': OUTS( pattern, 7 );     break;
314 #undef OUTS
315         }
316       }
317
318       // an unknown kind
319       return ResKind( std::string( ident, sep-ident ) );
320     }
321
322     bool Solvable::isKind( const ResKind & kind_r ) const
323     {
324       NO_SOLVABLE_RETURN( false );
325
326       // detect srcpackages by 'arch'
327       switch ( _solvable->arch )
328       {
329         case ARCH_SRC:
330         case ARCH_NOSRC:
331           return( kind_r == ResKind::srcpackage );
332           break;
333       }
334
335       // no ':' in package names (hopefully)
336       const char * ident = IdString( _solvable->name ).c_str();
337       if ( kind_r == ResKind::package )
338       {
339         return( ::strchr( ident, ':' ) == 0 );
340       }
341
342       // look for a 'kind:' prefix
343       const char * kind = kind_r.c_str();
344       unsigned     ksize = ::strlen( kind );
345       return( ::strncmp( ident, kind, ksize ) == 0
346               && ident[ksize] == ':' );
347     }
348
349     std::string Solvable::name() const
350     {
351       NO_SOLVABLE_RETURN( std::string() );
352       const char * ident = IdString( _solvable->name ).c_str();
353       const char * sep = ::strchr( ident, ':' );
354       return( sep ? sep+1 : ident );
355     }
356
357     Edition Solvable::edition() const
358     {
359       NO_SOLVABLE_RETURN( Edition() );
360       return Edition( _solvable->evr );
361     }
362
363     Arch Solvable::arch() const
364     {
365       NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
366       switch ( _solvable->arch )
367       {
368         case ARCH_SRC:
369         case ARCH_NOSRC:
370           return Arch_noarch; //ArchId( ARCH_NOARCH );
371           break;
372       }
373       return Arch( IdString(_solvable->arch).asString() );
374       //return ArchId( _solvable->arch );
375     }
376
377     bool Solvable::multiversionInstall() const
378     {
379       return myPool().isMultiversion( ident() );
380     }
381
382     bool Solvable::installOnly() const { return multiversionInstall(); }
383
384     IdString Solvable::vendor() const
385     {
386       NO_SOLVABLE_RETURN( IdString() );
387       return IdString( _solvable->vendor );
388     }
389
390     Capabilities Solvable::operator[]( Dep which_r ) const
391     {
392       switch( which_r.inSwitch() )
393       {
394         case Dep::PROVIDES_e:    return provides();    break;
395         case Dep::REQUIRES_e:    return requires();    break;
396         case Dep::CONFLICTS_e:   return conflicts();   break;
397         case Dep::OBSOLETES_e:   return obsoletes();   break;
398         case Dep::RECOMMENDS_e:  return recommends();  break;
399         case Dep::SUGGESTS_e:    return suggests();    break;
400         case Dep::ENHANCES_e:    return enhances();    break;
401         case Dep::SUPPLEMENTS_e: return supplements(); break;
402         case Dep::PREREQUIRES_e: return prerequires(); break;
403       }
404       return Capabilities();
405     }
406
407     inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
408     {
409       return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
410     }
411     Capabilities Solvable::provides() const
412     {
413       NO_SOLVABLE_RETURN( Capabilities() );
414       return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
415     }
416     Capabilities Solvable::requires() const
417     {
418       NO_SOLVABLE_RETURN( Capabilities() );
419       return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
420     }
421     Capabilities Solvable::conflicts() const
422     {
423       NO_SOLVABLE_RETURN( Capabilities() );
424       return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
425     }
426     Capabilities Solvable::obsoletes() const
427     {
428       NO_SOLVABLE_RETURN( Capabilities() );
429       return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
430     }
431     Capabilities Solvable::recommends() const
432     {
433       NO_SOLVABLE_RETURN( Capabilities() );
434       return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
435     }
436     Capabilities Solvable::suggests() const
437     {
438       NO_SOLVABLE_RETURN( Capabilities() );
439       return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
440     }
441     Capabilities Solvable::enhances() const
442     {
443       NO_SOLVABLE_RETURN( Capabilities() );
444       return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
445     }
446     Capabilities Solvable::supplements() const
447     {
448       NO_SOLVABLE_RETURN( Capabilities() );
449       return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
450     }
451     Capabilities Solvable::prerequires() const
452     {
453       NO_SOLVABLE_RETURN( Capabilities() );
454       // prerequires are a subset of requires
455        ::Offset offs = _solvable->requires;
456        return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
457                    : Capabilities();
458     }
459
460     CapabilitySet Solvable::providesNamespace( const std::string & namespace_r ) const
461     {
462       NO_SOLVABLE_RETURN( CapabilitySet() );
463       CapabilitySet ret;
464       Capabilities caps( provides() );
465       for_( it, caps.begin(), caps.end() )
466       {
467         CapDetail caprep( it->detail() );
468         if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
469           ret.insert( *it );
470       }
471       return ret;
472    }
473
474     CapabilitySet Solvable::valuesOfNamespace( const std::string & namespace_r ) const
475     {
476       NO_SOLVABLE_RETURN( CapabilitySet() );
477       CapabilitySet ret;
478       Capabilities caps( provides() );
479       for_( it, caps.begin(), caps.end() )
480       {
481         CapDetail caprep( it->detail() );
482         if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
483         {
484           std::string value( caprep.name().c_str()+namespace_r.size()+1 );
485           value[value.size()-1] = '\0'; // erase the trailing ')'
486           ret.insert( Capability( value, caprep.op(), caprep.ed() ) );
487         }
488       }
489       return ret;
490     }
491
492
493     std::string Solvable::asString() const
494     {
495       NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
496       return str::form( "%s-%s.%s",
497                         IdString( _solvable->name ).c_str(),
498                         IdString( _solvable->evr ).c_str(),
499                         IdString( _solvable->arch ).c_str() );
500     }
501
502     bool Solvable::identical( Solvable rhs ) const
503     {
504       NO_SOLVABLE_RETURN( ! rhs.get() );
505       ::_Solvable * rhssolvable( rhs.get() );
506       return rhssolvable && ::solvable_identical( _solvable, rhssolvable );
507     }
508
509     ///////////////////////////////////////////////////////////////////
510     namespace
511     { /////////////////////////////////////////////////////////////////
512       /** Expand \ref Capability and call \c fnc_r for each namescpace:language
513        * dependency. Return #invocations of fnc_r, negative if fnc_r returned
514        * false to indicate abort.
515        */
516       int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
517       {
518         CapDetail detail( cap_r );
519         if ( detail.kind() == CapDetail::EXPRESSION )
520         {
521           switch ( detail.capRel() )
522           {
523             case CapDetail::CAP_AND:
524             case CapDetail::CAP_OR:
525                 // expand
526               {
527                 int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
528                 if ( res < 0 )
529                   return res; // negative on abort.
530                 int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
531                 if ( res2 < 0 )
532                   return -res + res2; // negative on abort.
533                 return res + res2;
534               }
535               break;
536
537             case CapDetail::CAP_NAMESPACE:
538               if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
539               {
540                 return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
541               }
542               break;
543
544             case CapDetail::REL_NONE:
545             case CapDetail::CAP_WITH:
546             case CapDetail::CAP_ARCH:
547               break; // unwanted
548           }
549         }
550         return 0;
551       }
552
553        /** Expand \ref Capability and call \c fnc_r for each namescpace:language
554        * dependency. Return #invocations of fnc_r, negative if fnc_r returned
555        * false to indicate abort.
556        */
557       inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
558       {
559         int cnt = 0;
560         for_( cit, cap_r.begin(), cap_r.end() )
561         {
562           int res = invokeOnEachSupportedLocale( *cit, fnc_r );
563           if ( res < 0 )
564             return -cnt + res; // negative on abort.
565           cnt += res;
566         }
567         return cnt;
568       }
569       //@}
570
571       // Functor returning false if a Locale is in the set.
572       struct NoMatchIn
573       {
574         NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
575
576         bool operator()( const Locale & locale_r ) const
577         {
578           return _locales.find( locale_r ) == _locales.end();
579         }
580
581         const LocaleSet & _locales;
582       };
583
584     } /////////////////////////////////////////////////////////////////
585
586     bool Solvable::supportsLocales() const
587     {
588       // false_c stops on 1st Locale.
589       return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
590     }
591
592     bool Solvable::supportsLocale( const Locale & locale_r ) const
593     {
594       // not_equal_to stops on == Locale.
595       return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
596     }
597
598     bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
599     {
600       if ( locales_r.empty() )
601         return false;
602       // NoMatchIn stops if Locale is included.
603       return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
604     }
605
606     bool Solvable::supportsRequestedLocales() const
607     { return supportsLocale( myPool().getRequestedLocales() ); }
608
609     void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
610     {
611       invokeOnEachSupportedLocale( supplements(),
612                                    functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
613     }
614
615     /******************************************************************
616     **
617     **  FUNCTION NAME : operator<<
618     **  FUNCTION TYPE : std::ostream &
619     */
620     std::ostream & operator<<( std::ostream & str, const Solvable & obj )
621     {
622       if ( ! obj )
623         return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
624
625       return str << "(" << obj.id() << ")"
626           << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
627           << '-' << obj.edition() << '.' << obj.arch() << "("
628           << obj.repository().alias() << ")";
629     }
630
631     /******************************************************************
632     **
633     **  FUNCTION NAME : dumpOn
634     **  FUNCTION TYPE : std::ostream &
635     */
636     std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
637     {
638       str << obj;
639       if ( obj )
640       {
641 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
642         OUTS(PROVIDES);
643         OUTS(PREREQUIRES);
644         OUTS(REQUIRES);
645         OUTS(CONFLICTS);
646         OUTS(OBSOLETES);
647         OUTS(RECOMMENDS);
648         OUTS(SUGGESTS);
649         OUTS(ENHANCES);
650         OUTS(SUPPLEMENTS);
651 #undef OUTS
652       }
653       return str;
654     }
655
656     /////////////////////////////////////////////////////////////////
657   } // namespace sat
658   ///////////////////////////////////////////////////////////////////
659   /////////////////////////////////////////////////////////////////
660 } // namespace zypp
661 ///////////////////////////////////////////////////////////////////