Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / Capability.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/sat/Capability.cc
10  *
11 */
12 #include <iostream>
13 #include "zypp/base/Logger.h"
14
15 #include "zypp/base/String.h"
16 #include "zypp/base/Regex.h"
17 #include "zypp/base/Gettext.h"
18 #include "zypp/base/Exception.h"
19
20 #include "zypp/Arch.h"
21 #include "zypp/Rel.h"
22 #include "zypp/Edition.h"
23 #include "zypp/Capability.h"
24
25 #include "zypp/sat/detail/PoolImpl.h"
26 #include "zypp/sat/Pool.h"
27 #include "zypp/ResPool.h"
28
29 using std::endl;
30
31 ///////////////////////////////////////////////////////////////////
32 namespace zypp
33 { /////////////////////////////////////////////////////////////////
34   ///////////////////////////////////////////////////////////////////
35   namespace
36   { /////////////////////////////////////////////////////////////////
37
38     /** backward skip whitespace starting at pos_r */
39     inline std::string::size_type backskipWs( const std::string & str_r, std::string::size_type pos_r )
40     {
41       for ( ; pos_r != std::string::npos; --pos_r )
42       {
43         char ch = str_r[pos_r];
44         if ( ch != ' ' && ch != '\t' )
45           break;
46       }
47       return pos_r;
48     }
49
50     /** backward skip non-whitespace starting at pos_r */
51     inline std::string::size_type backskipNWs( const std::string & str_r, std::string::size_type pos_r )
52     {
53       for ( ; pos_r != std::string::npos; --pos_r )
54       {
55         char ch = str_r[pos_r];
56         if ( ch == ' ' || ch == '\t' )
57           break;
58       }
59       return pos_r;
60     }
61
62     /** Split any 'op edition' from str_r */
63     void splitOpEdition( std::string & str_r, Rel & op_r, Edition & ed_r )
64     {
65       if ( str_r.empty() )
66         return;
67       std::string::size_type ch( str_r.size()-1 );
68
69       // check whether the one but last word is a valid Rel:
70       if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
71       {
72         std::string::size_type ee( ch );
73         if ( (ch = backskipNWs( str_r, ch )) != std::string::npos )
74         {
75           std::string::size_type eb( ch );
76           if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
77           {
78             std::string::size_type oe( ch );
79             ch = backskipNWs( str_r, ch ); // now before 'op'? begin
80             if ( op_r.parseFrom( str_r.substr( ch+1, oe-ch ) ) )
81             {
82               // found a legal 'op'
83               ed_r = Edition( str_r.substr( eb+1, ee-eb ) );
84               if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
85                 ch = backskipWs( str_r, ch );
86               str_r.erase( ch+1 );
87               return;
88             }
89           }
90         }
91       }
92       // HERE: Didn't find 'name op edition'
93       // As a convenience we check for an embeded 'op' (not surounded by WS).
94       // But just '[<=>]=?|!=' and not inside '()'.
95       ch = str_r.find_last_of( "<=>)" );
96       if ( ch != std::string::npos && str_r[ch] != ')' )
97       {
98         std::string::size_type oe( ch );
99
100         // do edition first:
101         ch = str_r.find_first_not_of( " \t", oe+1 );
102         if ( ch != std::string::npos )
103           ed_r = Edition( str_r.substr( ch ) );
104
105         // now finish op:
106         ch = oe-1;
107         if ( str_r[oe] != '=' ) // '[<>]'
108         {
109           op_r = ( str_r[oe] == '<' ) ? Rel::LT : Rel::GT;
110         }
111         else
112         { // '?='
113           if ( ch != std::string::npos )
114           {
115             switch ( str_r[ch] )
116             {
117               case '<': --ch; op_r = Rel::LE; break;
118               case '>': --ch; op_r = Rel::GE; break;
119               case '!': --ch; op_r = Rel::NE; break;
120               case '=': --ch; // fall through
121               default:        op_r = Rel::EQ; break;
122             }
123           }
124         }
125
126         // finally name:
127         if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
128           ch = backskipWs( str_r, ch );
129         str_r.erase( ch+1 );
130         return;
131       }
132       // HERE: It's a plain 'name'
133     }
134
135     /** Build \ref Capability from data. No parsing required.
136     */
137     sat::detail::IdType relFromStr( sat::detail::CPool * pool_r,
138                                     const Arch & arch_r,
139                                     const std::string & name_r,
140                                     Rel op_r,
141                                     const Edition & ed_r,
142                                     const ResKind & kind_r )
143     {
144       // First build the name, non-packages prefixed by kind
145       sat::Solvable::SplitIdent split( kind_r, name_r );
146       sat::detail::IdType nid( split.ident().id() );
147
148       if ( split.kind() == ResKind::srcpackage )
149       {
150         // map 'kind srcpackage' to 'arch src', the pseudo architecture
151         // libsolv uses.
152         nid = ::pool_rel2id( pool_r, nid, IdString(ARCH_SRC).id(), REL_ARCH, /*create*/true );
153       }
154
155       // Extend name by architecture, if provided and not a srcpackage
156       if ( ! arch_r.empty() && kind_r != ResKind::srcpackage )
157       {
158         nid = ::pool_rel2id( pool_r, nid, arch_r.id(), REL_ARCH, /*create*/true );
159       }
160
161       // Extend 'op edition', if provided
162       if ( op_r != Rel::ANY && ed_r != Edition::noedition )
163       {
164         nid = ::pool_rel2id( pool_r, nid, ed_r.id(), op_r.bits(), /*create*/true );
165       }
166
167       return nid;
168     }
169
170    /** Build \ref Capability from data, just parsing name for '[.arch]' and detect
171     * 'kind srcpackage' (will be mapped to arch \c src).
172     */
173     sat::detail::IdType relFromStr( sat::detail::CPool * pool_r,
174                                     const std::string & name_r, Rel op_r, const Edition & ed_r,
175                                     const ResKind & kind_r )
176     {
177       static const Arch srcArch( IdString(ARCH_SRC).asString() );
178       static const std::string srcKindPrefix( ResKind::srcpackage.asString() + ':' );
179
180       // check for an embedded 'srcpackage:foo' to be mapped to 'foo' and 'ResKind::srcpackage'.
181       if ( kind_r.empty() && str::hasPrefix( name_r, srcKindPrefix ) )
182       {
183         return relFromStr( pool_r, Arch_empty, name_r.substr( srcKindPrefix.size() ), op_r, ed_r, ResKind::srcpackage );
184       }
185
186       Arch arch( Arch_empty );
187       std::string name( name_r );
188
189       std::string::size_type asep( name_r.rfind( "." ) );
190       if ( asep != std::string::npos )
191       {
192         Arch ext( name_r.substr( asep+1 ) );
193         if ( ext.isBuiltIn() || ext == srcArch )
194         {
195           arch = ext;
196           name.erase( asep );
197         }
198       }
199
200       return relFromStr( pool_r, arch, name, op_r, ed_r, kind_r );
201     }
202
203     /** Full parse from string, unless Capability::PARSED.
204     */
205     sat::detail::IdType relFromStr( sat::detail::CPool * pool_r,
206                                     const Arch & arch_r, // parse from name if empty
207                                     const std::string & str_r, const ResKind & kind_r,
208                                     Capability::CtorFlag flag_r )
209     {
210       std::string name( str_r );
211       Rel         op;
212       Edition     ed;
213       if ( flag_r == Capability::UNPARSED )
214       {
215         splitOpEdition( name, op, ed );
216       }
217
218       if ( arch_r.empty() )
219         return relFromStr( pool_r, name, op, ed, kind_r ); // parses for name[.arch]
220       // else
221       return relFromStr( pool_r, arch_r, name, op, ed, kind_r );
222     }
223
224     /////////////////////////////////////////////////////////////////
225   } // namespace
226   ///////////////////////////////////////////////////////////////////
227
228   const Capability Capability::Null( STRID_NULL );
229   const Capability Capability::Empty( STRID_EMPTY );
230
231   /////////////////////////////////////////////////////////////////
232
233   Capability::Capability( const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
234   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
235   {}
236
237   Capability::Capability( const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
238   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r.c_str(), prefix_r, flag_r ) )
239   {}
240
241   Capability::Capability( const Arch & arch_r, const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
242   : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
243   {}
244
245   Capability::Capability( const Arch & arch_r, const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
246   : _id( relFromStr( myPool().getPool(), arch_r, str_r.c_str(), prefix_r, flag_r ) )
247   {}
248
249   Capability::Capability( const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
250   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
251   {}
252
253   Capability::Capability( const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
254   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
255   {}
256
257   Capability::Capability( const Arch & arch_r, const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
258   : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
259   {}
260
261   Capability::Capability( const Arch & arch_r, const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
262   : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
263   {}
264
265   ///////////////////////////////////////////////////////////////////
266   // Ctor from <name[.arch] op edition>.
267   ///////////////////////////////////////////////////////////////////
268
269   Capability::Capability( const std::string & name_r, const std::string & op_r, const std::string & ed_r, const ResKind & prefix_r )
270   : _id( relFromStr( myPool().getPool(), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
271   {}
272   Capability::Capability( const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
273   : _id( relFromStr( myPool().getPool(), name_r, op_r, Edition(ed_r), prefix_r ) )
274   {}
275   Capability::Capability( const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
276   : _id( relFromStr( myPool().getPool(), name_r, op_r, ed_r, prefix_r ) )
277   {}
278
279   ///////////////////////////////////////////////////////////////////
280   // Ctor from <arch name op edition>.
281   ///////////////////////////////////////////////////////////////////
282
283   Capability::Capability( const std::string & arch_r, const std::string & name_r, const std::string & op_r, const std::string & ed_r, const ResKind & prefix_r )
284   : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
285   {}
286   Capability::Capability( const std::string & arch_r, const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
287   : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, op_r, Edition(ed_r), prefix_r ) )
288   {}
289   Capability::Capability( const std::string & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
290   : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, op_r, ed_r, prefix_r ) )
291   {}
292   Capability::Capability( const Arch & arch_r, const std::string & name_r, const std::string & op_r, const std::string & ed_r, const ResKind & prefix_r )
293   : _id( relFromStr( myPool().getPool(), arch_r, name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
294   {}
295   Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
296   : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, Edition(ed_r), prefix_r ) )
297   {}
298   Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
299   : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, ed_r, prefix_r ) )
300   {}
301
302   ///////////////////////////////////////////////////////////////////
303   // Ctor creating a namespace: capability.
304   ///////////////////////////////////////////////////////////////////
305
306   Capability::Capability( ResolverNamespace namespace_r, IdString value_r )
307   : _id( ::pool_rel2id( myPool().getPool(), asIdString(namespace_r).id(), (value_r.empty() ? STRID_NULL : value_r.id() ), REL_NAMESPACE, /*create*/true ) )
308   {}
309
310
311   const char * Capability::c_str() const
312   { return( _id ? ::pool_dep2str( myPool().getPool(), _id ) : "" ); }
313
314   CapMatch Capability::_doMatch( sat::detail::IdType lhs,  sat::detail::IdType rhs )
315   {
316 #warning MIGRATE TO SAT
317 #warning TESTCASE
318     if ( lhs == rhs )
319       return CapMatch::yes;
320
321     CapDetail l( lhs );
322     CapDetail r( rhs );
323
324     switch ( l.kind() )
325     {
326       case CapDetail::NOCAP:
327         return( r.kind() == CapDetail::NOCAP ); // NOCAP matches NOCAP only
328         break;
329       case CapDetail::EXPRESSION:
330         return CapMatch::irrelevant;
331         break;
332       case CapDetail::NAMED:
333       case CapDetail::VERSIONED:
334         break;
335     }
336
337     switch ( r.kind() )
338     {
339       case CapDetail::NOCAP:
340         return CapMatch::no; // match case handled above
341         break;
342       case CapDetail::EXPRESSION:
343         return CapMatch::irrelevant;
344         break;
345       case CapDetail::NAMED:
346       case CapDetail::VERSIONED:
347         break;
348     }
349     // comparing two simple caps:
350     if ( l.name() != r.name() )
351       return CapMatch::no;
352
353     // if both are arch restricted they must match
354     if ( l.arch() != r.arch()
355          && ! ( l.arch().empty() || r.arch().empty() ) )
356       return CapMatch::no;
357
358     // isNamed matches ANY edition:
359     if ( l.isNamed() || r.isNamed() )
360       return CapMatch::yes;
361
362     // both are versioned:
363     return overlaps( Edition::MatchRange( l.op(), l.ed() ),
364                      Edition::MatchRange( r.op(), r.ed() ) );
365   }
366
367   bool Capability::isInterestingFileSpec( const char * name_r )
368   {
369     static       str::smatch what;
370     static const str::regex  filenameRegex(
371                  "/(s?bin|lib(64)?|etc)/|^/usr/(games/|share/(dict/words|magic\\.mime)$)|^/opt/gnome/games/",
372                  str::regex::nosubs );
373
374     return str::regex_match( name_r, what, filenameRegex );
375   }
376
377   Capability Capability::guessPackageSpec( const std::string & str_r, bool & rewrote_r )
378   {
379     Capability cap( str_r );
380     CapDetail detail( cap.detail() );
381
382     // str_r might be the form "libzypp-1.2.3-4.5(.arch)'
383     // correctly parsed as name capability by the ctor.
384     // TODO: Think about allowing glob char in name - for now don't process
385     if ( detail.isNamed() && !::strpbrk( detail.name().c_str(), "*?[{" )
386       && ::strrchr( detail.name().c_str(), '-' ) && sat::WhatProvides( cap ).empty() )
387     {
388       Arch origArch( detail.arch() ); // to support a trailing .arch
389
390       std::string guess( detail.name().asString() );
391       std::string::size_type pos( guess.rfind( '-' ) );
392       guess[pos] = '=';
393
394       Capability guesscap( origArch, guess );
395       detail = guesscap.detail();
396
397       ResPool pool( ResPool::instance() );
398       // require name part matching a pool items name (not just provides!)
399       if ( pool.byIdentBegin( detail.name() ) != pool.byIdentEnd( detail.name() ) )
400       {
401         rewrote_r = true;
402         return guesscap;
403       }
404
405       // try the one but last '-'
406       if ( pos )
407       {
408         guess[pos] = '-';
409         if ( (pos = guess.rfind( '-', pos-1 )) != std::string::npos )
410         {
411           guess[pos] = '=';
412
413           guesscap = Capability( origArch, guess );
414           detail = guesscap.detail();
415
416           // require name part matching a pool items name (not just provides!)
417           if ( pool.byIdentBegin( detail.name() ) != pool.byIdentEnd( detail.name() ) )
418           {
419             rewrote_r = true;
420             return guesscap;
421           }
422         }
423       }
424     }
425
426     rewrote_r = false;
427     return cap;
428   }
429
430   Capability Capability::guessPackageSpec( const std::string & str_r )
431   {
432     bool dummy;
433     return guessPackageSpec( str_r, dummy );
434   }
435
436   /******************************************************************
437   **
438   **    FUNCTION NAME : operator<<
439   **    FUNCTION TYPE : std::ostream &
440   */
441   std::ostream & operator<<( std::ostream & str, const Capability & obj )
442   {
443     return str << obj.detail();
444   }
445
446   std::ostream & dumpOn( std::ostream & str, const Capability & obj )
447   {
448     return str << obj.detail();
449   }
450
451   ///////////////////////////////////////////////////////////////////
452   //
453   //    CLASS NAME : CapDetail
454   //
455   ///////////////////////////////////////////////////////////////////
456
457   void CapDetail::_init()
458   {
459     // : _kind( NOCAP ), _lhs( id_r ), _rhs( 0 ), _flag( 0 ), _archIfSimple( 0 )
460
461     if ( _lhs == sat::detail::emptyId || _lhs == sat::detail::noId )
462       return; // NOCAP
463
464     if ( ! ISRELDEP(_lhs) )
465     {
466       // this is name without arch!
467       _kind = NAMED;
468       return;
469     }
470
471     ::Reldep * rd = GETRELDEP( myPool().getPool(), _lhs );
472     _lhs  = rd->name;
473     _rhs  = rd->evr;
474     _flag = rd->flags;
475
476     if ( Rel::isRel( _flag ) )
477     {
478       _kind = VERSIONED;
479       // Check for name.arch...
480       if ( ! ISRELDEP(_lhs) )
481         return; // this is name without arch!
482       rd = GETRELDEP( myPool().getPool(), _lhs );
483       if ( rd->flags != CAP_ARCH )
484         return; // this is not name.arch
485       // This is name.arch:
486       _lhs = rd->name;
487       _archIfSimple = rd->evr;
488     }
489     else if ( rd->flags == CAP_ARCH )
490     {
491       _kind = NAMED;
492       // This is name.arch:
493       _lhs = rd->name;
494       _archIfSimple = rd->evr;
495     }
496     else
497     {
498       _kind = EXPRESSION;
499       return;
500     }
501     // map back libsolvs pseudo arch 'src' to kind srcpackage
502     if ( _archIfSimple == ARCH_SRC )
503     {
504       _lhs = IdString( (ResKind::srcpackage.asString() + ":" + IdString(_lhs).c_str()).c_str() ).id();
505       _archIfSimple = 0;
506     }
507   }
508
509   /******************************************************************
510   **
511   **    FUNCTION NAME : operator<<
512   **    FUNCTION TYPE : std::ostream &
513   */
514   std::ostream & operator<<( std::ostream & str, const CapDetail & obj )
515   {
516     static const char archsep = '.';
517     switch ( obj.kind() )
518     {
519       case CapDetail::NOCAP:
520         return str << "<NoCap>";
521         break;
522       case CapDetail::NAMED:
523         str << obj.name();
524         if ( obj.hasArch() )
525           str << archsep << obj.arch();
526         return str;
527         break;
528       case CapDetail::VERSIONED:
529         str << obj.name();
530         if ( obj.hasArch() )
531           str << archsep << obj.arch();
532         return str << " " << obj.op() << " " << obj.ed();
533         break;
534       case CapDetail::EXPRESSION:
535         switch ( obj.capRel() )
536         {
537           case CapDetail::REL_NONE:
538           case CapDetail::CAP_AND:
539           case CapDetail::CAP_OR:
540           case CapDetail::CAP_WITH:
541           case CapDetail::CAP_ARCH:
542             return str << obj.lhs().detail() << " " << obj.capRel() << " " << obj.rhs().detail();
543             break;
544           case CapDetail::CAP_NAMESPACE:
545             return str << obj.lhs().detail() << "(" << obj.rhs().detail() << ")";
546         }
547         break;
548     }
549     return str <<  "<UnknownCap>";
550   }
551
552   std::ostream & operator<<( std::ostream & str, CapDetail::Kind obj )
553   {
554     switch ( obj )
555     {
556       case CapDetail::NOCAP:      return str << "NoCap"; break;
557       case CapDetail::NAMED:      return str << "NamedCap"; break;
558       case CapDetail::VERSIONED:  return str << "VersionedCap"; break;
559       case CapDetail::EXPRESSION: return str << "CapExpression"; break;
560     }
561     return str << "UnknownCap";
562   }
563
564   std::ostream & operator<<( std::ostream & str, CapDetail::CapRel obj )
565   {
566     switch ( obj )
567     {
568       case CapDetail::REL_NONE:      return str << "NoCapRel"; break;
569       case CapDetail::CAP_AND:       return str << "&"; break; // AND
570       case CapDetail::CAP_OR:        return str << "|"; break; // OR
571       case CapDetail::CAP_WITH:      return str << "+"; break; // WITH
572       case CapDetail::CAP_NAMESPACE: return str << "NAMESPACE"; break;
573       case CapDetail::CAP_ARCH:      return str << "ARCH"; break;
574    }
575     return str << "UnknownCapRel";
576   }
577
578   /////////////////////////////////////////////////////////////////
579 } // namespace zypp
580 ///////////////////////////////////////////////////////////////////