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