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       //split:   modalias(name) [op string]
00348       static const str::regex  rx( "modalias\\(([^)]*)\\)" );
00349       str::smatch what;
00350       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
00351         {
00352           // Modalias always refers to 'System' kind of Resolvable.
00353           return usetInsert
00354           ( new capability::ModaliasCap( ResTraits<SystemResObject>::kind,
00355                                          what[1].str(), op_r, value_r ) );
00356         }
00357       // otherwise
00358       ZYPP_THROW( Exception("Unsupported kind of Modalias Capability'" + name_r + "'") );
00359       return NULL; // make gcc happy
00360     }
00361   };
00363 
00365 
00367   //
00368   //    CLASS NAME : CapFactory
00369   //
00371 
00373   //
00374   //    METHOD NAME : CapFactory::CapFactory
00375   //    METHOD TYPE : Ctor
00376   //
00377   CapFactory::CapFactory()
00378   {}
00379 
00381   //
00382   //    METHOD NAME : CapFactory::~CapFactory
00383   //    METHOD TYPE : Dtor
00384   //
00385   CapFactory::~CapFactory()
00386   {}
00387 
00389   //
00390   //    METHOD NAME : CapFactory::parse
00391   //    METHOD TYPE : Capability
00392   //
00393   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
00394                                 const std::string & strval_r ) const
00395 
00396   try
00397     {
00398       if ( Impl::isHalSpec( strval_r ) )
00399         {
00400           return Capability( Impl::buildHal( refers_r, strval_r ) );
00401         }
00402       if ( Impl::isModaliasSpec( strval_r ) )
00403         {
00404           return Capability( Impl::buildModalias( refers_r, strval_r ) );
00405         }
00406       if ( Impl::isFileSpec( strval_r ) )
00407         {
00408           return Capability( Impl::buildFile( refers_r, strval_r ) );
00409         }
00410 
00411       // strval_r has at least two words which could make 'op edition'?
00412       // improve regex!
00413       static const str::regex  rx( "(.*[^ \t])([ \t]+)([^ \t]+)([ \t]+)([^ \t]+)" );
00414       str::smatch what;
00415       if( str::regex_match( strval_r.begin(), strval_r.end(),what, rx ) )
00416         {
00417           Rel op;
00418           Edition edition;
00419           try
00420             {
00421               op = Rel(what[3].str());
00422               edition = Edition(what[5].str());
00423             }
00424           catch ( Exception & excpt )
00425             {
00426               // So they don't make valid 'op edition'
00427               ZYPP_CAUGHT( excpt );
00428               DBG << "Trying named cap for: " << strval_r << endl;
00429               // See whether it makes a named cap.
00430               return Capability( Impl::buildNamed( refers_r, strval_r ) );
00431             }
00432 
00433           // Valid 'op edition'
00434           return Capability ( Impl::buildVersioned( refers_r,
00435                                                     what[1].str(), op, edition ) );
00436         }
00437       //else
00438       // not a VersionedCap
00439       return Capability( Impl::buildNamed( refers_r, strval_r ) );
00440     }
00441   catch ( Exception & excpt )
00442     {
00443       ZYPP_RETHROW( excpt );
00444       return Capability(); // not reached
00445     }
00446 
00447 
00449   //
00450   //    METHOD NAME : CapFactory::parse
00451   //    METHOD TYPE : Capability
00452   //
00453   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
00454                                 const std::string & name_r,
00455                                 const std::string & op_r,
00456                                 const std::string & edition_r ) const
00457   try
00458     {
00459       if ( Impl::isHalSpec( name_r ) )
00460         {
00461           return Capability( Impl::buildHal( refers_r, name_r, Rel(op_r), edition_r ) );
00462         }
00463       if ( Impl::isModaliasSpec( name_r ) )
00464         {
00465           return Capability( Impl::buildModalias( refers_r, name_r, Rel(op_r), edition_r ) );
00466         }
00467       // Try creating Rel and Edition, then parse
00468       return parse( refers_r, name_r, Rel(op_r), Edition(edition_r) );
00469     }
00470   catch ( Exception & excpt )
00471     {
00472       ZYPP_RETHROW( excpt );
00473       return Capability(); // not reached
00474     }
00475 
00477   //
00478   //    METHOD NAME : CapFactory::parse
00479   //    METHOD TYPE : Capability
00480   //
00481   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
00482                                 const std::string & name_r,
00483                                 Rel op_r,
00484                                 const Edition & edition_r ) const
00485   try
00486     {
00487       if ( Impl::isHalSpec( name_r ) )
00488         {
00489           return Capability( Impl::buildHal( refers_r, name_r, op_r, edition_r.asString() ) );
00490         }
00491       if ( Impl::isModaliasSpec( name_r ) )
00492         {
00493           return Capability( Impl::buildModalias( refers_r, name_r, op_r, edition_r.asString() ) );
00494         }
00495       return Capability( Impl::buildVersioned( refers_r, name_r, op_r, edition_r ) );
00496     }
00497   catch ( Exception & excpt )
00498     {
00499       ZYPP_RETHROW( excpt );
00500       return Capability(); // not reached
00501     }
00502 
00504   //
00505   //    METHOD NAME : CapFactory::halEvalCap
00506   //    METHOD TYPE : Capability
00507   //
00508   Capability CapFactory::halEvalCap() const
00509   try
00510     {
00511       return Capability( Impl::buildHal( Resolvable::Kind(), "hal()" ) );
00512     }
00513   catch ( Exception & excpt )
00514     {
00515       ZYPP_RETHROW( excpt );
00516       return Capability(); // not reached
00517     }
00518 
00520   //
00521   //    METHOD NAME : CapFactory::modaliasEvalCap
00522   //    METHOD TYPE : Capability
00523   //
00524   Capability CapFactory::modaliasEvalCap() const
00525   try
00526     {
00527       return Capability( Impl::buildModalias( Resolvable::Kind(), "modalias()" ) );
00528     }
00529   catch ( Exception & excpt )
00530     {
00531       ZYPP_RETHROW( excpt );
00532       return Capability(); // not reached
00533     }
00534 
00536   //
00537   //    METHOD NAME : CapFactory::encode
00538   //    METHOD TYPE : std::string
00539   //
00540   std::string CapFactory::encode( const Capability & cap_r ) const
00541   {
00542     return cap_r._pimpl->encode();
00543   }
00544 
00545   /******************************************************************
00546   **
00547   **    FUNCTION NAME : operator<<
00548   **    FUNCTION TYPE : std::ostream &
00549   */
00550   std::ostream & operator<<( std::ostream & str, const CapFactory & obj )
00551   {
00552     str << "CapFactory stats:" << endl;
00553 
00554     return for_each( _uset.begin(), _uset.end(), USetStatsCollect() ).dumpOn( str );
00555   }
00556 
00558 } // namespace zypp

Generated on Sat Sep 5 12:05:06 2009 for zypp by  doxygen 1.4.6