libzypp  12.16.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  const char * file = ::solvable_lookup_location( _solvable, &medianr );
259  if ( ! file )
260  return OnMediaLocation();
261  if ( ! medianr )
262  medianr = 1;
263 
264  OnMediaLocation ret;
265 
266  Pathname path;
267  switch ( repository().info().type().toEnum() )
268  {
270  {
271  path = lookupDatadirIn( repository() );
272  if ( ! path.empty() )
274  }
275  break;
276 
278  {
279  path = lookupDatadirIn( repository() );
280  if ( path.empty() )
281  path = "suse";
282  }
283  break;
284 
285  default:
286  break;
287  }
288  ret.setLocation ( path/file, medianr );
291  // Not needed/available for solvables?
292  //ret.setOpenSize ( ByteCount( lookupNumAttribute( SolvAttr::opensize ) ) );
293  //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
294  return ret;
295  }
296 
298  {
300  // detect srcpackages by 'arch'
301  switch ( _solvable->arch )
302  {
303  case ARCH_SRC:
304  case ARCH_NOSRC:
305  return ResKind::srcpackage;
306  break;
307  }
308 
309  const char * ident = IdString( _solvable->name ).c_str();
310  const char * sep = ::strchr( ident, ':' );
311 
312  // no ':' in package names (hopefully)
313  if ( ! sep )
314  return ResKind::package;
315 
316  // quick check for well known kinds
317  if ( sep-ident >= 4 )
318  {
319  switch ( ident[3] )
320  {
321 #define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K
322  // ----v
323  case 'c': OUTS( patch, 5 ); break;
324  case 'd': OUTS( product, 7 ); break;
325  case 'k': OUTS( package, 7 ); break;
326  case 'p': OUTS( srcpackage, 10 ); break;
327  case 't': OUTS( pattern, 7 ); break;
328 #undef OUTS
329  }
330  }
331 
332  // an unknown kind
333  return ResKind( std::string( ident, sep-ident ) );
334  }
335 
336  bool Solvable::isKind( const ResKind & kind_r ) const
337  {
338  NO_SOLVABLE_RETURN( false );
339 
340  // detect srcpackages by 'arch'
341  switch ( _solvable->arch )
342  {
343  case ARCH_SRC:
344  case ARCH_NOSRC:
345  return( kind_r == ResKind::srcpackage );
346  break;
347  }
348 
349  // no ':' in package names (hopefully)
350  const char * ident = IdString( _solvable->name ).c_str();
351  if ( kind_r == ResKind::package )
352  {
353  return( ::strchr( ident, ':' ) == 0 );
354  }
355 
356  // look for a 'kind:' prefix
357  const char * kind = kind_r.c_str();
358  unsigned ksize = ::strlen( kind );
359  return( ::strncmp( ident, kind, ksize ) == 0
360  && ident[ksize] == ':' );
361  }
362 
363  std::string Solvable::name() const
364  {
365  NO_SOLVABLE_RETURN( std::string() );
366  const char * ident = IdString( _solvable->name ).c_str();
367  const char * sep = ::strchr( ident, ':' );
368  return( sep ? sep+1 : ident );
369  }
370 
372  {
374  return Edition( _solvable->evr );
375  }
376 
378  {
379  NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
380  switch ( _solvable->arch )
381  {
382  case ARCH_SRC:
383  case ARCH_NOSRC:
384  return Arch_noarch; //ArchId( ARCH_NOARCH );
385  break;
386  }
387  return Arch( IdString(_solvable->arch).asString() );
388  //return ArchId( _solvable->arch );
389  }
390 
392  {
393  return myPool().isMultiversion( ident() );
394  }
395 
397  {
399  return IdString( _solvable->vendor );
400  }
401 
403  {
404  switch( which_r.inSwitch() )
405  {
406  case Dep::PROVIDES_e: return provides(); break;
407  case Dep::REQUIRES_e: return requires(); break;
408  case Dep::CONFLICTS_e: return conflicts(); break;
409  case Dep::OBSOLETES_e: return obsoletes(); break;
410  case Dep::RECOMMENDS_e: return recommends(); break;
411  case Dep::SUGGESTS_e: return suggests(); break;
412  case Dep::ENHANCES_e: return enhances(); break;
413  case Dep::SUPPLEMENTS_e: return supplements(); break;
414  case Dep::PREREQUIRES_e: return prerequires(); break;
415  }
416  return Capabilities();
417  }
418 
419  inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
420  {
421  return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
422  }
424  {
426  return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
427  }
429  {
431  return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
432  }
434  {
436  return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
437  }
439  {
441  return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
442  }
444  {
446  return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
447  }
449  {
451  return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
452  }
454  {
456  return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
457  }
459  {
461  return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
462  }
464  {
466  // prerequires are a subset of requires
467  ::Offset offs = _solvable->requires;
468  return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
469  : Capabilities();
470  }
471 
472  CapabilitySet Solvable::providesNamespace( const std::string & namespace_r ) const
473  {
475  CapabilitySet ret;
476  Capabilities caps( provides() );
477  for_( it, caps.begin(), caps.end() )
478  {
479  CapDetail caprep( it->detail() );
480  if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
481  ret.insert( *it );
482  }
483  return ret;
484  }
485 
486  CapabilitySet Solvable::valuesOfNamespace( const std::string & namespace_r ) const
487  {
489  CapabilitySet ret;
490  Capabilities caps( provides() );
491  for_( it, caps.begin(), caps.end() )
492  {
493  CapDetail caprep( it->detail() );
494  if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
495  {
496  std::string value( caprep.name().c_str()+namespace_r.size()+1 );
497  value[value.size()-1] = '\0'; // erase the trailing ')'
498  ret.insert( Capability( value, caprep.op(), caprep.ed() ) );
499  }
500  }
501  return ret;
502  }
503 
504 
505  std::string Solvable::asString() const
506  {
507  NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
508  return str::form( "%s-%s.%s",
509  IdString( _solvable->name ).c_str(),
510  IdString( _solvable->evr ).c_str(),
511  IdString( _solvable->arch ).c_str() );
512  }
513 
514  bool Solvable::identical( Solvable rhs ) const
515  {
516  NO_SOLVABLE_RETURN( ! rhs.get() );
517  ::_Solvable * rhssolvable( rhs.get() );
518  return rhssolvable && ( _solvable == rhssolvable || ::solvable_identical( _solvable, rhssolvable ) );
519  }
520 
522  namespace
523  {
524 
528  int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
529  {
530  CapDetail detail( cap_r );
531  if ( detail.kind() == CapDetail::EXPRESSION )
532  {
533  switch ( detail.capRel() )
534  {
535  case CapDetail::CAP_AND:
536  case CapDetail::CAP_OR:
537  // expand
538  {
539  int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
540  if ( res < 0 )
541  return res; // negative on abort.
542  int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
543  if ( res2 < 0 )
544  return -res + res2; // negative on abort.
545  return res + res2;
546  }
547  break;
548 
550  if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
551  {
552  return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
553  }
554  break;
555 
556  case CapDetail::REL_NONE:
557  case CapDetail::CAP_WITH:
558  case CapDetail::CAP_ARCH:
559  break; // unwanted
560  }
561  }
562  return 0;
563  }
564 
569  inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (const Locale &)> fnc_r )
570  {
571  int cnt = 0;
572  for_( cit, cap_r.begin(), cap_r.end() )
573  {
574  int res = invokeOnEachSupportedLocale( *cit, fnc_r );
575  if ( res < 0 )
576  return -cnt + res; // negative on abort.
577  cnt += res;
578  }
579  return cnt;
580  }
582 
583  // Functor returning false if a Locale is in the set.
584  struct NoMatchIn
585  {
586  NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
587 
588  bool operator()( const Locale & locale_r ) const
589  {
590  return _locales.find( locale_r ) == _locales.end();
591  }
592 
594  };
595 
596  }
597 
599  {
600  // false_c stops on 1st Locale.
601  return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
602  }
603 
604  bool Solvable::supportsLocale( const Locale & locale_r ) const
605  {
606  // not_equal_to stops on == Locale.
607  return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
608  }
609 
610  bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
611  {
612  if ( locales_r.empty() )
613  return false;
614  // NoMatchIn stops if Locale is included.
615  return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
616  }
617 
619  { return supportsLocale( myPool().getRequestedLocales() ); }
620 
621  void Solvable::getSupportedLocales( LocaleSet & locales_r ) const
622  {
623  invokeOnEachSupportedLocale( supplements(),
624  functor::Collector( std::inserter( locales_r, locales_r.begin() ) ) );
625  }
626 
627  /******************************************************************
628  **
629  ** FUNCTION NAME : operator<<
630  ** FUNCTION TYPE : std::ostream &
631  */
632  std::ostream & operator<<( std::ostream & str, const Solvable & obj )
633  {
634  if ( ! obj )
635  return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
636 
637  return str << "(" << obj.id() << ")"
638  << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
639  << '-' << obj.edition() << '.' << obj.arch() << "("
640  << obj.repository().alias() << ")";
641  }
642 
643  /******************************************************************
644  **
645  ** FUNCTION NAME : dumpOn
646  ** FUNCTION TYPE : std::ostream &
647  */
648  std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
649  {
650  str << obj;
651  if ( obj )
652  {
653 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
654  OUTS(PROVIDES);
655  OUTS(PREREQUIRES);
656  OUTS(REQUIRES);
657  OUTS(CONFLICTS);
658  OUTS(OBSOLETES);
659  OUTS(RECOMMENDS);
660  OUTS(SUGGESTS);
661  OUTS(ENHANCES);
662  OUTS(SUPPLEMENTS);
663 #undef OUTS
664  }
665  return str;
666  }
667 
669  } // namespace sat
672 } // namespace zypp