00001
00002
00003
00004
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
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
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 }
00123
00125 namespace zypp
00126 {
00127
00129
00130
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
00192 ZYPP_THROW( Exception("Unknow Operator NONE is not allowed in Capability") );
00193 return false;
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
00224 if ( name_r.empty() )
00225 {
00226
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
00246 if ( name_r.empty() )
00247 {
00248
00249 return capability::NullCap::instance();
00250 }
00251
00252 assertResKind( refers_r );
00253
00254
00255 if ( isFileSpec( name_r ) )
00256 return usetInsert
00257 ( new capability::FileCap( refers_r, name_r ) );
00258
00259
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
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
00291 return usetInsert
00292 ( new capability::VersionedCap( refers_r, name_r, op_r, edition_r ) );
00293 }
00294
00295
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
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
00324 return usetInsert
00325 ( new capability::HalCap( ResTraits<SystemResObject>::kind,
00326 what[1].str() ) );
00327 }
00328
00329 ZYPP_THROW( Exception("Unsupported kind of Hal Capability '" + name_r + "'") );
00330 return NULL;
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
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
00358 return usetInsert
00359 ( new capability::ModaliasCap( ResTraits<SystemResObject>::kind,
00360 what[1].str() ) );
00361 }
00362
00363 ZYPP_THROW( Exception("Unsupported kind of Modalias Capability'" + name_r + "'") );
00364 return NULL;
00365 }
00366 };
00368
00370
00372
00373
00374
00376
00378
00379
00380
00381
00382 CapFactory::CapFactory()
00383 {}
00384
00386
00387
00388
00389
00390 CapFactory::~CapFactory()
00391 {}
00392
00394
00395
00396
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
00417
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
00432 ZYPP_CAUGHT( excpt );
00433 DBG << "Trying named cap for: " << strval_r << endl;
00434
00435 return Capability( Impl::buildNamed( refers_r, strval_r ) );
00436 }
00437
00438
00439 return Capability ( Impl::buildVersioned( refers_r,
00440 what[1].str(), op, edition ) );
00441 }
00442
00443
00444 return Capability( Impl::buildNamed( refers_r, strval_r ) );
00445 }
00446 catch ( Exception & excpt )
00447 {
00448 ZYPP_RETHROW( excpt );
00449 return Capability();
00450 }
00451
00452
00454
00455
00456
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
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();
00479 }
00480
00482
00483
00484
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();
00506 }
00507
00509
00510
00511
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();
00522 }
00523
00525
00526
00527
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();
00538 }
00539
00541
00542
00543
00544
00545 std::string CapFactory::encode( const Capability & cap_r ) const
00546 {
00547 return cap_r._pimpl->encode();
00548 }
00549
00550
00551
00552
00553
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 }