45562f086e428edcd1e9fa44aad5fcc720343ab2
[platform/upstream/libzypp.git] / zypp / Pattern.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/Pattern.cc
10  *
11 */
12 #include <iostream>
13 #include "zypp/base/LogTools.h"
14
15 #include "zypp/ResPool.h"
16 #include "zypp/Pattern.h"
17 #include "zypp/Filter.h"
18
19 using std::endl;
20
21 ///////////////////////////////////////////////////////////////////
22 namespace zypp
23 {
24   ///////////////////////////////////////////////////////////////////
25   namespace
26   {
27     inline Capability autoCapability( const Capabilities & provides_r )
28     {
29       static const Capability autopattern( "autopattern()" );
30       for ( const auto & cap : provides_r )
31         if ( cap.matches( autopattern ) == CapMatch::yes )
32           return cap;
33       return Capability();
34     }
35
36     ///////////////////////////////////////////////////////////////////
37     //
38     //  CLASS NAME : PatternExpander
39     //
40     /** Recursively expand a Pattern.
41      *
42      * This means recursively expanding Patterns included by this or
43      * extending this. The result is a \c set of <tt>Pattern::constPtr</tt>
44      * accessible via iterator.
45      */
46     class PatternExpander
47     {
48       public:
49         typedef std::map<Pattern::constPtr, DefaultIntegral<bool, false> > PatternMap;
50         typedef PatternMap::size_type size_type;
51         typedef PatternMap::key_type  value_type;
52         typedef MapKVIteratorTraits<PatternMap>::Key_const_iterator const_iterator;
53
54       public:
55         PatternExpander()
56         {}
57
58         /** Recursively expand Pattern. */
59         size_type doExpand( Pattern::constPtr pat_r )
60         {
61           // INT << "+++ " << pat_r << " ++++++++++++++++++++++++++++++++++" << endl;
62           _patternMap.clear();
63           if ( pat_r )
64           {
65             _patternMap[pat_r];
66             Pattern::constPtr unprocessed( pat_r );
67             // MIL << _patternMap << endl;
68             do {
69               expandIncludes( unprocessed );
70               expandExtending( unprocessed );
71               _patternMap[unprocessed] = true;
72               // MIL << _patternMap << endl;
73             } while( (unprocessed = nextUnprocessed()) );
74           }
75           // SEC << "--- " << _patternMap.size() << " ----------------------------------" << endl;
76           return _patternMap.size();
77         }
78
79         const_iterator begin() const
80         { return make_map_key_begin( _patternMap ); }
81
82         const_iterator end() const
83         { return make_map_key_end( _patternMap ); }
84
85       private:
86         /** Get the next unprocessed Pattern in \c _patternMap. */
87         Pattern::constPtr nextUnprocessed() const
88         {
89           for_( it, _patternMap.begin(), _patternMap.end() )
90           {
91             if ( ! it->second )
92               return it->first;
93           }
94           return NULL;
95         }
96
97       private:
98         /** Store all included patterns in \c _patternMap. */
99         void expandIncludes( const Pattern::constPtr & pat_r )
100         {
101           Pattern::NameList c( pat_r->includes() );
102           for_( it, c.begin(), c.end() )
103           {
104             expandInclude( Capability( it->c_str()/*, *ResKind::pattern*/ ) );
105           }
106         }
107
108         /** Store Patterns matching an \c Includes capability in \c _patternMap. */
109         void expandInclude( const Capability & include_r )
110         {
111           sat::WhatProvides w( include_r );
112           for_( it, w.begin(), w.end() )
113           {
114             _patternMap[asKind<Pattern>(PoolItem(*it))];
115           }
116         }
117
118       private:
119         /** Store all patterns extending \c pat_r in \c _patternMap. */
120         void expandExtending( const Pattern::constPtr & pat_r )
121         {
122           ResPool pool( ResPool::instance() );
123           for_( it, pool.byKindBegin<Pattern>(), pool.byKindEnd<Pattern>() )
124           {
125             expandIfExtends( pat_r, *it );
126           }
127         }
128
129         /** Store \c extending_r if it extends \c pat_r. */
130         void expandIfExtends( const Pattern::constPtr & pat_r, const PoolItem & extending_r )
131         {
132           Pattern::constPtr extending( asKind<Pattern>(extending_r) );
133           Pattern::NameList c( extending->extends() );
134           for_( it, c.begin(), c.end() )
135           {
136             if ( providedBy( pat_r, Capability( it->c_str()/*, *ResKind::pattern*/ ) ) )
137             {
138               // an extends matches the Pattern
139               _patternMap[extending];
140               break;
141             }
142           }
143         }
144
145         /** Return true if Capability \c extends_r is provided by Pattern. */
146         bool providedBy( const Pattern::constPtr & pat_r, const Capability & extends_r )
147         {
148           if ( !pat_r )
149             return false;
150
151           sat::Solvable pat( pat_r->satSolvable() );
152           sat::WhatProvides w( extends_r );
153           for_( it, w.begin(), w.end() )
154           {
155             if ( pat == *it )
156               return true;
157           }
158           return false;
159         }
160
161       private:
162         PatternMap _patternMap;
163     };
164   } // namespace
165   ///////////////////////////////////////////////////////////////////
166
167   ///////////////////////////////////////////////////////////////////
168   //    Pattern
169   ///////////////////////////////////////////////////////////////////
170
171   IMPL_PTR_TYPE(Pattern);
172
173   Pattern::Pattern( const sat::Solvable & solvable_r )
174   : ResObject( solvable_r )
175   {}
176
177   Pattern::~Pattern()
178   {}
179
180   bool Pattern::isDefault() const
181   { return lookupBoolAttribute( sat::SolvAttr::isdefault ); }
182
183   bool Pattern::userVisible() const
184   { return lookupBoolAttribute( sat::SolvAttr::isvisible ); }
185
186   std::string Pattern::category( const Locale & lang_r ) const
187   { return lookupStrAttribute( sat::SolvAttr::category, lang_r ); }
188
189   Pathname Pattern::icon() const
190   { return lookupStrAttribute( sat::SolvAttr::icon ); }
191
192   Pathname Pattern::script() const
193   { return lookupStrAttribute( sat::SolvAttr::script ); }
194
195   std::string Pattern::order() const
196   { return lookupStrAttribute( sat::SolvAttr::order ); }
197
198   bool Pattern::isAutoPattern() const
199   { return bool(autoCapability( provides() )); }
200
201   sat::Solvable Pattern::autoPackage() const
202   {
203     Capability autocap( autoCapability( provides() ) );
204     if ( autocap )
205     {
206       Capability pkgCap( arch(), autocap.detail().ed().asString(), Rel::EQ, edition() );
207       for ( const auto & solv: sat::WhatProvides( pkgCap ) )
208         if ( solv.repository() == repository() )
209           return solv;
210     }
211     return sat::Solvable();
212   }
213
214   Pattern::NameList Pattern::includes() const
215   { return NameList( sat::SolvAttr::includes, satSolvable() ); }
216
217   Pattern::NameList Pattern::extends() const
218   { return NameList( sat::SolvAttr::extends, satSolvable() ); }
219
220   ///////////////////////////////////////////////////////////////////
221   namespace
222   {
223     inline void addCaps( CapabilitySet & caps_r, sat::Solvable solv_r, Dep dep_r )
224     {
225       Capabilities c( solv_r[dep_r] );
226       if ( ! c.empty() )
227       {
228         caps_r.insert( c.begin(),c.end() );
229       }
230     }
231   } //namespace
232   ///////////////////////////////////////////////////////////////////
233
234   Pattern::Contents Pattern::core() const
235   {
236     // Content dependencies are either associated with
237     // the autoPackage or the (oldstype) pattern itself.
238     // load requires
239     CapabilitySet caps;
240     addCaps( caps, *this, Dep::REQUIRES );
241
242     sat::Solvable depKeeper( autoPackage() );
243     if ( depKeeper )
244       addCaps( caps, depKeeper, Dep::REQUIRES );
245     // get items providing the requirements
246     sat::WhatProvides prv( caps );
247     // return packages only.
248     return Pattern::Contents( make_filter_begin( filter::byKind<Package>(), prv ),
249                               make_filter_end( filter::byKind<Package>(), prv ) );
250   }
251
252   Pattern::Contents Pattern::depends( bool includeSuggests_r ) const
253   {
254     // Content dependencies are either associated with
255     // the autoPackage or the (oldstype) pattern itself.
256     // load requires, recommends[, suggests]
257     CapabilitySet caps;
258     addCaps( caps, *this, Dep::REQUIRES );
259     addCaps( caps, *this, Dep::RECOMMENDS );
260     if ( includeSuggests_r )
261       addCaps( caps, *this, Dep::SUGGESTS );
262
263     sat::Solvable depKeeper( autoPackage() );
264     if ( depKeeper )
265     {
266       addCaps( caps, depKeeper, Dep::REQUIRES );
267       addCaps( caps, depKeeper, Dep::RECOMMENDS );
268       if ( includeSuggests_r )
269         addCaps( caps, depKeeper, Dep::SUGGESTS );
270     }
271     // get items providing the above
272     sat::WhatProvides prv( caps );
273     // return packages only.
274     return Pattern::Contents( make_filter_begin( filter::byKind<Package>(), prv ),
275                               make_filter_end( filter::byKind<Package>(), prv ) );
276   }
277
278   Pattern::Contents Pattern::contents( bool includeSuggests_r ) const
279   {
280     PatternExpander expander;
281     if ( ! expander.doExpand( this ) )
282       return Contents(); // empty pattern set
283
284     Contents result;
285     for_( it, expander.begin(), expander.end() )
286     {
287       Contents c( (*it)->depends( includeSuggests_r ) );
288       result.get().insert( c.begin(), c.end() );
289     }
290     return result;
291   }
292
293   /////////////////////////////////////////////////////////////////
294 } // namespace zypp
295 ///////////////////////////////////////////////////////////////////