CapFactory.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <functional>
00014 #include <set>
00015 #include <map>
00016 
00017 #include <ext/hash_set>
00018 #include <ext/hash_fun.h>
00019 
00020 #include "zypp/base/Logger.h"
00021 #include "zypp/base/Exception.h"
00022 #include "zypp/base/String.h"
00023 #include "zypp/base/Counter.h"
00024 
00025 #include "zypp/CapFactory.h"
00026 #include "zypp/capability/Capabilities.h"
00027 
00028 using std::endl;
00029 
00031 namespace
00032 { 
00033   using ::zypp::Resolvable;
00034   using ::zypp::capability::CapabilityImpl;
00035   using ::zypp::capability::CapImplOrder;
00036 
00037   struct CapImplHashFun
00038   {
00039     size_t operator() ( const CapabilityImpl::Ptr & p ) const
00040     {
00041       return __gnu_cxx::hash<const char*>()( p->encode().c_str() );
00042     }
00043   };
00044 
00045   struct CapImplHashEqual
00046   {
00047     bool operator() ( const CapabilityImpl::Ptr & lhs, const CapabilityImpl::Ptr & rhs ) const
00048     {
00049       return (    lhs->encode() == rhs->encode()
00050                && lhs->kind()   == rhs->kind()
00051                && lhs->refers() == rhs->refers() );
00052     }
00053   };
00054 
00056   //typedef std::set<CapabilityImpl::Ptr,CapImplOrder> USet;
00057   typedef __gnu_cxx::hash_set<CapabilityImpl::Ptr, CapImplHashFun, CapImplHashEqual> USet;
00058 
00059 
00066   USet _uset;
00067 
00077   CapabilityImpl::Ptr usetInsert( CapabilityImpl * allocated_r )
00078   {
00079     return *(_uset.insert( CapabilityImpl::Ptr(allocated_r) ).first);
00080   }
00081 
00085   struct USetStatsCollect : public std::unary_function<CapabilityImpl::constPtr, void>
00086   {
00087     typedef ::zypp::Counter<unsigned> Counter;
00088 
00089     Counter _caps;
00090     std::map<CapabilityImpl::Kind,Counter> _capKind;
00091     std::map<Resolvable::Kind,Counter>     _capRefers;
00092 
00093     void operator()( const CapabilityImpl::constPtr & cap_r )
00094     {
00095       //DBG << *cap_r << endl;
00096       ++_caps;
00097       ++(_capKind[cap_r->kind()]);
00098       ++(_capRefers[cap_r->refers()]);
00099     }
00100 
00101     std::ostream & dumpOn( std::ostream & str ) const
00102     {
00103       str << "  Capabilities total: " << _caps << endl;
00104       str << "  Capability kinds:" << endl;
00105       for ( std::map<CapabilityImpl::Kind,Counter>::const_iterator it = _capKind.begin();
00106             it != _capKind.end(); ++it )
00107         {
00108           str << "    " << it->first << '\t' << it->second << endl;
00109         }
00110       str << "  Capability refers:" << endl;
00111       for ( std::map<Resolvable::Kind,Counter>::const_iterator it = _capRefers.begin();
00112             it != _capRefers.end(); ++it )
00113         {
00114           str << "    " << it->first << '\t' << it->second << endl;
00115         }
00116       return str;
00117     }
00118   };
00119 
00121 } // namespace
00123 
00125 namespace zypp
00126 { 
00127 
00129   //
00130   //    CLASS NAME : CapFactoryImpl
00131   //
00149   struct CapFactory::Impl
00150   {
00152     static void assertResKind( const Resolvable::Kind & refers_r )
00153     {
00154       if ( refers_r == Resolvable::Kind() )
00155         ZYPP_THROW( Exception("Missing or empty  Resolvable::Kind in Capability") );
00156     }
00157 
00167     static bool isEditionSpec( Rel op_r, const Edition & edition_r )
00168     {
00169       switch ( op_r.inSwitch() )
00170         {
00171         case Rel::ANY_e:
00172           if ( edition_r != Edition::noedition )
00173             WAR << "Operator " << op_r << " causes Edition "
00174             << edition_r << " to be ignored." << endl;
00175           return false;
00176           break;
00177 
00178         case Rel::NONE_e:
00179           ZYPP_THROW( Exception("Operator NONE is not allowed in Capability") );
00180           break;
00181 
00182         case Rel::EQ_e:
00183         case Rel::NE_e:
00184         case Rel::LT_e:
00185         case Rel::LE_e:
00186         case Rel::GT_e:
00187         case Rel::GE_e:
00188           return true;
00189           break;
00190         }
00191       // SHOULD NOT GET HERE
00192       ZYPP_THROW( Exception("Unknow Operator NONE is not allowed in Capability") );
00193       return false; // not reached
00194     }
00195 
00197     static bool isFileSpec( const std::string & name_r )
00198     {
00199       return *name_r.c_str() == '/';
00200     }
00201 
00203     static bool isSplitSpec( const std::string & name_r )
00204     {
00205       return name_r.find( ":/" ) != std::string::npos;
00206     }
00207 
00209     static bool isHalSpec( const std::string & name_r )
00210     {
00211       return name_r.substr(0,4) == "hal(";
00212     }
00213 
00215     static bool isModaliasSpec( const std::string & name_r )
00216     {
00217       return name_r.substr(0,9) == "modalias(";
00218     }
00219 
00220     static CapabilityImpl::Ptr buildFile( const Resolvable::Kind & refers_r,
00221                                           const std::string & name_r )
00222     {
00223       // NullCap check first:
00224       if ( name_r.empty() )
00225         {
00226           // Singleton, so no need to put it into _uset !?
00227           return capability::NullCap::instance();
00228         }
00229 
00230       assertResKind( refers_r );
00231 
00232       return usetInsert
00233       ( new capability::FileCap( refers_r, name_r ) );
00234     }
00235 
00242     static CapabilityImpl::Ptr buildNamed( const Resolvable::Kind & refers_r,
00243                                            const std::string & name_r )
00244     {
00245       // NullCap check first:
00246       if ( name_r.empty() )
00247         {
00248           // Singleton, so no need to put it into _uset !?
00249           return capability::NullCap::instance();
00250         }
00251 
00252       assertResKind( refers_r );
00253 
00254       // file:    /absolute/path
00255       if ( isFileSpec( name_r ) )
00256         return usetInsert
00257         ( new capability::FileCap( refers_r, name_r ) );
00258 
00259       //split:   name:/absolute/path
00260       static const str::regex  rx( "([^/]*):(/.*)" );
00261       str::smatch what;
00262       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
00263         {
00264           return usetInsert
00265           ( new capability::SplitCap( refers_r, what[1].str(), what[2].str() ) );
00266         }
00267 
00268       //name:    name
00269       return usetInsert
00270       ( new capability::NamedCap( refers_r, name_r ) );
00271     }
00272 
00281     static CapabilityImpl::Ptr buildVersioned( const Resolvable::Kind & refers_r,
00282                                                const std::string & name_r,
00283                                                Rel op_r,
00284                                                const Edition & edition_r )
00285     {
00286       if ( Impl::isEditionSpec( op_r, edition_r ) )
00287         {
00288           assertResKind( refers_r );
00289 
00290           // build a VersionedCap
00291           return usetInsert
00292           ( new capability::VersionedCap( refers_r, name_r, op_r, edition_r ) );
00293         }
00294       //else
00295       // build a NamedCap
00296 
00297       return buildNamed( refers_r, name_r );
00298     }
00299 
00308     static CapabilityImpl::Ptr buildHal( const Resolvable::Kind & refers_r,
00309                                          const std::string & name_r,
00310                                          Rel op_r = Rel::ANY,
00311                                          const std::string & value_r = std::string() )
00312     {
00313       if ( op_r != Rel::ANY )
00314         {
00315           ZYPP_THROW( Exception("Unsupported kind of Hal Capability '" + op_r.asString() + "'") );
00316         }
00317 
00318       //split:   hal(name) [op string]
00319       static const str::regex  rx( "hal\\(([^)]*)\\)" );
00320       str::smatch what;
00321       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
00322         {
00323           // Hal always refers to 'System' kind of Resolvable.
00324           return usetInsert
00325           ( new capability::HalCap( ResTraits<SystemResObject>::kind,
00326                                     what[1].str() ) );
00327         }
00328       // otherwise
00329       ZYPP_THROW( Exception("Unsupported kind of Hal Capability '" + name_r + "'") );
00330       return NULL; // make gcc happy
00331     }
00332 
00333 
00342     static CapabilityImpl::Ptr buildModalias( const Resolvable::Kind & refers_r,
00343                                               const std::string & name_r,
00344                                               Rel op_r = Rel::ANY,
00345                                               const std::string & value_r = std::string() )
00346     {
00347       if ( op_r != Rel::ANY )
00348         {
00349           ZYPP_THROW( Exception("Unsupported kind of Modalias Capability  '" + op_r.asString() + "'") );
00350         }
00351 
00352       //split:   modalias(name) [op string]
00353       static const str::regex  rx( "modalias\\(([^)]*)\\)" );
00354       str::smatch what;
00355       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
00356         {
00357           // Modalias always refers to 'System' kind of Resolvable.
00358           return usetInsert
00359           ( new capability::ModaliasCap( ResTraits<SystemResObject>::kind,
00360                                          what[1].str() ) );
00361         }
00362       // otherwise
00363       ZYPP_THROW( Exception("Unsupported kind of Modalias Capability'" + name_r + "'") );
00364       return NULL; // make gcc happy
00365     }
00366   };
00368 
00370 
00372   //
00373   //    CLASS NAME : CapFactory
00374   //
00376 
00378   //
00379   //    METHOD NAME : CapFactory::CapFactory
00380   //    METHOD TYPE : Ctor
00381   //
00382   CapFactory::CapFactory()
00383   {}
00384 
00386   //
00387   //    METHOD NAME : CapFactory::~CapFactory
00388   //    METHOD TYPE : Dtor
00389   //
00390   CapFactory::~CapFactory()
00391   {}
00392 
00394   //
00395   //    METHOD NAME : CapFactory::parse
00396   //    METHOD TYPE : Capability
00397   //
00398   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
00399                                 const std::string & strval_r ) const
00400 
00401   try
00402     {
00403       if ( Impl::isHalSpec( strval_r ) )
00404         {
00405           return Capability( Impl::buildHal( refers_r, strval_r ) );
00406         }
00407       if ( Impl::isModaliasSpec( strval_r ) )
00408         {
00409           return Capability( Impl::buildModalias( refers_r, strval_r ) );
00410         }
00411       if ( Impl::isFileSpec( strval_r ) )
00412         {
00413           return Capability( Impl::buildFile( refers_r, strval_r ) );
00414         }
00415 
00416       // strval_r has at least two words which could make 'op edition'?
00417       // improve regex!
00418       static const str::regex  rx( "(.*[^ \t])([ \t]+)([^ \t]+)([ \t]+)([^ \t]+)" );
00419       str::smatch what;
00420       if( str::regex_match( strval_r.begin(), strval_r.end(),what, rx ) )
00421         {
00422           Rel op;
00423           Edition edition;
00424           try
00425             {
00426               op = Rel(what[3].str());
00427               edition = Edition(what[5].str());
00428             }
00429           catch ( Exception & excpt )
00430             {
00431               // So they don't make valid 'op edition'
00432               ZYPP_CAUGHT( excpt );
00433               DBG << "Trying named cap for: " << strval_r << endl;
00434               // See whether it makes a named cap.
00435               return Capability( Impl::buildNamed( refers_r, strval_r ) );
00436             }
00437 
00438           // Valid 'op edition'
00439           return Capability ( Impl::buildVersioned( refers_r,
00440                                                     what[1].str(), op, edition ) );
00441         }
00442       //else
00443       // not a VersionedCap
00444       return Capability( Impl::buildNamed( refers_r, strval_r ) );
00445     }
00446   catch ( Exception & excpt )
00447     {
00448       ZYPP_RETHROW( excpt );
00449       return Capability(); // not reached
00450     }
00451 
00452 
00454   //
00455   //    METHOD NAME : CapFactory::parse
00456   //    METHOD TYPE : Capability
00457   //
00458   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
00459                                 const std::string & name_r,
00460                                 const std::string & op_r,
00461                                 const std::string & edition_r ) const
00462   try
00463     {
00464       if ( Impl::isHalSpec( name_r ) )
00465         {
00466           return Capability( Impl::buildHal( refers_r, name_r, Rel(op_r), edition_r ) );
00467         }
00468       if ( Impl::isModaliasSpec( name_r ) )
00469         {
00470           return Capability( Impl::buildModalias( refers_r, name_r, Rel(op_r), edition_r ) );
00471         }
00472       // Try creating Rel and Edition, then parse
00473       return parse( refers_r, name_r, Rel(op_r), Edition(edition_r) );
00474     }
00475   catch ( Exception & excpt )
00476     {
00477       ZYPP_RETHROW( excpt );
00478       return Capability(); // not reached
00479     }
00480 
00482   //
00483   //    METHOD NAME : CapFactory::parse
00484   //    METHOD TYPE : Capability
00485   //
00486   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
00487                                 const std::string & name_r,
00488                                 Rel op_r,
00489                                 const Edition & edition_r ) const
00490   try
00491     {
00492       if ( Impl::isHalSpec( name_r ) )
00493         {
00494           return Capability( Impl::buildHal( refers_r, name_r, op_r, edition_r.asString() ) );
00495         }
00496       if ( Impl::isModaliasSpec( name_r ) )
00497         {
00498           return Capability( Impl::buildModalias( refers_r, name_r, op_r, edition_r.asString() ) );
00499         }
00500       return Capability( Impl::buildVersioned( refers_r, name_r, op_r, edition_r ) );
00501     }
00502   catch ( Exception & excpt )
00503     {
00504       ZYPP_RETHROW( excpt );
00505       return Capability(); // not reached
00506     }
00507 
00509   //
00510   //    METHOD NAME : CapFactory::halEvalCap
00511   //    METHOD TYPE : Capability
00512   //
00513   Capability CapFactory::halEvalCap() const
00514   try
00515     {
00516       return Capability( Impl::buildHal( Resolvable::Kind(), "hal()" ) );
00517     }
00518   catch ( Exception & excpt )
00519     {
00520       ZYPP_RETHROW( excpt );
00521       return Capability(); // not reached
00522     }
00523 
00525   //
00526   //    METHOD NAME : CapFactory::modaliasEvalCap
00527   //    METHOD TYPE : Capability
00528   //
00529   Capability CapFactory::modaliasEvalCap() const
00530   try
00531     {
00532       return Capability( Impl::buildModalias( Resolvable::Kind(), "modalias()" ) );
00533     }
00534   catch ( Exception & excpt )
00535     {
00536       ZYPP_RETHROW( excpt );
00537       return Capability(); // not reached
00538     }
00539 
00541   //
00542   //    METHOD NAME : CapFactory::encode
00543   //    METHOD TYPE : std::string
00544   //
00545   std::string CapFactory::encode( const Capability & cap_r ) const
00546   {
00547     return cap_r._pimpl->encode();
00548   }
00549 
00550   /******************************************************************
00551   **
00552   **    FUNCTION NAME : operator<<
00553   **    FUNCTION TYPE : std::ostream &
00554   */
00555   std::ostream & operator<<( std::ostream & str, const CapFactory & obj )
00556   {
00557     str << "CapFactory stats:" << endl;
00558 
00559     return for_each( _uset.begin(), _uset.end(), USetStatsCollect() ).dumpOn( str );
00560   }
00561 
00563 } // namespace zypp

Generated on Tue Nov 28 16:49:29 2006 for zypp by  doxygen 1.5.0