libzypp  10.5.0
Capability.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include "zypp/base/Logger.h"
00014 
00015 #include "zypp/base/String.h"
00016 #include "zypp/base/Regex.h"
00017 #include "zypp/base/Gettext.h"
00018 #include "zypp/base/Exception.h"
00019 
00020 #include "zypp/Arch.h"
00021 #include "zypp/Rel.h"
00022 #include "zypp/Edition.h"
00023 #include "zypp/Capability.h"
00024 
00025 #include "zypp/sat/detail/PoolImpl.h"
00026 #include "zypp/sat/Pool.h"
00027 #include "zypp/ResPool.h"
00028 
00029 using std::endl;
00030 
00032 namespace zypp
00033 { 
00034 
00035   namespace
00036   { 
00037 
00039     inline std::string::size_type backskipWs( const std::string & str_r, std::string::size_type pos_r )
00040     {
00041       for ( ; pos_r != std::string::npos; --pos_r )
00042       {
00043         char ch = str_r[pos_r];
00044         if ( ch != ' ' && ch != '\t' )
00045           break;
00046       }
00047       return pos_r;
00048     }
00049 
00051     inline std::string::size_type backskipNWs( const std::string & str_r, std::string::size_type pos_r )
00052     {
00053       for ( ; pos_r != std::string::npos; --pos_r )
00054       {
00055         char ch = str_r[pos_r];
00056         if ( ch == ' ' || ch == '\t' )
00057           break;
00058       }
00059       return pos_r;
00060     }
00061 
00063     void splitOpEdition( std::string & str_r, Rel & op_r, Edition & ed_r )
00064     {
00065       if ( str_r.empty() )
00066         return;
00067       std::string::size_type ch( str_r.size()-1 );
00068 
00069       // check whether the one but last word is a valid Rel:
00070       if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
00071       {
00072         std::string::size_type ee( ch );
00073         if ( (ch = backskipNWs( str_r, ch )) != std::string::npos )
00074         {
00075           std::string::size_type eb( ch );
00076           if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
00077           {
00078             std::string::size_type oe( ch );
00079             ch = backskipNWs( str_r, ch ); // now before 'op'? begin
00080             if ( op_r.parseFrom( str_r.substr( ch+1, oe-ch ) ) )
00081             {
00082               // found a legal 'op'
00083               ed_r = Edition( str_r.substr( eb+1, ee-eb ) );
00084               if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
00085                 ch = backskipWs( str_r, ch );
00086               str_r.erase( ch+1 );
00087               return;
00088             }
00089           }
00090         }
00091       }
00092       // HERE: Didn't find 'name op edition'
00093       // As a convenience we check for an embeded 'op' (not surounded by WS).
00094       // But just '[<=>]=?|!=' and not inside '()'.
00095       ch = str_r.find_last_of( "<=>)" );
00096       if ( ch != std::string::npos && str_r[ch] != ')' )
00097       {
00098         std::string::size_type oe( ch );
00099 
00100         // do edition first:
00101         ch = str_r.find_first_not_of( " \t", oe+1 );
00102         if ( ch != std::string::npos )
00103           ed_r = Edition( str_r.substr( ch ) );
00104 
00105         // now finish op:
00106         ch = oe-1;
00107         if ( str_r[oe] != '=' ) // '[<>]'
00108         {
00109           op_r = ( str_r[oe] == '<' ) ? Rel::LT : Rel::GT;
00110         }
00111         else
00112         { // '?='
00113           if ( ch != std::string::npos )
00114           {
00115             switch ( str_r[ch] )
00116             {
00117               case '<': --ch; op_r = Rel::LE; break;
00118               case '>': --ch; op_r = Rel::GE; break;
00119               case '!': --ch; op_r = Rel::NE; break;
00120               case '=': --ch; // fall through
00121               default:        op_r = Rel::EQ; break;
00122             }
00123           }
00124         }
00125 
00126         // finally name:
00127         if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
00128           ch = backskipWs( str_r, ch );
00129         str_r.erase( ch+1 );
00130         return;
00131       }
00132       // HERE: It's a plain 'name'
00133     }
00134 
00137     sat::detail::IdType relFromStr( ::_Pool * pool_r,
00138                                     const Arch & arch_r,
00139                                     const std::string & name_r,
00140                                     Rel op_r,
00141                                     const Edition & ed_r,
00142                                     const ResKind & kind_r )
00143     {
00144       // First build the name, non-packages prefixed by kind
00145       sat::Solvable::SplitIdent split( kind_r, name_r );
00146       sat::detail::IdType nid( split.ident().id() );
00147 
00148       if ( split.kind() == ResKind::srcpackage )
00149       {
00150         // map 'kind srcpackage' to 'arch src', the pseudo architecture
00151         // libsolv uses.
00152         nid = ::pool_rel2id( pool_r, nid, IdString(ARCH_SRC).id(), REL_ARCH, /*create*/true );
00153       }
00154 
00155       // Extend name by architecture, if provided and not a srcpackage
00156       if ( ! arch_r.empty() && kind_r != ResKind::srcpackage )
00157       {
00158         nid = ::pool_rel2id( pool_r, nid, arch_r.id(), REL_ARCH, /*create*/true );
00159       }
00160 
00161       // Extend 'op edition', if provided
00162       if ( op_r != Rel::ANY && ed_r != Edition::noedition )
00163       {
00164         nid = ::pool_rel2id( pool_r, nid, ed_r.id(), op_r.bits(), /*create*/true );
00165       }
00166 
00167       return nid;
00168     }
00169 
00173     sat::detail::IdType relFromStr( ::_Pool * pool_r,
00174                                     const std::string & name_r, Rel op_r, const Edition & ed_r,
00175                                     const ResKind & kind_r )
00176     {
00177       static const Arch srcArch( IdString(ARCH_SRC).asString() );
00178       static const std::string srcKindPrefix( ResKind::srcpackage.asString() + ':' );
00179 
00180       // check for an embedded 'srcpackage:foo' to be mapped to 'foo' and 'ResKind::srcpackage'.
00181       if ( kind_r.empty() && str::hasPrefix( name_r, srcKindPrefix ) )
00182       {
00183         return relFromStr( pool_r, Arch_empty, name_r.substr( srcKindPrefix.size() ), op_r, ed_r, ResKind::srcpackage );
00184       }
00185 
00186       Arch arch( Arch_empty );
00187       std::string name( name_r );
00188 
00189       std::string::size_type asep( name_r.rfind( "." ) );
00190       if ( asep != std::string::npos )
00191       {
00192         Arch ext( name_r.substr( asep+1 ) );
00193         if ( ext.isBuiltIn() || ext == srcArch )
00194         {
00195           arch = ext;
00196           name.erase( asep );
00197         }
00198       }
00199 
00200       return relFromStr( pool_r, arch, name, op_r, ed_r, kind_r );
00201     }
00202 
00205     sat::detail::IdType relFromStr( ::_Pool * pool_r,
00206                                     const Arch & arch_r, // parse from name if empty
00207                                     const std::string & str_r, const ResKind & kind_r,
00208                                     Capability::CtorFlag flag_r )
00209     {
00210       std::string name( str_r );
00211       Rel         op;
00212       Edition     ed;
00213       if ( flag_r == Capability::UNPARSED )
00214       {
00215         splitOpEdition( name, op, ed );
00216       }
00217 
00218       if ( arch_r.empty() )
00219         return relFromStr( pool_r, name, op, ed, kind_r ); // parses for name[.arch]
00220       // else
00221       return relFromStr( pool_r, arch_r, name, op, ed, kind_r );
00222     }
00223 
00225   } // namespace
00227 
00228   const Capability Capability::Null( STRID_NULL );
00229   const Capability Capability::Empty( STRID_EMPTY );
00230 
00232 
00233   Capability::Capability( const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
00234   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
00235   {}
00236 
00237   Capability::Capability( const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
00238   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r.c_str(), prefix_r, flag_r ) )
00239   {}
00240 
00241   Capability::Capability( const Arch & arch_r, const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
00242   : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
00243   {}
00244 
00245   Capability::Capability( const Arch & arch_r, const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
00246   : _id( relFromStr( myPool().getPool(), arch_r, str_r.c_str(), prefix_r, flag_r ) )
00247   {}
00248 
00249   Capability::Capability( const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
00250   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
00251   {}
00252 
00253   Capability::Capability( const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
00254   : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
00255   {}
00256 
00257   Capability::Capability( const Arch & arch_r, const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
00258   : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
00259   {}
00260 
00261   Capability::Capability( const Arch & arch_r, const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
00262   : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
00263   {}
00264 
00266   // Ctor from <name[.arch] op edition>.
00268 
00269   Capability::Capability( const std::string & name_r, const std::string & op_r, const std::string & ed_r, const ResKind & prefix_r )
00270   : _id( relFromStr( myPool().getPool(), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
00271   {}
00272   Capability::Capability( const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
00273   : _id( relFromStr( myPool().getPool(), name_r, op_r, Edition(ed_r), prefix_r ) )
00274   {}
00275   Capability::Capability( const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
00276   : _id( relFromStr( myPool().getPool(), name_r, op_r, ed_r, prefix_r ) )
00277   {}
00278 
00280   // Ctor from <arch name op edition>.
00282 
00283   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 )
00284   : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
00285   {}
00286   Capability::Capability( const std::string & arch_r, const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
00287   : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, op_r, Edition(ed_r), prefix_r ) )
00288   {}
00289   Capability::Capability( const std::string & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
00290   : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, op_r, ed_r, prefix_r ) )
00291   {}
00292   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 )
00293   : _id( relFromStr( myPool().getPool(), arch_r, name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
00294   {}
00295   Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
00296   : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, Edition(ed_r), prefix_r ) )
00297   {}
00298   Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
00299   : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, ed_r, prefix_r ) )
00300   {}
00301 
00302   const char * Capability::c_str() const
00303   { return( _id ? ::pool_dep2str( myPool().getPool(), _id ) : "" ); }
00304 
00305   CapMatch Capability::_doMatch( sat::detail::IdType lhs,  sat::detail::IdType rhs )
00306   {
00307 #warning MIGRATE TO SAT
00308 #warning TESTCASE
00309     if ( lhs == rhs )
00310       return CapMatch::yes;
00311 
00312     CapDetail l( lhs );
00313     CapDetail r( rhs );
00314 
00315     switch ( l.kind() )
00316     {
00317       case CapDetail::NOCAP:
00318         return( r.kind() == CapDetail::NOCAP ); // NOCAP matches NOCAP only
00319         break;
00320       case CapDetail::EXPRESSION:
00321         return CapMatch::irrelevant;
00322         break;
00323       case CapDetail::NAMED:
00324       case CapDetail::VERSIONED:
00325         break;
00326     }
00327 
00328     switch ( r.kind() )
00329     {
00330       case CapDetail::NOCAP:
00331         return CapMatch::no; // match case handled above
00332         break;
00333       case CapDetail::EXPRESSION:
00334         return CapMatch::irrelevant;
00335         break;
00336       case CapDetail::NAMED:
00337       case CapDetail::VERSIONED:
00338         break;
00339     }
00340     // comparing two simple caps:
00341     if ( l.name() != r.name() )
00342       return CapMatch::no;
00343 
00344     // if both are arch restricted they must match
00345     if ( l.arch() != r.arch()
00346          && ! ( l.arch().empty() || r.arch().empty() ) )
00347       return CapMatch::no;
00348 
00349     // isNamed matches ANY edition:
00350     if ( l.isNamed() || r.isNamed() )
00351       return CapMatch::yes;
00352 
00353     // both are versioned:
00354     return overlaps( Edition::MatchRange( l.op(), l.ed() ),
00355                      Edition::MatchRange( r.op(), r.ed() ) );
00356   }
00357 
00358   bool Capability::isInterestingFileSpec( const char * name_r )
00359   {
00360     static       str::smatch what;
00361     static const str::regex  filenameRegex(
00362                  "/(s?bin|lib(64)?|etc)/|^/usr/(games/|share/(dict/words|magic\\.mime)$)|^/opt/gnome/games/",
00363                  str::regex::optimize|str::regex::nosubs );
00364 
00365     return str::regex_match( name_r, what, filenameRegex );
00366   }
00367 
00368   Capability Capability::guessPackageSpec( const std::string & str_r, bool & rewrote_r )
00369   {
00370     Capability cap( str_r );
00371     CapDetail detail( cap.detail() );
00372 
00373     // str_r might be the form "libzypp-1.2.3-4.5(.arch)'
00374     // correctly parsed as name capability by the ctor.
00375     if ( detail.isNamed() && ::strrchr( detail.name().c_str(), '-' ) && sat::WhatProvides( cap ).empty() )
00376     {
00377       Arch origArch( detail.arch() ); // to support a trailing .arch
00378 
00379       std::string guess( detail.name().asString() );
00380       std::string::size_type pos( guess.rfind( '-' ) );
00381       guess[pos] = '=';
00382 
00383       Capability guesscap( origArch, guess );
00384       detail = guesscap.detail();
00385 
00386       ResPool pool( ResPool::instance() );
00387       // require name part matching a pool items name (not just provides!)
00388       if ( pool.byIdentBegin( detail.name() ) != pool.byIdentEnd( detail.name() ) )
00389       {
00390         rewrote_r = true;
00391         return guesscap;
00392       }
00393 
00394       // try the one but last '-'
00395       if ( pos )
00396       {
00397         guess[pos] = '-';
00398         if ( (pos = guess.rfind( '-', pos-1 )) != std::string::npos )
00399         {
00400           guess[pos] = '=';
00401 
00402           guesscap = Capability( origArch, guess );
00403           detail = guesscap.detail();
00404 
00405           // require name part matching a pool items name (not just provides!)
00406           if ( pool.byIdentBegin( detail.name() ) != pool.byIdentEnd( detail.name() ) )
00407           {
00408             rewrote_r = true;
00409             return guesscap;
00410           }
00411         }
00412       }
00413     }
00414 
00415     rewrote_r = false;
00416     return cap;
00417   }
00418 
00419   Capability Capability::guessPackageSpec( const std::string & str_r )
00420   {
00421     bool dummy;
00422     return guessPackageSpec( str_r, dummy );
00423   }
00424 
00425   /******************************************************************
00426   **
00427   **    FUNCTION NAME : operator<<
00428   **    FUNCTION TYPE : std::ostream &
00429   */
00430   std::ostream & operator<<( std::ostream & str, const Capability & obj )
00431   {
00432     return str << obj.detail();
00433   }
00434 
00435   std::ostream & dumpOn( std::ostream & str, const Capability & obj )
00436   {
00437     return str << obj.detail();
00438   }
00439 
00441   //
00442   //    CLASS NAME : CapDetail
00443   //
00445 
00446   void CapDetail::_init()
00447   {
00448     // : _kind( NOCAP ), _lhs( id_r ), _rhs( 0 ), _flag( 0 ), _archIfSimple( 0 )
00449 
00450     if ( _lhs == sat::detail::emptyId || _lhs == sat::detail::noId )
00451       return; // NOCAP
00452 
00453     if ( ! ISRELDEP(_lhs) )
00454     {
00455       // this is name without arch!
00456       _kind = NAMED;
00457       return;
00458     }
00459 
00460     ::Reldep * rd = GETRELDEP( myPool().getPool(), _lhs );
00461     _lhs  = rd->name;
00462     _rhs  = rd->evr;
00463     _flag = rd->flags;
00464 
00465     if ( Rel::isRel( _flag ) )
00466     {
00467       _kind = VERSIONED;
00468       // Check for name.arch...
00469       if ( ! ISRELDEP(_lhs) )
00470         return; // this is name without arch!
00471       rd = GETRELDEP( myPool().getPool(), _lhs );
00472       if ( rd->flags != CAP_ARCH )
00473         return; // this is not name.arch
00474       // This is name.arch:
00475       _lhs = rd->name;
00476       _archIfSimple = rd->evr;
00477     }
00478     else if ( rd->flags == CAP_ARCH )
00479     {
00480       _kind = NAMED;
00481       // This is name.arch:
00482       _lhs = rd->name;
00483       _archIfSimple = rd->evr;
00484     }
00485     else
00486     {
00487       _kind = EXPRESSION;
00488       return;
00489     }
00490     // map back libsolvs pseudo arch 'src' to kind srcpackage
00491     if ( _archIfSimple == ARCH_SRC )
00492     {
00493       _lhs = IdString( (ResKind::srcpackage.asString() + ":" + IdString(_lhs).c_str()).c_str() ).id();
00494       _archIfSimple = 0;
00495     }
00496   }
00497 
00498   /******************************************************************
00499   **
00500   **    FUNCTION NAME : operator<<
00501   **    FUNCTION TYPE : std::ostream &
00502   */
00503   std::ostream & operator<<( std::ostream & str, const CapDetail & obj )
00504   {
00505     static const char archsep = '.';
00506     switch ( obj.kind() )
00507     {
00508       case CapDetail::NOCAP:
00509         return str << "<NoCap>";
00510         break;
00511       case CapDetail::NAMED:
00512         str << obj.name();
00513         if ( obj.hasArch() )
00514           str << archsep << obj.arch();
00515         return str;
00516         break;
00517       case CapDetail::VERSIONED:
00518         str << obj.name();
00519         if ( obj.hasArch() )
00520           str << archsep << obj.arch();
00521         return str << " " << obj.op() << " " << obj.ed();
00522         break;
00523       case CapDetail::EXPRESSION:
00524         switch ( obj.capRel() )
00525         {
00526           case CapDetail::REL_NONE:
00527           case CapDetail::CAP_AND:
00528           case CapDetail::CAP_OR:
00529           case CapDetail::CAP_WITH:
00530           case CapDetail::CAP_ARCH:
00531             return str << obj.lhs().detail() << " " << obj.capRel() << " " << obj.rhs().detail();
00532             break;
00533           case CapDetail::CAP_NAMESPACE:
00534             return str << obj.lhs().detail() << "(" << obj.rhs().detail() << ")";
00535         }
00536         break;
00537     }
00538     return str <<  "<UnknownCap>";
00539   }
00540 
00541   std::ostream & operator<<( std::ostream & str, CapDetail::Kind obj )
00542   {
00543     switch ( obj )
00544     {
00545       case CapDetail::NOCAP:      return str << "NoCap"; break;
00546       case CapDetail::NAMED:      return str << "NamedCap"; break;
00547       case CapDetail::VERSIONED:  return str << "VersionedCap"; break;
00548       case CapDetail::EXPRESSION: return str << "CapExpression"; break;
00549     }
00550     return str << "UnknownCap";
00551   }
00552 
00553   std::ostream & operator<<( std::ostream & str, CapDetail::CapRel obj )
00554   {
00555     switch ( obj )
00556     {
00557       case CapDetail::REL_NONE:      return str << "NoCapRel"; break;
00558       case CapDetail::CAP_AND:       return str << "&"; break; // AND
00559       case CapDetail::CAP_OR:        return str << "|"; break; // OR
00560       case CapDetail::CAP_WITH:      return str << "+"; break; // WITH
00561       case CapDetail::CAP_NAMESPACE: return str << "NAMESPACE"; break;
00562       case CapDetail::CAP_ARCH:      return str << "ARCH"; break;
00563    }
00564     return str << "UnknownCapRel";
00565   }
00566 
00568 } // namespace zypp