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