1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/CapFactory.cc
17 #include <ext/hash_set>
18 #include <ext/hash_fun.h>
20 #include "zypp/base/Logger.h"
21 #include "zypp/base/Exception.h"
22 #include "zypp/base/String.h"
23 #include "zypp/base/Counter.h"
25 #include "zypp/CapFactory.h"
26 #include "zypp/capability/Capabilities.h"
30 ///////////////////////////////////////////////////////////////////
32 { /////////////////////////////////////////////////////////////////
33 using ::zypp::Resolvable;
34 using ::zypp::capability::CapabilityImpl;
35 using ::zypp::capability::CapImplOrder;
39 size_t operator() ( const CapabilityImpl::Ptr & p ) const
41 return __gnu_cxx::hash<const char*>()( p->encode().c_str() );
45 struct CapImplHashEqual
47 bool operator() ( const CapabilityImpl::Ptr & lhs, const CapabilityImpl::Ptr & rhs ) const
49 return ( lhs->encode() == rhs->encode()
50 && lhs->kind() == rhs->kind()
51 && lhs->refers() == rhs->refers() );
55 /** Set of unique CapabilityImpl. */
56 //typedef std::set<CapabilityImpl::Ptr,CapImplOrder> USet;
57 typedef __gnu_cxx::hash_set<CapabilityImpl::Ptr, CapImplHashFun, CapImplHashEqual> USet;
60 /** Set to unify created capabilities.
62 * This is to unify capabilities. Each CapabilityImpl created
63 * by CapFactory, must be inserted into _uset, and the returned
64 * CapabilityImpl::Ptr has to be uset to create the Capability.
68 /** Each CapabilityImpl created in CapFactory \b must be wrapped.
70 * Immediately wrap \a allocated_r, and unified by inserting it into
71 * \c _uset. Each CapabilityImpl created by CapFactory, \b must be
72 * inserted into _uset, by calling usetInsert.
74 * \return CapabilityImpl_Ptr referencing \a allocated_r (or an
75 * eqal representation, allocated is deleted then).
77 CapabilityImpl::Ptr usetInsert( CapabilityImpl * allocated_r )
79 return *(_uset.insert( CapabilityImpl::Ptr(allocated_r) ).first);
82 /** Collect USet statistics.
85 struct USetStatsCollect : public std::unary_function<CapabilityImpl::constPtr, void>
87 typedef ::zypp::Counter<unsigned> Counter;
90 std::map<CapabilityImpl::Kind,Counter> _capKind;
91 std::map<Resolvable::Kind,Counter> _capRefers;
93 void operator()( const CapabilityImpl::constPtr & cap_r )
95 //DBG << *cap_r << endl;
97 ++(_capKind[cap_r->kind()]);
98 ++(_capRefers[cap_r->refers()]);
101 std::ostream & dumpOn( std::ostream & str ) const
103 str << " Capabilities total: " << _caps << endl;
104 str << " Capability kinds:" << endl;
105 for ( std::map<CapabilityImpl::Kind,Counter>::const_iterator it = _capKind.begin();
106 it != _capKind.end(); ++it )
108 str << " " << it->first << '\t' << it->second << endl;
110 str << " Capability refers:" << endl;
111 for ( std::map<Resolvable::Kind,Counter>::const_iterator it = _capRefers.begin();
112 it != _capRefers.end(); ++it )
114 str << " " << it->first << '\t' << it->second << endl;
120 /////////////////////////////////////////////////////////////////
122 ///////////////////////////////////////////////////////////////////
124 ///////////////////////////////////////////////////////////////////
126 { /////////////////////////////////////////////////////////////////
128 ///////////////////////////////////////////////////////////////////
130 // CLASS NAME : CapFactoryImpl
132 /** CapFactory implementation.
134 * Provides various functions doing checks and log and \c throw.
135 * CapFactory::parse usually combines them, and if nothing fails,
136 * finaly builds the Capability.
138 * \attention Each CapabilityImpl created by CapFactory, \b must
139 * be inserted into ::_uset, by calling ::usetInsert, \b before
140 * the Capability is created.
142 * \li \c file: /absolute/path
143 * \li \c split: name:/absolute/path
145 * \li \c vers: name op edition
146 * \li \c hal: hal(string)
147 * \li \c modalias: modalias(string)
149 struct CapFactory::Impl
151 /** Assert a valid Resolvable::Kind. */
152 static void assertResKind( const Resolvable::Kind & refers_r )
154 if ( refers_r == Resolvable::Kind() )
155 ZYPP_THROW( Exception("Missing or empty Resolvable::Kind in Capability") );
158 /** Check whether \a op_r and \a edition_r make a valid edition spec.
160 * Rel::NONE is not usefull thus forbidden. Rel::ANY can be ignored,
161 * so no VersionedCap is needed for this. Everything else requires
164 * \return Whether to build a VersionedCap (i.e. \a op_r
167 static bool isEditionSpec( Rel op_r, const Edition & edition_r )
169 switch ( op_r.inSwitch() )
172 if ( edition_r != Edition::noedition )
173 WAR << "Operator " << op_r << " causes Edition "
174 << edition_r << " to be ignored." << endl;
179 ZYPP_THROW( Exception("Operator NONE is not allowed in Capability") );
191 // SHOULD NOT GET HERE
192 ZYPP_THROW( Exception("Unknow Operator NONE is not allowed in Capability") );
193 return false; // not reached
196 /** Test for a FileCap. \a name_r starts with \c "/". */
197 static bool isFileSpec( const std::string & name_r )
199 return *name_r.c_str() == '/';
202 /** Test for a SplitCap. \a name_r constains \c ":/". */
203 static bool isSplitSpec( const std::string & name_r )
205 return name_r.find( ":/" ) != std::string::npos;
208 /** Test for a HalCap. \a name_r starts with "hal(". */
209 static bool isHalSpec( const std::string & name_r )
211 return name_r.substr(0,4) == "hal(";
214 /** Test for a ModaliasCap. \a name_r starts with "modalias(". */
215 static bool isModaliasSpec( const std::string & name_r )
217 return name_r.substr(0,9) == "modalias(";
220 static CapabilityImpl::Ptr buildFile( const Resolvable::Kind & refers_r,
221 const std::string & name_r )
223 // NullCap check first:
224 if ( name_r.empty() )
226 // Singleton, so no need to put it into _uset !?
227 return capability::NullCap::instance();
230 assertResKind( refers_r );
233 ( new capability::FileCap( refers_r, name_r ) );
236 /** Try to build a non versioned cap from \a name_r .
238 * The CapabilityImpl is built here and inserted into _uset.
239 * The final Capability must be created by CapFactory, as it
240 * is a friend of Capability. Here we can't access the ctor.
242 static CapabilityImpl::Ptr buildNamed( const Resolvable::Kind & refers_r,
243 const std::string & name_r )
245 // NullCap check first:
246 if ( name_r.empty() )
248 // Singleton, so no need to put it into _uset !?
249 return capability::NullCap::instance();
252 assertResKind( refers_r );
254 // file: /absolute/path
255 if ( isFileSpec( name_r ) )
257 ( new capability::FileCap( refers_r, name_r ) );
259 //split: name:/absolute/path
260 static const str::regex rx( "([^/]*):(/.*)" );
262 if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
265 ( new capability::SplitCap( refers_r, what[1].str(), what[2].str() ) );
270 ( new capability::NamedCap( refers_r, name_r ) );
273 /** Try to build a versioned cap from \a name_r .
275 * The CapabilityImpl is built here and inserted into _uset.
276 * The final Capability must be created by CapFactory, as it
277 * is a friend of Capability. Here we can't access the ctor.
279 * \todo Quick check for name not being filename or split.
281 static CapabilityImpl::Ptr buildVersioned( const Resolvable::Kind & refers_r,
282 const std::string & name_r,
284 const Edition & edition_r )
286 if ( Impl::isEditionSpec( op_r, edition_r ) )
288 assertResKind( refers_r );
290 // build a VersionedCap
292 ( new capability::VersionedCap( refers_r, name_r, op_r, edition_r ) );
297 return buildNamed( refers_r, name_r );
300 /** Try to build a hal cap from \a name_r .
302 * The CapabilityImpl is built here and inserted into _uset.
303 * The final Capability must be created by CapFactory, as it
304 * is a friend of Capability. Here we can't access the ctor.
306 * \todo Fix incaccuracy.
308 static CapabilityImpl::Ptr buildHal( const Resolvable::Kind & refers_r,
309 const std::string & name_r,
311 const std::string & value_r = std::string() )
313 if ( op_r != Rel::ANY )
315 ZYPP_THROW( Exception("Unsupported kind of Hal Capability '" + op_r.asString() + "'") );
318 //split: hal(name) [op string]
319 static const str::regex rx( "hal\\(([^)]*)\\)" );
321 if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
323 // Hal always refers to 'System' kind of Resolvable.
325 ( new capability::HalCap( ResTraits<SystemResObject>::kind,
329 ZYPP_THROW( Exception("Unsupported kind of Hal Capability '" + name_r + "'") );
330 return NULL; // make gcc happy
334 /** Try to build a modalias cap from \a name_r .
336 * The CapabilityImpl is built here and inserted into _uset.
337 * The final Capability must be created by CapFactory, as it
338 * is a friend of Capability. Here we can't access the ctor.
340 * \todo Fix incaccuracy.
342 static CapabilityImpl::Ptr buildModalias( const Resolvable::Kind & refers_r,
343 const std::string & name_r,
345 const std::string & value_r = std::string() )
347 if ( op_r != Rel::ANY )
349 ZYPP_THROW( Exception("Unsupported kind of Modalias Capability '" + op_r.asString() + "'") );
352 //split: modalias(name) [op string]
353 static const str::regex rx( "modalias\\(([^)]*)\\)" );
355 if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
357 // Modalias always refers to 'System' kind of Resolvable.
359 ( new capability::ModaliasCap( ResTraits<SystemResObject>::kind,
363 ZYPP_THROW( Exception("Unsupported kind of Modalias Capability'" + name_r + "'") );
364 return NULL; // make gcc happy
367 ///////////////////////////////////////////////////////////////////
369 ///////////////////////////////////////////////////////////////////
371 ///////////////////////////////////////////////////////////////////
373 // CLASS NAME : CapFactory
375 ///////////////////////////////////////////////////////////////////
377 ///////////////////////////////////////////////////////////////////
379 // METHOD NAME : CapFactory::CapFactory
380 // METHOD TYPE : Ctor
382 CapFactory::CapFactory()
385 ///////////////////////////////////////////////////////////////////
387 // METHOD NAME : CapFactory::~CapFactory
388 // METHOD TYPE : Dtor
390 CapFactory::~CapFactory()
393 ///////////////////////////////////////////////////////////////////
395 // METHOD NAME : CapFactory::parse
396 // METHOD TYPE : Capability
398 Capability CapFactory::parse( const Resolvable::Kind & refers_r,
399 const std::string & strval_r ) const
403 if ( Impl::isHalSpec( strval_r ) )
405 return Capability( Impl::buildHal( refers_r, strval_r ) );
407 if ( Impl::isModaliasSpec( strval_r ) )
409 return Capability( Impl::buildModalias( refers_r, strval_r ) );
411 if ( Impl::isFileSpec( strval_r ) )
413 return Capability( Impl::buildFile( refers_r, strval_r ) );
416 // strval_r has at least two words which could make 'op edition'?
418 static const str::regex rx( "(.*[^ \t])([ \t]+)([^ \t]+)([ \t]+)([^ \t]+)" );
420 if( str::regex_match( strval_r.begin(), strval_r.end(),what, rx ) )
426 op = Rel(what[3].str());
427 edition = Edition(what[5].str());
429 catch ( Exception & excpt )
431 // So they don't make valid 'op edition'
432 ZYPP_CAUGHT( excpt );
433 DBG << "Trying named cap for: " << strval_r << endl;
434 // See whether it makes a named cap.
435 return Capability( Impl::buildNamed( refers_r, strval_r ) );
438 // Valid 'op edition'
439 return Capability ( Impl::buildVersioned( refers_r,
440 what[1].str(), op, edition ) );
443 // not a VersionedCap
444 return Capability( Impl::buildNamed( refers_r, strval_r ) );
446 catch ( Exception & excpt )
448 ZYPP_RETHROW( excpt );
449 return Capability(); // not reached
453 ///////////////////////////////////////////////////////////////////
455 // METHOD NAME : CapFactory::parse
456 // METHOD TYPE : Capability
458 Capability CapFactory::parse( const Resolvable::Kind & refers_r,
459 const std::string & name_r,
460 const std::string & op_r,
461 const std::string & edition_r ) const
464 if ( Impl::isHalSpec( name_r ) )
466 return Capability( Impl::buildHal( refers_r, name_r, Rel(op_r), edition_r ) );
468 if ( Impl::isModaliasSpec( name_r ) )
470 return Capability( Impl::buildModalias( refers_r, name_r, Rel(op_r), edition_r ) );
472 // Try creating Rel and Edition, then parse
473 return parse( refers_r, name_r, Rel(op_r), Edition(edition_r) );
475 catch ( Exception & excpt )
477 ZYPP_RETHROW( excpt );
478 return Capability(); // not reached
481 ///////////////////////////////////////////////////////////////////
483 // METHOD NAME : CapFactory::parse
484 // METHOD TYPE : Capability
486 Capability CapFactory::parse( const Resolvable::Kind & refers_r,
487 const std::string & name_r,
489 const Edition & edition_r ) const
492 if ( Impl::isHalSpec( name_r ) )
494 return Capability( Impl::buildHal( refers_r, name_r, op_r, edition_r.asString() ) );
496 if ( Impl::isModaliasSpec( name_r ) )
498 return Capability( Impl::buildModalias( refers_r, name_r, op_r, edition_r.asString() ) );
500 return Capability( Impl::buildVersioned( refers_r, name_r, op_r, edition_r ) );
502 catch ( Exception & excpt )
504 ZYPP_RETHROW( excpt );
505 return Capability(); // not reached
508 ///////////////////////////////////////////////////////////////////
510 // METHOD NAME : CapFactory::halEvalCap
511 // METHOD TYPE : Capability
513 Capability CapFactory::halEvalCap() const
516 return Capability( Impl::buildHal( Resolvable::Kind(), "hal()" ) );
518 catch ( Exception & excpt )
520 ZYPP_RETHROW( excpt );
521 return Capability(); // not reached
524 ///////////////////////////////////////////////////////////////////
526 // METHOD NAME : CapFactory::modaliasEvalCap
527 // METHOD TYPE : Capability
529 Capability CapFactory::modaliasEvalCap() const
532 return Capability( Impl::buildModalias( Resolvable::Kind(), "modalias()" ) );
534 catch ( Exception & excpt )
536 ZYPP_RETHROW( excpt );
537 return Capability(); // not reached
540 ///////////////////////////////////////////////////////////////////
542 // METHOD NAME : CapFactory::encode
543 // METHOD TYPE : std::string
545 std::string CapFactory::encode( const Capability & cap_r ) const
547 return cap_r._pimpl->encode();
550 /******************************************************************
552 ** FUNCTION NAME : operator<<
553 ** FUNCTION TYPE : std::ostream &
555 std::ostream & operator<<( std::ostream & str, const CapFactory & obj )
557 str << "CapFactory stats:" << endl;
559 return for_each( _uset.begin(), _uset.end(), USetStatsCollect() ).dumpOn( str );
562 /////////////////////////////////////////////////////////////////
564 ///////////////////////////////////////////////////////////////////