64eb6f1f0d5ddbe6540ed3ede5f25a1451798515
[platform/upstream/libzypp.git] / zypp / CapFactory.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/CapFactory.cc
10  *
11 */
12 #include <iostream>
13 #include <functional>
14 #include <set>
15
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/Exception.h"
18 #include "zypp/base/String.h"
19
20 #include "zypp/CapFactory.h"
21 #include "zypp/capability/Capabilities.h"
22
23 using namespace std;
24
25 ///////////////////////////////////////////////////////////////////
26 namespace
27 { /////////////////////////////////////////////////////////////////
28
29   using ::zypp::capability::CapabilityImpl;
30
31   /** \ref USet order.
32    * \todo check set ordering to assert no dups
33   */
34   struct USetOrder : public std::binary_function<CapabilityImpl::Ptr, CapabilityImpl::Ptr, bool>
35   {
36     /** */
37     bool operator()( const CapabilityImpl::Ptr & lhs,
38                      const CapabilityImpl::Ptr & rhs ) const
39     { return lhs->asString() < rhs->asString(); }
40   };
41
42   /** */
43   typedef std::set<CapabilityImpl::Ptr,USetOrder> USet;
44
45   /** Set to unify created capabilities. */
46   USet _uset;
47
48   /** Immediately wrap \a allocated_r and unify by inserting
49    * it into \c _uset.
50    * \return CapabilityImpl_Ptr referencing \a allocated_r (or an
51    * eqal representation, allocated is deleted then).
52   */
53   CapabilityImpl::Ptr usetInsert( CapabilityImpl * allocated_r )
54   {
55     return *(_uset.insert( CapabilityImpl::Ptr(allocated_r) ).first);
56   }
57
58   /////////////////////////////////////////////////////////////////
59 } // namespace
60 ///////////////////////////////////////////////////////////////////
61
62 ///////////////////////////////////////////////////////////////////
63 namespace zypp
64 { /////////////////////////////////////////////////////////////////
65
66   ///////////////////////////////////////////////////////////////////
67   //
68   //    CLASS NAME : CapFactoryImpl
69   //
70   /** CapFactory implementation.
71    *
72    * Provides various functions doing checks and log and \c throw.
73    * CapFactory::parse usually combines them, and if nothing fails,
74    * finaly builds the Capability.
75    *
76    * \li \c file:    /absolute/path
77    * \li \c split:   name:/absolute/path
78    * \li \c name:    name
79    * \li \c vers:    name op edition
80   */
81   struct CapFactory::Impl
82   {
83     /** Assert a valid Resolvable::Kind. */
84     static void assertResKind( const Resolvable::Kind & refers_r )
85     {
86       if ( refers_r == Resolvable::Kind() )
87         ZYPP_THROW( "Missing or empty  Resolvable::Kind in Capability." );
88     }
89
90     /** Check whether \a op_r and \a edition_r make a valid edition spec.
91      *
92      * Rel::NONE is not usefull thus forbidden. Rel::ANY can be ignored,
93      * so no VersionedCap is needed for this. Everything else requires
94      * a VersionedCap.
95      *
96      * \return Whether to build a VersionedCap (i.e. \a op_r
97      * is not Rel::ANY.
98     */
99     static bool isEditionSpec( Rel op_r, const Edition & edition_r )
100     {
101       switch ( op_r.inSwitch() )
102         {
103         case Rel::ANY_e:
104           if ( edition_r != Edition::noedition )
105             WAR << "Operator " << op_r << " causes Edition "
106             << edition_r << " to be ignored." << endl;
107           return false;
108           break;
109
110         case Rel::NONE_e:
111           ZYPP_THROW( "Operator NONE is not allowed in Capability " );
112           break;
113
114         case Rel::EQ_e:
115         case Rel::NE_e:
116         case Rel::LT_e:
117         case Rel::LE_e:
118         case Rel::GT_e:
119         case Rel::GE_e:
120           return true;
121           break;
122         }
123       // SHOULD NOT GET HERE
124       ZYPP_THROW( "Unknow Operator NONE is not allowed in Capability " );
125       return false; // not reached
126     }
127
128     /** Test for a FileCap. \a name_r starts with \c "/". */
129     static bool isFileSpec( const std::string & name_r )
130     {
131       return *name_r.c_str() == '/';
132     }
133
134     /** Test for a SplitCap. \a name_r constains \c ":/". */
135     static bool isSplitSpec( const std::string & name_r )
136     {
137       return name_r.find( ":/" ) != std::string::npos;
138     }
139
140     /** Try to build a non versioned cap from \a name_r .
141      *
142      * The CapabilityImpl is built here and inserted into _uset.
143      * The final Capability must be created by CapFactory, as it
144      * is a friend of Capability. Here we can't access the ctor.
145     */
146     static CapabilityImpl::Ptr buildNamed( const Resolvable::Kind & refers_r,
147                                            const std::string & name_r )
148     {
149       assertResKind( refers_r );
150
151       // file:    /absolute/path
152       if ( isFileSpec( name_r ) )
153         return usetInsert
154         ( new capability::FileCap( refers_r, name_r ) );
155
156       //split:   name:/absolute/path
157       str::regex  rx( "([^/]*):(/.*)" );
158       str::smatch what;
159       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
160         {
161           return usetInsert
162           ( new capability::SplitCap( refers_r, what[1].str(), what[2].str() ) );
163         }
164
165       //name:    name
166       return usetInsert
167       ( new capability::NamedCap( refers_r, name_r ) );
168     }
169
170     /** Try to build a versioned cap from \a name_r .
171      *
172      * The CapabilityImpl is built here and inserted into _uset.
173      * The final Capability must be created by CapFactory, as it
174      * is a friend of Capability. Here we can't access the ctor.
175      *
176      * \todo Quick check for name not being filename or split.
177     */
178     static CapabilityImpl::Ptr buildVersioned( const Resolvable::Kind & refers_r,
179                                                const std::string & name_r,
180                                                Rel op_r,
181                                                const Edition & edition_r )
182     {
183       if ( Impl::isEditionSpec( op_r, edition_r ) )
184         {
185           assertResKind( refers_r );
186
187           // build a VersionedCap
188           return usetInsert
189           ( new capability::VersionedCap( refers_r, name_r, op_r, edition_r ) );
190         }
191       //else
192       // build a NamedCap
193
194       return buildNamed( refers_r, name_r );
195     }
196   };
197   ///////////////////////////////////////////////////////////////////
198
199   ///////////////////////////////////////////////////////////////////
200
201   ///////////////////////////////////////////////////////////////////
202   //
203   //    CLASS NAME : CapFactory
204   //
205   ///////////////////////////////////////////////////////////////////
206
207   ///////////////////////////////////////////////////////////////////
208   //
209   //    METHOD NAME : CapFactory::CapFactory
210   //    METHOD TYPE : Ctor
211   //
212   CapFactory::CapFactory()
213   {}
214
215   ///////////////////////////////////////////////////////////////////
216   //
217   //    METHOD NAME : CapFactory::~CapFactory
218   //    METHOD TYPE : Dtor
219   //
220   CapFactory::~CapFactory()
221   {}
222
223 #if 0
224   ///////////////////////////////////////////////////////////////////
225   //
226   //    METHOD NAME : CapFactory::parse
227   //    METHOD TYPE : Capability
228   //
229   Capability CapFactory::parse( const std::string & strval_r ) const
230   {
231     return parse( strval_r, Resolvable::Kind() );
232   }
233 #endif
234
235   ///////////////////////////////////////////////////////////////////
236   //
237   //    METHOD NAME : CapFactory::parse
238   //    METHOD TYPE : Capability
239   //
240   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
241                                 const std::string & strval_r ) const
242
243   try
244     {
245       // strval_r has at least two words which could make 'op edition'?
246       str::regex  rx( "(.*[^ \t])([ \t]+)([^ \t]+)([ \t]+)([^ \t]+)" );
247       str::smatch what;
248       if( str::regex_match( strval_r.begin(), strval_r.end(),what, rx ) )
249         {
250           Rel op;
251           Edition edition;
252           try
253             {
254               op = Rel(what[3].str());
255               edition = Edition(what[5].str());
256             }
257           catch ( Exception & excpt )
258             {
259               // So they don't make valid 'op edition'
260               ZYPP_CAUGHT( excpt );
261               // See whether it makes a named cap.
262               return Capability( Impl::buildNamed( refers_r, strval_r ) );
263             }
264
265           // Valid 'op edition'
266           return Capability ( Impl::buildVersioned( refers_r,
267                                                     what[1].str(), op, edition ) );
268         }
269       //else
270       // not a VersionedCap
271
272       return Capability( Impl::buildNamed( refers_r, strval_r ) );
273     }
274   catch ( Exception & excpt )
275     {
276       ZYPP_RETHROW( excpt );
277       return Capability(); // not reached
278     }
279
280
281   ///////////////////////////////////////////////////////////////////
282   //
283   //    METHOD NAME : CapFactory::parse
284   //    METHOD TYPE : Capability
285   //
286   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
287                                 const std::string & name_r,
288                                 const std::string & op_r,
289                                 const std::string & edition_r ) const
290   try
291     {
292       // Try creating Rel and Edition, then parse
293       return parse( refers_r, name_r, Rel(op_r), Edition(edition_r) );
294     }
295   catch ( Exception & excpt )
296     {
297       ZYPP_RETHROW( excpt );
298       return Capability(); // not reached
299     }
300
301   ///////////////////////////////////////////////////////////////////
302   //
303   //    METHOD NAME : CapFactory::parse
304   //    METHOD TYPE : Capability
305   //
306   Capability CapFactory::parse( const Resolvable::Kind & refers_r,
307                                 const std::string & name_r,
308                                 Rel op_r,
309                                 const Edition & edition_r ) const
310   try
311     {
312       return Capability
313       ( Impl::buildVersioned( refers_r, name_r, op_r, edition_r ) );
314     }
315   catch ( Exception & excpt )
316     {
317       ZYPP_RETHROW( excpt );
318       return Capability(); // not reached
319     }
320
321   /******************************************************************
322   **
323   **    FUNCTION NAME : operator<<
324   **    FUNCTION TYPE : std::ostream &
325   */
326   std::ostream & operator<<( std::ostream & str, const CapFactory & obj )
327   {
328     return str << "No CapFactory stats implemented";
329   }
330
331   /////////////////////////////////////////////////////////////////
332 } // namespace zypp
333 ///////////////////////////////////////////////////////////////////