libzypp  17.14.0
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 #include "zypp/base/Xml.h"
20 
22 #include "zypp/sat/Solvable.h"
23 #include "zypp/sat/Pool.h"
24 #include "zypp/sat/LookupAttr.h"
25 
26 #include "zypp/Repository.h"
27 #include "zypp/OnMediaLocation.h"
28 #include "zypp/ZConfig.h"
29 
30 #include "zypp/ui/Selectable.h"
31 
32 using std::endl;
33 
35 namespace zypp
36 {
38  namespace sat
39  {
41  namespace
42  {
43  void _doSplit( IdString & _ident, ResKind & _kind, IdString & _name )
44  {
45  if ( ! _ident )
46  return;
47 
48  ResKind explicitKind = ResKind::explicitBuiltin( _ident.c_str() );
49  // NOTE: kind package and srcpackage do not have namespaced ident!
50  if ( ! explicitKind )
51  {
52  _name = _ident;
53  // No kind defaults to package
54  if ( !_kind )
55  _kind = ResKind::package;
56  else if ( ! ( _kind == ResKind::package || _kind == ResKind::srcpackage ) )
57  _ident = IdString( str::form( "%s:%s", _kind.c_str(), _ident.c_str() ) );
58  }
59  else
60  {
61  // strip kind spec from name
62  _name = IdString( ::strchr( _ident.c_str(), ':' )+1 );
63  _kind = explicitKind;
64  if ( _kind == ResKind::package || _kind == ResKind::srcpackage )
65  _ident = _name;
66  }
67  return;
68  }
69  } // namespace
71 
73  : _ident( ident_r )
74  { _doSplit( _ident, _kind, _name ); }
75 
76  Solvable::SplitIdent::SplitIdent( const char * ident_r )
77  : _ident( ident_r )
78  { _doSplit( _ident, _kind, _name ); }
79 
80  Solvable::SplitIdent::SplitIdent( const std::string & ident_r )
81  : _ident( ident_r )
82  { _doSplit( _ident, _kind, _name ); }
83 
85  : _ident( name_r )
86  , _kind( kind_r )
87  { _doSplit( _ident, _kind, _name ); }
88 
90  : _ident( name_r )
91  , _kind( kind_r )
92  { _doSplit( _ident, _kind, _name ); }
93 
95  // class Solvable
97 
99 
101 
103  { return myPool().getSolvable( _id ); }
104 
105 #define NO_SOLVABLE_RETURN( VAL ) \
106  detail::CSolvable * _solvable( get() ); \
107  if ( ! _solvable ) return VAL
108 
110  { return Solvable( myPool().getNextId( _id ) ); }
111 
113  {
115  for ( detail::SolvableIdType next = _id+1; next < unsigned(_solvable->repo->end); ++next )
116  {
117  detail::CSolvable * nextS( myPool().getSolvable( next ) );
118  if ( nextS && nextS->repo == _solvable->repo )
119  {
120  return Solvable( next );
121  }
122  }
123  return noSolvable;
124  }
125 
126  std::string Solvable::lookupStrAttribute( const SolvAttr & attr ) const
127  {
128  NO_SOLVABLE_RETURN( std::string() );
129  const char * s = ::solvable_lookup_str( _solvable, attr.id() );
130  return s ? s : std::string();
131  }
132 
133  std::string Solvable::lookupStrAttribute( const SolvAttr & attr, const Locale & lang_r ) const
134  {
135  NO_SOLVABLE_RETURN( std::string() );
136  const char * s = 0;
137  if ( !lang_r )
138  {
139  s = ::solvable_lookup_str_poollang( _solvable, attr.id() );
140  }
141  else
142  {
143  for ( Locale l( lang_r ); l; l = l.fallback() )
144  {
145  if ( (s = ::solvable_lookup_str_lang( _solvable, attr.id(), l.c_str(), 0 )) )
146  return s;
147  }
148  // here: no matching locale, so use default
149  s = ::solvable_lookup_str_lang( _solvable, attr.id(), 0, 0 );
150  }
151  return s ? s : std::string();
152  }
153 
154  unsigned long long Solvable::lookupNumAttribute( const SolvAttr & attr ) const
155  {
156  NO_SOLVABLE_RETURN( 0 );
157  return ::solvable_lookup_num( _solvable, attr.id(), 0 );
158  }
159 
160  unsigned long long Solvable::lookupNumAttribute( const SolvAttr & attr, unsigned long long notfound_r ) const
161  {
162  NO_SOLVABLE_RETURN( notfound_r );
163  return ::solvable_lookup_num( _solvable, attr.id(), notfound_r );
164  }
165 
167  {
168  NO_SOLVABLE_RETURN( false );
169  return ::solvable_lookup_bool( _solvable, attr.id() );
170  }
171 
173  {
175  return ::solvable_lookup_id( _solvable, attr.id() );
176  }
177 
179  {
181  detail::IdType chksumtype = 0;
182  const char * s = ::solvable_lookup_checksum( _solvable, attr.id(), &chksumtype );
183  if ( ! s )
184  return CheckSum();
185  switch ( chksumtype )
186  {
187  case REPOKEY_TYPE_MD5: return CheckSum::md5( s );
188  case REPOKEY_TYPE_SHA1: return CheckSum::sha1( s );
189  case REPOKEY_TYPE_SHA224: return CheckSum::sha224( s );
190  case REPOKEY_TYPE_SHA256: return CheckSum::sha256( s );
191  case REPOKEY_TYPE_SHA384: return CheckSum::sha384( s );
192  case REPOKEY_TYPE_SHA512: return CheckSum::sha512( s );
193  }
194  return CheckSum( std::string(), s ); // try to autodetect
195  }
196 
198  namespace
199  {
200  inline Pathname lookupDatadirIn( Repository repor_r )
201  {
202  static const SolvAttr susetagsDatadir( "susetags:datadir" );
203  Pathname ret;
204  // First look for repo attribute "susetags:datadir". If not found,
205  // look into the solvables as Code11 libsolv placed it there.
206  LookupRepoAttr datadir( susetagsDatadir, repor_r );
207  if ( ! datadir.empty() )
208  ret = datadir.begin().asString();
209  else
210  {
211  LookupAttr datadir( susetagsDatadir, repor_r );
212  if ( ! datadir.empty() )
213  ret = datadir.begin().asString();
214  }
215  return ret;
216  }
217  } // namespace
219 
221  {
223  // medianumber and path
224  unsigned medianr;
225  const char * file = ::solvable_lookup_location( _solvable, &medianr );
226  if ( ! file )
227  return OnMediaLocation();
228  if ( ! medianr )
229  medianr = 1;
230 
231  OnMediaLocation ret;
232 
233  Pathname path;
234  switch ( repository().info().type().toEnum() )
235  {
237  {
238  path = lookupDatadirIn( repository() );
239  if ( ! path.empty() )
241  }
242  break;
243 
245  {
246  path = lookupDatadirIn( repository() );
247  if ( path.empty() )
248  path = "suse";
249  }
250  break;
251 
252  default:
253  break;
254  }
255  ret.setLocation ( path/file, medianr );
258  // Not needed/available for solvables?
259  //ret.setOpenSize ( ByteCount( lookupNumAttribute( SolvAttr::opensize ) ) );
260  //ret.setOpenChecksum( lookupCheckSumAttribute( SolvAttr::openchecksum ) );
261  return ret;
262  }
263 
264 
266  {
268  return IdString( _solvable->name );
269  }
270 
272  {
274  // detect srcpackages by 'arch'
275  switch ( _solvable->arch )
276  {
277  case ARCH_SRC:
278  case ARCH_NOSRC:
279  return ResKind::srcpackage;
280  break;
281  }
282 
283  // either explicitly prefixed...
284  const char * ident = IdString( _solvable->name ).c_str();
285  ResKind knownKind( ResKind::explicitBuiltin( ident ) );
286  if ( knownKind )
287  return knownKind;
288 
289  // ...or no ':' in package names (hopefully)...
290  const char * sep = ::strchr( ident, ':' );
291  if ( ! sep )
292  return ResKind::package;
293 
294  // ...or something unknown.
295  return ResKind( std::string( ident, sep-ident ) );
296  }
297 
298  bool Solvable::isKind( const ResKind & kind_r ) const
299  {
300  NO_SOLVABLE_RETURN( false );
301 
302  // detect srcpackages by 'arch'
303  switch ( _solvable->arch )
304  {
305  case ARCH_SRC:
306  case ARCH_NOSRC:
307  return( kind_r == ResKind::srcpackage );
308  break;
309  }
310 
311  // no ':' in package names (hopefully)
312  const char * ident = IdString( _solvable->name ).c_str();
313  if ( kind_r == ResKind::package )
314  {
315  return( ::strchr( ident, ':' ) == 0 );
316  }
317 
318  // look for a 'kind:' prefix
319  const char * kind = kind_r.c_str();
320  unsigned ksize = ::strlen( kind );
321  return( ::strncmp( ident, kind, ksize ) == 0
322  && ident[ksize] == ':' );
323  }
324 
325  std::string Solvable::name() const
326  {
327  NO_SOLVABLE_RETURN( std::string() );
328  const char * ident = IdString( _solvable->name ).c_str();
329  const char * sep = ::strchr( ident, ':' );
330  return( sep ? sep+1 : ident );
331  }
332 
334  {
336  return Edition( _solvable->evr );
337  }
338 
340  {
341  NO_SOLVABLE_RETURN( Arch_noarch ); //ArchId() );
342  switch ( _solvable->arch )
343  {
344  case ARCH_SRC:
345  case ARCH_NOSRC:
346  return Arch_noarch; //ArchId( ARCH_NOARCH );
347  break;
348  }
349  return Arch( IdString(_solvable->arch).asString() );
350  //return ArchId( _solvable->arch );
351  }
352 
354  {
356  return IdString( _solvable->vendor );
357  }
358 
360  {
362  return Repository( _solvable->repo );
363  }
364 
366  { return repository().info(); }
367 
368 
369  bool Solvable::isSystem() const
370  {
372  return myPool().isSystemRepo( _solvable->repo );
373  }
374 
376  {
377  return isSystem() && myPool().isOnSystemByUser( ident() );
378  }
379 
381  {
382  return isSystem() && myPool().isOnSystemByAuto( ident() );
383  }
384 
385  bool Solvable::identIsAutoInstalled( const IdString & ident_r )
386  {
387  return myPool().isOnSystemByAuto( ident_r );
388  }
389 
391  {
392  NO_SOLVABLE_RETURN( false );
393  return myPool().isNeedreboot( *this );
394  }
395 
397  {
398  NO_SOLVABLE_RETURN( false );
399  return myPool().isMultiversion( *this );
400  }
401 
403  {
406  }
407 
409  {
412  }
413 
414  std::string Solvable::asString() const
415  {
416  NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
417  return str::form( "%s-%s.%s",
418  IdString( _solvable->name ).c_str(),
419  IdString( _solvable->evr ).c_str(),
420  IdString( _solvable->arch ).c_str() );
421  }
422 
423  std::string Solvable::asUserString() const\
424  {
425  NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") );
426  return str::form( "%s-%s.%s (%s)",
427  IdString( _solvable->name ).c_str(),
428  IdString( _solvable->evr ).c_str(),
429  IdString( _solvable->arch ).c_str(),
430  repository().asUserString().c_str() );
431  }
432 
433  bool Solvable::identical( const Solvable & rhs ) const
434  {
435  NO_SOLVABLE_RETURN( ! rhs.get() );
436  detail::CSolvable * rhssolvable( rhs.get() );
437  return rhssolvable && ( _solvable == rhssolvable || ::solvable_identical( _solvable, rhssolvable ) );
438  }
439 
441  namespace
442  {
443  inline Capabilities _getCapabilities( detail::IdType * idarraydata_r, ::Offset offs_r )
444  {
445  return offs_r ? Capabilities( idarraydata_r + offs_r ) : Capabilities();
446  }
447  } // namespace
449 
451  {
453  return _getCapabilities( _solvable->repo->idarraydata, _solvable->provides );
454  }
456  {
458  return _getCapabilities( _solvable->repo->idarraydata, _solvable->requires );
459  }
461  {
463  return _getCapabilities( _solvable->repo->idarraydata, _solvable->conflicts );
464  }
466  {
468  return _getCapabilities( _solvable->repo->idarraydata, _solvable->obsoletes );
469  }
471  {
473  return _getCapabilities( _solvable->repo->idarraydata, _solvable->recommends );
474  }
476  {
478  return _getCapabilities( _solvable->repo->idarraydata, _solvable->suggests );
479  }
481  {
483  return _getCapabilities( _solvable->repo->idarraydata, _solvable->enhances );
484  }
486  {
488  return _getCapabilities( _solvable->repo->idarraydata, _solvable->supplements );
489  }
491  {
493  // prerequires are a subset of requires
494  ::Offset offs = _solvable->requires;
495  return offs ? Capabilities( _solvable->repo->idarraydata + offs, detail::solvablePrereqMarker )
496  : Capabilities();
497  }
498 
499  CapabilitySet Solvable::providesNamespace( const std::string & namespace_r ) const
500  {
502  CapabilitySet ret;
503  Capabilities caps( provides() );
504  for_( it, caps.begin(), caps.end() )
505  {
506  CapDetail caprep( it->detail() );
507  if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
508  ret.insert( *it );
509  }
510  return ret;
511  }
512 
513  CapabilitySet Solvable::valuesOfNamespace( const std::string & namespace_r ) const
514  {
516  CapabilitySet ret;
517  Capabilities caps( provides() );
518  for_( it, caps.begin(), caps.end() )
519  {
520  CapDetail caprep( it->detail() );
521  if ( str::hasPrefix( caprep.name().c_str(), namespace_r ) && *(caprep.name().c_str()+namespace_r.size()) == '(' )
522  {
523  std::string value( caprep.name().c_str()+namespace_r.size()+1 );
524  value[value.size()-1] = '\0'; // erase the trailing ')'
525  ret.insert( Capability( value, caprep.op(), caprep.ed() ) );
526  }
527  }
528  return ret;
529  }
530 
532  namespace
533  {
538  int invokeOnEachSupportedLocale( Capability cap_r, function<bool (const Locale &)> fnc_r )
539  {
540  CapDetail detail( cap_r );
541  if ( detail.kind() == CapDetail::EXPRESSION )
542  {
543  switch ( detail.capRel() )
544  {
545  case CapDetail::CAP_AND:
546  case CapDetail::CAP_OR:
547  // expand
548  {
549  int res = invokeOnEachSupportedLocale( detail.lhs(), fnc_r );
550  if ( res < 0 )
551  return res; // negative on abort.
552  int res2 = invokeOnEachSupportedLocale( detail.rhs(), fnc_r );
553  if ( res2 < 0 )
554  return -res + res2; // negative on abort.
555  return res + res2;
556  }
557  break;
558 
560  if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
561  {
562  return ( !fnc_r || fnc_r( Locale( IdString(detail.rhs().id()) ) ) ) ? 1 : -1; // negative on abort.
563  }
564  break;
565 
566  case CapDetail::REL_NONE:
567  case CapDetail::CAP_WITH:
568  case CapDetail::CAP_ARCH:
569  break; // unwanted
570  }
571  }
572  return 0;
573  }
574 
579  inline int invokeOnEachSupportedLocale( Capabilities cap_r, function<bool (Locale)> fnc_r )
580  {
581  int cnt = 0;
582  for_( cit, cap_r.begin(), cap_r.end() )
583  {
584  int res = invokeOnEachSupportedLocale( *cit, fnc_r );
585  if ( res < 0 )
586  return -cnt + res; // negative on abort.
587  cnt += res;
588  }
589  return cnt;
590  }
592 
593  // Functor returning false if a Locale is in the set.
594  struct NoMatchIn
595  {
596  NoMatchIn( const LocaleSet & locales_r ) : _locales( locales_r ) {}
597 
598  bool operator()( const Locale & locale_r ) const
599  {
600  return _locales.find( locale_r ) == _locales.end();
601  }
602 
604  };
605  } // namespace
607 
609  {
610  // false_c stops on 1st Locale.
611  return invokeOnEachSupportedLocale( supplements(), functor::false_c() ) < 0;
612  }
613 
614  bool Solvable::supportsLocale( const Locale & locale_r ) const
615  {
616  // not_equal_to stops on == Locale.
617  return invokeOnEachSupportedLocale( supplements(), bind( std::not_equal_to<Locale>(), locale_r, _1 ) ) < 0;
618  }
619 
620  bool Solvable::supportsLocale( const LocaleSet & locales_r ) const
621  {
622  if ( locales_r.empty() )
623  return false;
624  // NoMatchIn stops if Locale is included.
625  return invokeOnEachSupportedLocale( supplements(), NoMatchIn(locales_r) ) < 0;
626  }
627 
629  { return supportsLocale( myPool().getRequestedLocales() ); }
630 
632  {
633  LocaleSet ret;
634  invokeOnEachSupportedLocale( supplements(), functor::collector( std::inserter( ret, ret.begin() ) ) );
635  return ret;
636  }
637 
639  {
642  }
643 
644  unsigned Solvable::mediaNr() const
645  {
646  NO_SOLVABLE_RETURN( 0U );
647  // medianumber and path
648  unsigned medianr = 0U;
649  const char * file = ::solvable_lookup_location( _solvable, &medianr );
650  if ( ! file )
651  medianr = 0U;
652  else if ( ! medianr )
653  medianr = 1U;
654  return medianr;
655  }
656 
658  {
661  }
662 
664  {
667  }
668 
669  std::string Solvable::distribution() const
670  {
671  NO_SOLVABLE_RETURN( std::string() );
673  }
674 
675  std::string Solvable::summary( const Locale & lang_r ) const
676  {
677  NO_SOLVABLE_RETURN( std::string() );
678  return lookupStrAttribute( SolvAttr::summary, lang_r );
679  }
680 
681  std::string Solvable::description( const Locale & lang_r ) const
682  {
683  NO_SOLVABLE_RETURN( std::string() );
684  return lookupStrAttribute( SolvAttr::description, lang_r );
685  }
686 
687  std::string Solvable::insnotify( const Locale & lang_r ) const
688  {
689  NO_SOLVABLE_RETURN( std::string() );
690  return lookupStrAttribute( SolvAttr::insnotify, lang_r );
691  }
692 
693  std::string Solvable::delnotify( const Locale & lang_r ) const
694  {
695  NO_SOLVABLE_RETURN( std::string() );
696  return lookupStrAttribute( SolvAttr::delnotify, lang_r );
697  }
698 
699  std::string Solvable::licenseToConfirm( const Locale & lang_r ) const
700  {
701  NO_SOLVABLE_RETURN( std::string() );
702  std::string ret = lookupStrAttribute( SolvAttr::eula, lang_r );
703  if ( ret.empty() && isKind<Product>() )
704  {
705  const RepoInfo & ri( repoInfo() );
706  std::string riname( name() ); // "license-"+name with fallback "license"
707  if ( ! ri.hasLicense( riname ) )
708  riname.clear();
709 
710  if ( ri.needToAcceptLicense( riname ) || ! ui::Selectable::get( *this )->hasInstalledObj() )
711  ret = ri.getLicense( riname, lang_r ); // bnc#908976: suppress informal license upon update
712  }
713  return ret;
714  }
715 
717  {
718  NO_SOLVABLE_RETURN( false );
719  if ( isKind<Product>() )
720  {
721  const RepoInfo & ri( repoInfo() );
722  std::string riname( name() ); // "license-"+name with fallback "license"
723  if ( ! ri.hasLicense( riname ) )
724  riname.clear();
725 
726  return ri.needToAcceptLicense( riname );
727  }
728  return true;
729  }
730 
731 
732  std::ostream & operator<<( std::ostream & str, const Solvable & obj )
733  {
734  if ( ! obj )
735  return str << (obj.isSystem() ? "systemSolvable" : "noSolvable" );
736 
737  return str << "(" << obj.id() << ")"
738  << ( obj.isKind( ResKind::srcpackage ) ? "srcpackage:" : "" ) << obj.ident()
739  << '-' << obj.edition() << '.' << obj.arch() << "("
740  << obj.repository().alias() << ")";
741  }
742 
743  std::ostream & dumpOn( std::ostream & str, const Solvable & obj )
744  {
745  str << obj;
746  if ( obj )
747  {
748 #define OUTS(X) if ( ! obj[Dep::X].empty() ) str << endl << " " #X " " << obj[Dep::X]
749  OUTS(PROVIDES);
750  OUTS(PREREQUIRES);
751  OUTS(REQUIRES);
752  OUTS(CONFLICTS);
753  OUTS(OBSOLETES);
754  OUTS(RECOMMENDS);
755  OUTS(SUGGESTS);
756  OUTS(ENHANCES);
757  OUTS(SUPPLEMENTS);
758 #undef OUTS
759  }
760  return str;
761  }
762 
763  std::ostream & dumpAsXmlOn( std::ostream & str, const Solvable & obj )
764  {
765  xmlout::Node guard( str, "solvable" );
766 
767  dumpAsXmlOn( *guard, obj.kind() );
768  *xmlout::Node( *guard, "name" ) << obj.name();
769  dumpAsXmlOn( *guard, obj.edition() );
770  dumpAsXmlOn( *guard, obj.arch() );
771  dumpAsXmlOn( *guard, obj.repository() );
772  return str;
773  }
774 
775  } // namespace sat
777 } // namespace zypp