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 "zypp/base/Logger.h"
00018 #include "zypp/base/Exception.h"
00019 #include "zypp/base/String.h"
00020 #include "zypp/base/Counter.h"
00021 
00022 #include "zypp/CapFactory.h"
00023 #include "zypp/capability/Capabilities.h"
00024 
00025 using std::endl;
00026 
00028 namespace
00029 { 
00030   using ::zypp::Resolvable;
00031   using ::zypp::capability::CapabilityImpl;
00032   using ::zypp::capability::CapImplOrder;
00033 
00035   typedef std::set<CapabilityImpl::Ptr,CapImplOrder> USet;
00036 
00043   USet _uset;
00044 
00054   CapabilityImpl::Ptr usetInsert( CapabilityImpl * allocated_r )
00055   {
00056     return *(_uset.insert( CapabilityImpl::Ptr(allocated_r) ).first);
00057   }
00058 
00062   struct USetStatsCollect : public std::unary_function<CapabilityImpl::constPtr, void>
00063   {
00064     typedef ::zypp::Counter<unsigned> Counter;
00065 
00066     Counter _caps;
00067     std::map<CapabilityImpl::Kind,Counter> _capKind;
00068     std::map<Resolvable::Kind,Counter>     _capRefers;
00069 
00070     void operator()( const CapabilityImpl::constPtr & cap_r )
00071     {
00072       //DBG << *cap_r << endl;
00073       ++_caps;
00074       ++(_capKind[cap_r->kind()]);
00075       ++(_capRefers[cap_r->refers()]);
00076     }
00077 
00078     std::ostream & dumpOn( std::ostream & str ) const
00079     {
00080       str << "  Capabilities total: " << _caps << endl;
00081       str << "  Capability kinds:" << endl;
00082       for ( std::map<CapabilityImpl::Kind,Counter>::const_iterator it = _capKind.begin();
00083             it != _capKind.end(); ++it )
00084         {
00085           str << "    " << it->first << '\t' << it->second << endl;
00086         }
00087       str << "  Capability refers:" << endl;
00088       for ( std::map<Resolvable::Kind,Counter>::const_iterator it = _capRefers.begin();
00089             it != _capRefers.end(); ++it )
00090         {
00091           str << "    " << it->first << '\t' << it->second << endl;
00092         }
00093       return str;
00094     }
00095   };
00096 
00098 } // namespace
00100 
00102 namespace zypp
00103 { 
00104 
00106   //
00107   //    CLASS NAME : CapFactoryImpl
00108   //
00126   struct CapFactory::Impl
00127   {
00129     static void assertResKind( const Resolvable::Kind & refers_r )
00130     {
00131       if ( refers_r == Resolvable::Kind() )
00132         ZYPP_THROW( Exception("Missing or empty  Resolvable::Kind in Capability") );
00133     }
00134 
00144     static bool isEditionSpec( Rel op_r, const Edition & edition_r )
00145     {
00146       switch ( op_r.inSwitch() )
00147         {
00148         case Rel::ANY_e:
00149           if ( edition_r != Edition::noedition )
00150             WAR << "Operator " << op_r << " causes Edition "
00151             << edition_r << " to be ignored." << endl;
00152           return false;
00153           break;
00154 
00155         case Rel::NONE_e:
00156           ZYPP_THROW( Exception("Operator NONE is not allowed in Capability") );
00157           break;
00158 
00159         case Rel::EQ_e:
00160         case Rel::NE_e:
00161         case Rel::LT_e:
00162         case Rel::LE_e:
00163         case Rel::GT_e:
00164         case Rel::GE_e:
00165           return true;
00166           break;
00167         }
00168       // SHOULD NOT GET HERE
00169       ZYPP_THROW( Exception("Unknow Operator NONE is not allowed in Capability") );
00170       return false; // not reached
00171     }
00172 
00174     static bool isFileSpec( const std::string & name_r )
00175     {
00176       return *name_r.c_str() == '/';
00177     }
00178 
00180     static bool isSplitSpec( const std::string & name_r )
00181     {
00182       return name_r.find( ":/" ) != std::string::npos;
00183     }
00184 
00186     static bool isHalSpec( const std::string & name_r )
00187     {
00188       return name_r.substr(0,4) == "hal(";
00189     }
00190 
00192     static bool isModaliasSpec( const std::string & name_r )
00193     {
00194       return name_r.substr(0,9) == "modalias(";
00195     }
00196 
00197     static CapabilityImpl::Ptr buildFile( const Resolvable::Kind & refers_r,
00198                                           const std::string & name_r )
00199     {
00200       // NullCap check first:
00201       if ( name_r.empty() )
00202         {
00203           // Singleton, so no need to put it into _uset !?
00204           return capability::NullCap::instance();
00205         }
00206 
00207       assertResKind( refers_r );
00208 
00209       return usetInsert
00210       ( new capability::FileCap( refers_r, name_r ) );
00211     }
00212 
00219     static CapabilityImpl::Ptr buildNamed( const Resolvable::Kind & refers_r,
00220                                            const std::string & name_r )
00221     {
00222       // NullCap check first:
00223       if ( name_r.empty() )
00224         {
00225           // Singleton, so no need to put it into _uset !?
00226           return capability::NullCap::instance();
00227         }
00228 
00229       assertResKind( refers_r );
00230 
00231       // file:    /absolute/path
00232       if ( isFileSpec( name_r ) )
00233         return usetInsert
00234         ( new capability::FileCap( refers_r, name_r ) );
00235 
00236       //split:   name:/absolute/path
00237       static const str::regex  rx( "([^/]*):(/.*)" );
00238       str::smatch what;
00239       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
00240         {
00241           return usetInsert
00242           ( new capability::SplitCap( refers_r, what[1].str(), what[2].str() ) );
00243         }
00244 
00245       //name:    name
00246       return usetInsert
00247       ( new capability::NamedCap( refers_r, name_r ) );
00248     }
00249 
00258     static CapabilityImpl::Ptr buildVersioned( const Resolvable::Kind & refers_r,
00259                                                const std::string & name_r,
00260                                                Rel op_r,
00261                                                const Edition & edition_r )
00262     {
00263       if ( Impl::isEditionSpec( op_r, edition_r ) )
00264         {
00265           assertResKind( refers_r );
00266 
00267           // build a VersionedCap
00268           return usetInsert
00269           ( new capability::VersionedCap( refers_r, name_r, op_r, edition_r ) );
00270         }
00271       //else
00272       // build a NamedCap
00273 
00274       return buildNamed( refers_r, name_r );
00275     }
00276 
00285     static CapabilityImpl::Ptr buildHal( const Resolvable::Kind & refers_r,
00286                                          const std::string & name_r,
00287                                          Rel op_r = Rel::ANY,
00288                                          const std::string & value_r = std::string() )
00289     {
00290       if ( op_r != Rel::ANY )
00291         {
00292           ZYPP_THROW( Exception("Unsupported kind of Hal Capability '" + op_r.asString() + "'") );
00293         }
00294 
00295       //split:   hal(name) [op string]
00296       static const str::regex  rx( "hal\\(([^)]*)\\)" );
00297       str::smatch what;
00298       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
00299         {
00300           // Hal always refers to 'System' kind of Resolvable.
00301           return usetInsert
00302           ( new capability::HalCap( ResTraits<SystemResObject>::kind,
00303                                     what[1].str() ) );
00304         }
00305       // otherwise
00306       ZYPP_THROW( Exception("Unsupported kind of Hal Capability '" + name_r + "'") );
00307       return NULL; // make gcc happy
00308     }
00309 
00310 
00319     static CapabilityImpl::Ptr buildModalias( const Resolvable::Kind & refers_r,
00320                                               const std::string & name_r,
00321                                               Rel op_r = Rel::ANY,
00322                                               const std::string & value_r = std::string() )
00323     {
00324       if ( op_r != Rel::ANY )
00325         {
00326           ZYPP_THROW( Exception("Unsupported kind of Modalias Capability  '" + op_r.asString() + "'") );
00327         }
00328 
00329       //split:   modalias(name) [op string]
00330       static const str::regex  rx( "modalias\\(([^)]*)\\)" );
00331       str::smatch what;
00332       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
00333         {
00334           // Modalias always refers to 'System' kind of Resolvable.
00335           return usetInsert
00336           ( new capability::ModaliasCap( ResTraits<SystemResObject>::kind,
00337                                          what[1].str() ) );
00338         }
00339       // otherwise
00340       ZYPP_THROW( Exception("Unsupported kind of Modalias Capability'" + name_r + "'") );
00341       return NULL; // make gcc happy
00342     }
00343   };
00345 
00347 
00349   //
00350   //    CLASS NAME : CapFactory
00351   //
00353 
00355   //
00356   //    METHOD NAME : CapFactory::CapFactory
00357   //    METHOD TYPE : Ctor
00358   //
00359   CapFactory::CapFactory()
00360   {}
00361 
00363   //
00364   //    METHOD NAME : CapFactory::~CapFactory
00365   //    METHOD TYPE : Dtor
00366   //
00367   CapFactory::~CapFactory()
00368   {}
00369 
00371   //
00372   //    METHOD NAME : CapFactory::parse
00373   //    METHOD TYPE : Capability
00374   //
00375   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
00376                                 const std::string & strval_r ) const
00377 
00378   try
00379     {
00380       if ( Impl::isHalSpec( strval_r ) )
00381         {
00382           return Capability( Impl::buildHal( refers_r, strval_r ) );
00383         }
00384       if ( Impl::isModaliasSpec( strval_r ) )
00385         {
00386           return Capability( Impl::buildModalias( refers_r, strval_r ) );
00387         }
00388       if ( Impl::isFileSpec( strval_r ) )
00389         {
00390           return Capability( Impl::buildFile( refers_r, strval_r ) );
00391         }
00392 
00393       // strval_r has at least two words which could make 'op edition'?
00394       // improve regex!
00395       static const str::regex  rx( "(.*[^ \t])([ \t]+)([^ \t]+)([ \t]+)([^ \t]+)" );
00396       str::smatch what;
00397       if( str::regex_match( strval_r.begin(), strval_r.end(),what, rx ) )
00398         {
00399           Rel op;
00400           Edition edition;
00401           try
00402             {
00403               op = Rel(what[3].str());
00404               edition = Edition(what[5].str());
00405             }
00406           catch ( Exception & excpt )
00407             {
00408               // So they don't make valid 'op edition'
00409               ZYPP_CAUGHT( excpt );
00410               DBG << "Trying named cap for: " << strval_r << endl;
00411               // See whether it makes a named cap.
00412               return Capability( Impl::buildNamed( refers_r, strval_r ) );
00413             }
00414 
00415           // Valid 'op edition'
00416           return Capability ( Impl::buildVersioned( refers_r,
00417                                                     what[1].str(), op, edition ) );
00418         }
00419       //else
00420       // not a VersionedCap
00421       return Capability( Impl::buildNamed( refers_r, strval_r ) );
00422     }
00423   catch ( Exception & excpt )
00424     {
00425       ZYPP_RETHROW( excpt );
00426       return Capability(); // not reached
00427     }
00428 
00429 
00431   //
00432   //    METHOD NAME : CapFactory::parse
00433   //    METHOD TYPE : Capability
00434   //
00435   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
00436                                 const std::string & name_r,
00437                                 const std::string & op_r,
00438                                 const std::string & edition_r ) const
00439   try
00440     {
00441       if ( Impl::isHalSpec( name_r ) )
00442         {
00443           return Capability( Impl::buildHal( refers_r, name_r, Rel(op_r), edition_r ) );
00444         }
00445       if ( Impl::isModaliasSpec( name_r ) )
00446         {
00447           return Capability( Impl::buildModalias( refers_r, name_r, Rel(op_r), edition_r ) );
00448         }
00449       // Try creating Rel and Edition, then parse
00450       return parse( refers_r, name_r, Rel(op_r), Edition(edition_r) );
00451     }
00452   catch ( Exception & excpt )
00453     {
00454       ZYPP_RETHROW( excpt );
00455       return Capability(); // not reached
00456     }
00457 
00459   //
00460   //    METHOD NAME : CapFactory::parse
00461   //    METHOD TYPE : Capability
00462   //
00463   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
00464                                 const std::string & name_r,
00465                                 Rel op_r,
00466                                 const Edition & edition_r ) const
00467   try
00468     {
00469       if ( Impl::isHalSpec( name_r ) )
00470         {
00471           return Capability( Impl::buildHal( refers_r, name_r, op_r, edition_r.asString() ) );
00472         }
00473       if ( Impl::isModaliasSpec( name_r ) )
00474         {
00475           return Capability( Impl::buildModalias( refers_r, name_r, op_r, edition_r.asString() ) );
00476         }
00477       return Capability( Impl::buildVersioned( refers_r, name_r, op_r, edition_r ) );
00478     }
00479   catch ( Exception & excpt )
00480     {
00481       ZYPP_RETHROW( excpt );
00482       return Capability(); // not reached
00483     }
00484 
00486   //
00487   //    METHOD NAME : CapFactory::halEvalCap
00488   //    METHOD TYPE : Capability
00489   //
00490   Capability CapFactory::halEvalCap() const
00491   try
00492     {
00493       return Capability( Impl::buildHal( Resolvable::Kind(), "hal()" ) );
00494     }
00495   catch ( Exception & excpt )
00496     {
00497       ZYPP_RETHROW( excpt );
00498       return Capability(); // not reached
00499     }
00500 
00502   //
00503   //    METHOD NAME : CapFactory::modaliasEvalCap
00504   //    METHOD TYPE : Capability
00505   //
00506   Capability CapFactory::modaliasEvalCap() const
00507   try
00508     {
00509       return Capability( Impl::buildModalias( Resolvable::Kind(), "modalias()" ) );
00510     }
00511   catch ( Exception & excpt )
00512     {
00513       ZYPP_RETHROW( excpt );
00514       return Capability(); // not reached
00515     }
00516 
00518   //
00519   //    METHOD NAME : CapFactory::encode
00520   //    METHOD TYPE : std::string
00521   //
00522   std::string CapFactory::encode( const Capability & cap_r ) const
00523   {
00524     return cap_r._pimpl->encode();
00525   }
00526 
00527   /******************************************************************
00528   **
00529   **    FUNCTION NAME : operator<<
00530   **    FUNCTION TYPE : std::ostream &
00531   */
00532   std::ostream & operator<<( std::ostream & str, const CapFactory & obj )
00533   {
00534     str << "CapFactory stats:" << endl;
00535 
00536     return for_each( _uset.begin(), _uset.end(), USetStatsCollect() ).dumpOn( str );
00537   }
00538 
00540 } // namespace zypp

Generated on Thu Jul 6 00:07:20 2006 for zypp by  doxygen 1.4.6