f7bd3d0e7410c5221da89c89d67dccbfd1540e35
[platform/upstream/libzypp.git] / zypp / capability / CapabilityImpl.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/capability/CapabilityImpl.cc
10  *
11 */
12 #include <iostream>
13
14 #include "zypp/base/Logger.h"
15 #include "zypp/base/Exception.h"
16 #include "zypp/capability/CapabilityImpl.h"
17 #include "zypp/capability/Capabilities.h"
18
19 using namespace std;
20
21 ///////////////////////////////////////////////////////////////////
22 namespace zypp
23 { /////////////////////////////////////////////////////////////////
24   ///////////////////////////////////////////////////////////////////
25   namespace capability
26   { /////////////////////////////////////////////////////////////////
27     IMPL_PTR_TYPE(CapabilityImpl)
28
29     ///////////////////////////////////////////////////////////////////
30     //
31     //  METHOD NAME : CapabilityImpl::CapabilityImpl
32     //  METHOD TYPE : Ctor
33     //
34     CapabilityImpl::CapabilityImpl( const Resolvable::Kind & refers_r )
35     : _refers( refers_r )
36     {}
37
38     ///////////////////////////////////////////////////////////////////
39     //
40     //  METHOD NAME : CapabilityImpl::capImplOrderLess
41     //  METHOD TYPE : bool
42     //
43     bool CapabilityImpl::capImplOrderLess( const constPtr & rhs ) const
44     {
45       return encode() < rhs->encode();
46     }
47
48     ///////////////////////////////////////////////////////////////////
49     //
50     //  METHOD NAME : CapabilityImpl::capImplOrderLess
51     //  METHOD TYPE : bool
52     //
53     std::ostream & CapabilityImpl::dumpOn( std::ostream & str ) const
54     {
55       return str << '[' << refers() << "] "
56                  << '(' << kind() << ") "
57                  << asString();
58     }
59
60     /** Assert a valid Resolvable::Kind. */
61     static void assertResKind( const Resolvable::Kind & refers_r )
62     {
63       if ( refers_r == Resolvable::Kind() )
64         ZYPP_THROW( Exception("Missing or empty  Resolvable::Kind in Capability") );
65     }
66
67     bool isEditionSpec( Rel op_r, const Edition & edition_r )
68     {
69       switch ( op_r.inSwitch() )
70         {
71         case Rel::ANY_e:
72           if ( edition_r != Edition::noedition )
73             WAR << "Operator " << op_r << " causes Edition "
74             << edition_r << " to be ignored." << endl;
75           return false;
76           break;
77
78         case Rel::NONE_e:
79           ZYPP_THROW( Exception("Operator NONE is not allowed in Capability") );
80           break;
81
82         case Rel::EQ_e:
83         case Rel::NE_e:
84         case Rel::LT_e:
85         case Rel::LE_e:
86         case Rel::GT_e:
87         case Rel::GE_e:
88           return true;
89           break;
90         }
91       // SHOULD NOT GET HERE
92       ZYPP_THROW( Exception("Unknown Operator NONE is not allowed in Capability") );
93       return false; // not reached
94     }
95
96     bool isFileSpec( const std::string & name_r )
97     {
98       return *name_r.c_str() == '/';
99     }
100
101     bool isSplitSpec( const std::string & name_r )
102     {
103       return name_r.find( ":/" ) != std::string::npos;
104     }
105
106     bool isHalSpec( const std::string & name_r )
107     {
108       return name_r.substr(0,4) == "hal(";
109     }
110
111     bool isModaliasSpec( const std::string & name_r )
112     {
113       return name_r.substr(0,9) == "modalias(";
114     }
115
116     bool isFilesystemSpec( const std::string & name_r )
117     {
118       return name_r.substr(0,11) == "filesystem(";
119     }
120
121     CapabilityImpl::Ptr buildFile( const Resolvable::Kind & refers_r,
122                                           const std::string & name_r )
123     {
124       // NullCap check first:
125       if ( name_r.empty() )
126         {
127           // Singleton, so no need to put it into _uset !?
128           return capability::NullCap::instance();
129         }
130
131       assertResKind( refers_r );
132
133       return new capability::FileCap( refers_r, name_r );
134     }
135
136     CapabilityImpl::Ptr buildNamed( const Resolvable::Kind & refers_r,
137                                            const std::string & name_r )
138     {
139       // NullCap check first:
140       if ( name_r.empty() )
141       {
142         // Singleton, so no need to put it into _uset !?
143         return capability::NullCap::instance();
144       }
145
146       assertResKind( refers_r );
147
148       // file:    /absolute/path
149       if ( isFileSpec( name_r ) )
150       {
151         return new capability::FileCap( refers_r, name_r );
152       }
153       if ( isFilesystemSpec( name_r ) )
154       {
155         return buildFilesystem( refers_r, name_r );
156       }
157
158       //split:   name:/absolute/path
159       static const str::regex  rx( "([^/]*):(/.*)" );
160       str::smatch what;
161       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
162       {
163         return new capability::SplitCap( refers_r, what[1].str(), what[2].str() );
164       }
165
166       //name:    name
167       return new capability::NamedCap( refers_r, name_r );
168     }
169
170     CapabilityImpl::Ptr buildVersioned( const Resolvable::Kind & refers_r,
171                                                const std::string & name_r,
172                                                Rel op_r,
173                                                const Edition & edition_r )
174     {
175       if ( isEditionSpec( op_r, edition_r ) )
176         {
177           assertResKind( refers_r );
178
179           // build a VersionedCap
180           return new capability::VersionedCap( refers_r, name_r, op_r, edition_r );
181         }
182       //else
183       // build a NamedCap
184
185       return buildNamed( refers_r, name_r );
186     }
187
188     CapabilityImpl::Ptr buildHal( const Resolvable::Kind & refers_r,
189                                          const std::string & name_r,
190                                          Rel op_r,
191                                          const std::string & value_r )
192     {
193       if ( op_r != Rel::ANY )
194         {
195           ZYPP_THROW( Exception("Unsupported kind of Hal Capability '" + op_r.asString() + "'") );
196         }
197
198       //split:   hal(name) [op string]
199       static const str::regex  rx( "hal\\(([^)]*)\\)" );
200       str::smatch what;
201       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
202         {
203           // Hal always refers to 'System' kind of Resolvable.
204           return new capability::HalCap( ResTraits<SystemResObject>::kind,
205                                     what[1].str() );
206         }
207       // otherwise
208       ZYPP_THROW( Exception("Unsupported kind of Hal Capability '" + name_r + "'") );
209       return NULL; // make gcc happy
210     }
211
212     CapabilityImpl::Ptr buildModalias( const Resolvable::Kind & refers_r,
213                                               const std::string & name_r,
214                                               Rel op_r,
215                                               const std::string & value_r )
216     {
217       if ( op_r != Rel::ANY )
218         {
219           ZYPP_THROW( Exception("Unsupported kind of Modalias Capability  '" + op_r.asString() + "'") );
220         }
221
222       //split:   modalias(name) [op string]
223       static const str::regex  rx( "modalias\\(([^)]*)\\)" );
224       str::smatch what;
225       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
226         {
227           // Modalias always refers to 'System' kind of Resolvable
228           return new capability::ModaliasCap( ResTraits<SystemResObject>::kind,
229                                          what[1].str() );
230         }
231       // otherwise
232       ZYPP_THROW( Exception("Unsupported kind of Modalias Capability'" + name_r + "'") );
233       return NULL; // make gcc happy
234     }
235
236     /******************************************************************
237     **
238     **  FUNCTION NAME : buildFilesystem
239     **  FUNCTION TYPE : CapabilityImpl::Ptr
240     */
241     CapabilityImpl::Ptr buildFilesystem( const Resolvable::Kind & refers_r,
242                                        const std::string & name_r )
243     {
244       //split:   filesystem(name) [op string]
245       static const str::regex  rx( "filesystem\\(([^)]*)\\)" );
246       str::smatch what;
247       if( str::regex_match( name_r.begin(), name_r.end(), what, rx ) )
248       {
249         // Filesystem always refers to 'System' kind of Resolvable
250         return new capability::FilesystemCap( ResTraits<SystemResObject>::kind,
251                                               what[1].str() );
252       }
253       // otherwise
254       ZYPP_THROW( Exception("Unsupported kind of Filesystem Capability'" + name_r + "'") );
255       return NULL; // make gcc happy
256     }
257
258
259     CapabilityImpl::Ptr parse( const Resolvable::Kind & refers_r,
260                                const std::string & strval_r )
261   try
262     {
263       if ( isHalSpec( strval_r ) )
264         {
265           return buildHal( refers_r, strval_r );
266         }
267       if ( isModaliasSpec( strval_r ) )
268         {
269           return buildModalias( refers_r, strval_r );
270         }
271       if ( isFilesystemSpec( strval_r ) )
272         {
273           return buildFilesystem( refers_r, strval_r );
274         }
275       if ( isFileSpec( strval_r ) )
276         {
277           return buildFile( refers_r, strval_r );
278         }
279
280       // strval_r has at least two words which could make 'op edition'?
281       // improve regex!
282       static const str::regex  rx( "(.*[^ \t])([ \t]+)([^ \t]+)([ \t]+)([^ \t]+)" );
283       str::smatch what;
284       if( str::regex_match( strval_r.begin(), strval_r.end(),what, rx ) )
285         {
286           Rel op;
287           Edition edition;
288           try
289             {
290               op = Rel(what[3].str());
291               edition = Edition(what[5].str());
292             }
293           catch ( Exception & excpt )
294             {
295               // So they don't make valid 'op edition'
296               ZYPP_CAUGHT( excpt );
297               DBG << "Trying named cap for: " << strval_r << endl;
298               // See whether it makes a named cap.
299               return buildNamed( refers_r, strval_r );
300             }
301
302           // Valid 'op edition'
303           return buildVersioned( refers_r,
304                                  what[1].str(), op, edition );
305         }
306       //else
307       // not a VersionedCap
308       return buildNamed( refers_r, strval_r );
309     }
310   catch ( Exception & excpt )
311     {
312       ZYPP_RETHROW( excpt );
313       return NULL; // not reached
314     }
315
316
317   CapabilityImpl::Ptr parse( const Resolvable::Kind & refers_r,
318                                 const std::string & name_r,
319                                 const std::string & op_r,
320                                 const std::string & edition_r )
321     try
322     {
323       if ( isHalSpec( name_r ) )
324       {
325         return buildHal( refers_r, name_r, Rel(op_r), edition_r );
326       }
327       if ( isModaliasSpec( name_r ) )
328         {
329           return buildModalias( refers_r, name_r, Rel(op_r), edition_r );
330         }
331       // Try creating Rel and Edition, then parse
332       return parse( refers_r, name_r, Rel(op_r), Edition(edition_r) );
333     }
334     catch ( Exception & excpt )
335     {
336       ZYPP_RETHROW( excpt );
337       return NULL; // not reached
338     }
339
340   ///////////////////////////////////////////////////////////////////
341   //
342   //    METHOD NAME : CapFactory::parse
343   //    METHOD TYPE : Capability
344   //
345   CapabilityImpl::Ptr parse( const Resolvable::Kind & refers_r,
346                              const std::string & name_r,
347                              Rel op_r,
348                              const Edition & edition_r )
349   try
350   {
351       if ( isHalSpec( name_r ) )
352       {
353         return buildHal( refers_r, name_r, op_r, edition_r.asString() );
354       }
355       if ( isModaliasSpec( name_r ) )
356       {
357         return buildModalias( refers_r, name_r, op_r, edition_r.asString() );
358       }
359       return buildVersioned( refers_r, name_r, op_r, edition_r );
360   }
361   catch ( Exception & excpt )
362   {
363       ZYPP_RETHROW( excpt );
364       return NULL; // not reached
365   }
366
367   ///////////////////////////////////////////////////////////////////
368
369     /////////////////////////////////////////////////////////////////
370   } // namespace capability
371   ///////////////////////////////////////////////////////////////////
372   /////////////////////////////////////////////////////////////////
373 } // namespace zypp
374 ///////////////////////////////////////////////////////////////////