Deprecate MediaAccess::downloads (accidentally deleted)
[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
28 using std::endl;
29
30 ///////////////////////////////////////////////////////////////////
31 namespace zypp
32 { /////////////////////////////////////////////////////////////////
33   ///////////////////////////////////////////////////////////////////
34   namespace
35   { /////////////////////////////////////////////////////////////////
36
37     /** backward skip whitespace starting at pos_r */
38     inline std::string::size_type backskipWs( const std::string & str_r, std::string::size_type pos_r )
39     {
40       for ( ; pos_r != std::string::npos; --pos_r )
41       {
42         char ch = str_r[pos_r];
43         if ( ch != ' ' && ch != '\t' )
44           break;
45       }
46       return pos_r;
47     }
48
49     /** backward skip non-whitespace starting at pos_r */
50     inline std::string::size_type backskipNWs( const std::string & str_r, std::string::size_type pos_r )
51     {
52       for ( ; pos_r != std::string::npos; --pos_r )
53       {
54         char ch = str_r[pos_r];
55         if ( ch == ' ' || ch == '\t' )
56           break;
57       }
58       return pos_r;
59     }
60
61     /** Split any 'op edition' from str_r */
62     void splitOpEdition( std::string & str_r, Rel & op_r, Edition & ed_r )
63     {
64       if ( str_r.empty() )
65         return;
66       std::string::size_type ch( str_r.size()-1 );
67
68       // check whether the one but last word is a valid Rel:
69       if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
70       {
71         std::string::size_type ee( ch );
72         if ( (ch = backskipNWs( str_r, ch )) != std::string::npos )
73         {
74           std::string::size_type eb( ch );
75           if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
76           {
77             std::string::size_type oe( ch );
78             ch = backskipNWs( str_r, ch ); // now before 'op'? begin
79             if ( op_r.parseFrom( str_r.substr( ch+1, oe-ch ) ) )
80             {
81               // found a legal 'op'
82               ed_r = Edition( str_r.substr( eb+1, ee-eb ) );
83               if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
84                 ch = backskipWs( str_r, ch );
85               str_r.erase( ch+1 );
86               return;
87             }
88           }
89         }
90       }
91       // HERE: Didn't find 'name op edition'
92       // As a convenience we check for an embeded 'op' (not surounded by WS).
93       // But just '[<=>]=?|!=' and not inside '()'.
94       ch = str_r.find_last_of( "<=>)" );
95       if ( ch != std::string::npos && str_r[ch] != ')' )
96       {
97         std::string::size_type oe( ch );
98
99         // do edition first:
100         ch = str_r.find_first_not_of( " \t", oe+1 );
101         if ( ch != std::string::npos )
102           ed_r = Edition( str_r.substr( ch ) );
103
104         // now finish op:
105         ch = oe-1;
106         if ( str_r[oe] != '=' ) // '[<>]'
107         {
108           op_r = ( str_r[oe] == '<' ) ? Rel::LT : Rel::GT;
109         }
110         else
111         { // '?='
112           if ( ch != std::string::npos )
113           {
114             switch ( str_r[ch] )
115             {
116               case '<': --ch; op_r = Rel::LE; break;
117               case '>': --ch; op_r = Rel::GE; break;
118               case '!': --ch; op_r = Rel::NE; break;
119               case '=': --ch; // fall through
120               default:        op_r = Rel::EQ; break;
121             }
122           }
123         }
124
125         // finally name:
126         if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
127           ch = backskipWs( str_r, ch );
128         str_r.erase( ch+1 );
129         return;
130       }
131       // HERE: It's a plain 'name'
132     }
133
134     /** Build \ref Capability from data. No parsing required.
135     */
136     sat::detail::IdType relFromStr( ::_Pool * pool_r,
137                                     const Arch & arch_r,
138                                     const std::string & name_r,
139                                     Rel op_r,
140                                     const Edition & ed_r,
141                                     const ResKind & kind_r )
142     {
143       // First build the name, non-packages prefixed by kind
144       sat::detail::IdType nid( sat::detail::noId );
145       if ( ! kind_r || kind_r == ResKind::package )
146       {
147         nid = IdString( name_r ).id();
148       }
149       else if ( kind_r == ResKind::srcpackage )
150       {
151         // map 'kind srcpackage' to 'arch src', the pseudo architecture
152         // satsolver uses.
153         nid = IdString( name_r ).id();
154         nid = ::rel2id( pool_r, nid, IdString(ARCH_SRC).id(), REL_ARCH, /*create*/true );
155       }
156       else
157       {
158         nid = IdString( str::form( "%s:%s",
159                         kind_r.c_str(),
160                         name_r.c_str() ) ).id();
161       }
162
163
164       // Extend name by architecture, if provided and not a srcpackage
165       if ( ! arch_r.empty() && kind_r != ResKind::srcpackage )
166       {
167         nid = ::rel2id( pool_r, nid, arch_r.id(), REL_ARCH, /*create*/true );
168       }
169
170       // Extend 'op edition', if provided
171       if ( op_r != Rel::ANY && ed_r != Edition::noedition )
172       {
173         nid = ::rel2id( pool_r, nid, ed_r.id(), op_r.bits(), /*create*/true );
174       }
175
176       return nid;
177     }
178
179    /** Build \ref Capability from data, just parsing name for '[.arch]' and detect
180     * 'kind srcpackage' (will be mapped to arch \c src).
181     */
182     sat::detail::IdType relFromStr( ::_Pool * pool_r,
183                                     const std::string & name_r, Rel op_r, const Edition & ed_r,
184                                     const ResKind & kind_r )
185     {
186       static const Arch srcArch( IdString(ARCH_SRC).asString() );
187       static const std::string srcKindPrefix( ResKind::srcpackage.asString() + ':' );
188
189       // check for an embedded 'srcpackage:foo' to be mapped to 'foo' and 'ResKind::srcpackage'.
190       if ( kind_r.empty() && str::hasPrefix( name_r, srcKindPrefix ) )
191       {
192         return relFromStr( pool_r, Arch_empty, name_r.substr( srcKindPrefix.size() ), op_r, ed_r, ResKind::srcpackage );
193       }
194
195       Arch arch( Arch_empty );
196       std::string name( name_r );
197
198       std::string::size_type asep( name_r.rfind( "." ) );
199       if ( asep != std::string::npos )
200       {
201         Arch ext( name_r.substr( asep+1 ) );
202         if ( ext.isBuiltIn() || ext == srcArch )
203         {
204           arch = ext;
205           name.erase( asep );
206         }
207       }
208
209       return relFromStr( pool_r, arch, name, op_r, ed_r, kind_r );
210     }
211
212     /** Full parse from string, unless Capability::PARSED.
213     */
214     sat::detail::IdType relFromStr( ::_Pool * pool_r,
215                                     const Arch & arch_r, // parse from name if empty
216                                     const std::string & str_r, const ResKind & kind_r,
217                                     Capability::CtorFlag flag_r )
218     {
219       std::string name( str_r );
220       Rel         op;
221       Edition     ed;
222       if ( flag_r == Capability::UNPARSED )
223       {
224         splitOpEdition( name, op, ed );
225       }
226
227       if ( arch_r.empty() )
228         return relFromStr( pool_r, name, op, ed, kind_r ); // parses for name[.arch]
229       // else
230       return relFromStr( pool_r, arch_r, name, op, ed, kind_r );
231     }
232
233     /////////////////////////////////////////////////////////////////
234   } // namespace
235   ///////////////////////////////////////////////////////////////////
236
237   const Capability Capability::Null( STRID_NULL );
238   const Capability Capability::Empty( STRID_EMPTY );
239
240   /////////////////////////////////////////////////////////////////
241
242   Capability::Capability( const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
243   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
244   {}
245
246   Capability::Capability( const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
247   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r.c_str(), prefix_r, flag_r ) )
248   {}
249
250   Capability::Capability( const Arch & arch_r, const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
251   : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
252   {}
253
254   Capability::Capability( const Arch & arch_r, const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
255   : _id( relFromStr( myPool().getPool(), arch_r, str_r.c_str(), prefix_r, flag_r ) )
256   {}
257
258   Capability::Capability( const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
259   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
260   {}
261
262   Capability::Capability( const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
263   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
264   {}
265
266   Capability::Capability( const Arch & arch_r, const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
267   : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
268   {}
269
270   Capability::Capability( const Arch & arch_r, const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
271   : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
272   {}
273
274   ///////////////////////////////////////////////////////////////////
275   // Ctor from <name[.arch] op edition>.
276   ///////////////////////////////////////////////////////////////////
277
278   Capability::Capability( const std::string & name_r, const std::string & op_r, const std::string & ed_r, const ResKind & prefix_r )
279   : _id( relFromStr( myPool().getPool(), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
280   {}
281   Capability::Capability( const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
282   : _id( relFromStr( myPool().getPool(), name_r, op_r, Edition(ed_r), prefix_r ) )
283   {}
284   Capability::Capability( const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
285   : _id( relFromStr( myPool().getPool(), name_r, op_r, ed_r, prefix_r ) )
286   {}
287
288   ///////////////////////////////////////////////////////////////////
289   // Ctor from <arch name op edition>.
290   ///////////////////////////////////////////////////////////////////
291
292   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 )
293   : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
294   {}
295   Capability::Capability( const std::string & 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(arch_r), name_r, op_r, Edition(ed_r), prefix_r ) )
297   {}
298   Capability::Capability( const std::string & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
299   : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, op_r, ed_r, prefix_r ) )
300   {}
301   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 )
302   : _id( relFromStr( myPool().getPool(), arch_r, name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
303   {}
304   Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
305   : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, Edition(ed_r), prefix_r ) )
306   {}
307   Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
308   : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, ed_r, prefix_r ) )
309   {}
310
311   const char * Capability::c_str() const
312   { return( _id ? ::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::optimize|str::regex::nosubs );
373
374     return str::regex_match( name_r, what, filenameRegex );
375   }
376
377   Capability Capability::guessPackageSpec( const std::string & str_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     if ( detail.isNamed() && ::strrchr( detail.name().c_str(), '-' ) && sat::WhatProvides( cap ).empty() )
385     {
386       Arch origArch( detail.arch() ); // to support a trailing .arch
387
388       std::string guess( detail.name().asString() );
389       std::string::size_type pos( guess.rfind( '-' ) );
390       guess[pos] = '=';
391
392       Capability guesscap( origArch, guess );
393       detail = guesscap.detail();
394
395       if ( ! sat::WhatProvides( Capability(detail.name().id()) ).empty() )
396         return guesscap;
397
398       // try the one but last '-'
399       if ( pos )
400       {
401         guess[pos] = '-';
402         if ( (pos = guess.rfind( '-', pos-1 )) != std::string::npos )
403         {
404           guess[pos] = '=';
405
406           guesscap = Capability( origArch, guess );
407           detail = guesscap.detail();
408
409           if ( ! sat::WhatProvides( Capability(detail.name().id()) ).empty() )
410             return guesscap;
411         }
412       }
413     }
414     return cap;
415   }
416
417   /******************************************************************
418   **
419   **    FUNCTION NAME : operator<<
420   **    FUNCTION TYPE : std::ostream &
421   */
422   std::ostream & operator<<( std::ostream & str, const Capability & obj )
423   {
424     return str << obj.detail();
425   }
426
427   std::ostream & dumpOn( std::ostream & str, const Capability & obj )
428   {
429     return str << obj.detail();
430   }
431
432   ///////////////////////////////////////////////////////////////////
433   //
434   //    CLASS NAME : CapDetail
435   //
436   ///////////////////////////////////////////////////////////////////
437
438   void CapDetail::_init()
439   {
440     // : _kind( NOCAP ), _lhs( id_r ), _rhs( 0 ), _flag( 0 ), _archIfSimple( 0 )
441
442     if ( _lhs == sat::detail::emptyId || _lhs == sat::detail::noId )
443       return; // NOCAP
444
445     if ( ! ISRELDEP(_lhs) )
446     {
447       // this is name without arch!
448       _kind = NAMED;
449       return;
450     }
451
452     ::Reldep * rd = GETRELDEP( myPool().getPool(), _lhs );
453     _lhs  = rd->name;
454     _rhs  = rd->evr;
455     _flag = rd->flags;
456
457     if ( Rel::isRel( _flag ) )
458     {
459       _kind = VERSIONED;
460       // Check for name.arch...
461       if ( ! ISRELDEP(_lhs) )
462         return; // this is name without arch!
463       rd = GETRELDEP( myPool().getPool(), _lhs );
464       if ( rd->flags != CAP_ARCH )
465         return; // this is not name.arch
466       // This is name.arch:
467       _lhs = rd->name;
468       _archIfSimple = rd->evr;
469     }
470     else if ( rd->flags == CAP_ARCH )
471     {
472       _kind = NAMED;
473       // This is name.arch:
474       _lhs = rd->name;
475       _archIfSimple = rd->evr;
476     }
477     else
478     {
479       _kind = EXPRESSION;
480       return;
481     }
482     // map back satsolvers pseudo arch 'src' to kind srcpackage
483     if ( _archIfSimple == ARCH_SRC )
484     {
485       _lhs = IdString( (ResKind::srcpackage.asString() + ":" + IdString(_lhs).c_str()).c_str() ).id();
486       _archIfSimple = 0;
487     }
488   }
489
490   /******************************************************************
491   **
492   **    FUNCTION NAME : operator<<
493   **    FUNCTION TYPE : std::ostream &
494   */
495   std::ostream & operator<<( std::ostream & str, const CapDetail & obj )
496   {
497     static const char archsep = '.';
498     switch ( obj.kind() )
499     {
500       case CapDetail::NOCAP:
501         return str << "<NoCap>";
502         break;
503       case CapDetail::NAMED:
504         str << obj.name();
505         if ( obj.hasArch() )
506           str << archsep << obj.arch();
507         return str;
508         break;
509       case CapDetail::VERSIONED:
510         str << obj.name();
511         if ( obj.hasArch() )
512           str << archsep << obj.arch();
513         return str << " " << obj.op() << " " << obj.ed();
514         break;
515       case CapDetail::EXPRESSION:
516         switch ( obj.capRel() )
517         {
518           case CapDetail::REL_NONE:
519           case CapDetail::CAP_AND:
520           case CapDetail::CAP_OR:
521           case CapDetail::CAP_WITH:
522           case CapDetail::CAP_ARCH:
523             return str << obj.lhs().detail() << " " << obj.capRel() << " " << obj.rhs().detail();
524             break;
525           case CapDetail::CAP_NAMESPACE:
526             return str << obj.lhs().detail() << "(" << obj.rhs().detail() << ")";
527         }
528         break;
529     }
530     return str <<  "<UnknownCap>";
531   }
532
533   std::ostream & operator<<( std::ostream & str, CapDetail::Kind obj )
534   {
535     switch ( obj )
536     {
537       case CapDetail::NOCAP:      return str << "NoCap"; break;
538       case CapDetail::NAMED:      return str << "NamedCap"; break;
539       case CapDetail::VERSIONED:  return str << "VersionedCap"; break;
540       case CapDetail::EXPRESSION: return str << "CapExpression"; break;
541     }
542     return str << "UnknownCap";
543   }
544
545   std::ostream & operator<<( std::ostream & str, CapDetail::CapRel obj )
546   {
547     switch ( obj )
548     {
549       case CapDetail::REL_NONE:      return str << "NoCapRel"; break;
550       case CapDetail::CAP_AND:       return str << "&"; break; // AND
551       case CapDetail::CAP_OR:        return str << "|"; break; // OR
552       case CapDetail::CAP_WITH:      return str << "+"; break; // WITH
553       case CapDetail::CAP_NAMESPACE: return str << "NAMESPACE"; break;
554       case CapDetail::CAP_ARCH:      return str << "ARCH"; break;
555    }
556     return str << "UnknownCapRel";
557   }
558
559   /////////////////////////////////////////////////////////////////
560 } // namespace zypp
561 ///////////////////////////////////////////////////////////////////