Imported Upstream version 16.3.2
[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   {
185     // bsc#900769: If visibility is a string(solvable ident) the pattern
186     // is visible IFF ident is available in the pool.
187     IdString ident( lookupStrAttribute( sat::SolvAttr::isvisible ) );
188     return( ident.empty() ? lookupBoolAttribute( sat::SolvAttr::isvisible )
189                           : ! ResPool::instance().byIdent( ident ).empty() );
190   }
191
192   std::string Pattern::category( const Locale & lang_r ) const
193   { return lookupStrAttribute( sat::SolvAttr::category, lang_r ); }
194
195   Pathname Pattern::icon() const
196   { return lookupStrAttribute( sat::SolvAttr::icon ); }
197
198   Pathname Pattern::script() const
199   { return lookupStrAttribute( sat::SolvAttr::script ); }
200
201   std::string Pattern::order() const
202   { return lookupStrAttribute( sat::SolvAttr::order ); }
203
204   bool Pattern::isAutoPattern() const
205   { return bool(autoCapability( provides() )); }
206
207   sat::Solvable Pattern::autoPackage() const
208   {
209     Capability autocap( autoCapability( provides() ) );
210     if ( autocap )
211     {
212       Capability pkgCap( arch(), autocap.detail().ed().asString(), Rel::EQ, edition() );
213       for ( const auto & solv: sat::WhatProvides( pkgCap ) )
214         if ( solv.repository() == repository() )
215           return solv;
216     }
217     return sat::Solvable();
218   }
219
220   Pattern::NameList Pattern::includes() const
221   { return NameList( sat::SolvAttr::includes, satSolvable() ); }
222
223   Pattern::NameList Pattern::extends() const
224   { return NameList( sat::SolvAttr::extends, satSolvable() ); }
225
226   ///////////////////////////////////////////////////////////////////
227   namespace
228   {
229     inline void addCaps( CapabilitySet & caps_r, sat::Solvable solv_r, Dep dep_r )
230     {
231       Capabilities c( solv_r[dep_r] );
232       if ( ! c.empty() )
233       {
234         caps_r.insert( c.begin(),c.end() );
235       }
236     }
237   } //namespace
238   ///////////////////////////////////////////////////////////////////
239
240   Pattern::Contents Pattern::core() const
241   {
242     // Content dependencies are either associated with
243     // the autoPackage or the (oldstype) pattern itself.
244     // load requires
245     CapabilitySet caps;
246     addCaps( caps, *this, Dep::REQUIRES );
247
248     sat::Solvable depKeeper( autoPackage() );
249     if ( depKeeper )
250       addCaps( caps, depKeeper, Dep::REQUIRES );
251     // get items providing the requirements
252     sat::WhatProvides prv( caps );
253     // return packages only.
254     return Pattern::Contents( make_filter_begin( filter::byKind<Package>(), prv ),
255                               make_filter_end( filter::byKind<Package>(), prv ) );
256   }
257
258   Pattern::Contents Pattern::depends( bool includeSuggests_r ) const
259   {
260     // Content dependencies are either associated with
261     // the autoPackage or the (oldstype) pattern itself.
262     // load requires, recommends[, suggests]
263     CapabilitySet caps;
264     addCaps( caps, *this, Dep::REQUIRES );
265     addCaps( caps, *this, Dep::RECOMMENDS );
266     if ( includeSuggests_r )
267       addCaps( caps, *this, Dep::SUGGESTS );
268
269     sat::Solvable depKeeper( autoPackage() );
270     if ( depKeeper )
271     {
272       addCaps( caps, depKeeper, Dep::REQUIRES );
273       addCaps( caps, depKeeper, Dep::RECOMMENDS );
274       if ( includeSuggests_r )
275         addCaps( caps, depKeeper, Dep::SUGGESTS );
276     }
277     // get items providing the above
278     sat::WhatProvides prv( caps );
279     // return packages only.
280     return Pattern::Contents( make_filter_begin( filter::byKind<Package>(), prv ),
281                               make_filter_end( filter::byKind<Package>(), prv ) );
282   }
283
284   Pattern::Contents Pattern::contents( bool includeSuggests_r ) const
285   {
286     PatternExpander expander;
287     if ( ! expander.doExpand( this ) )
288       return Contents(); // empty pattern set
289
290     Contents result;
291     for_( it, expander.begin(), expander.end() )
292     {
293       Contents c( (*it)->depends( includeSuggests_r ) );
294       result.get().insert( c.begin(), c.end() );
295     }
296     return result;
297   }
298
299   ///////////////////////////////////////////////////////////////////
300   namespace
301   {
302     // Get packages referenced by depKeeper dependency.
303     inline void dependsSetDoCollect( sat::Solvable depKeeper_r, Dep dep_r, Pattern::Contents & set_r )
304     {
305       CapabilitySet caps;
306       addCaps( caps, depKeeper_r, dep_r );
307       sat::WhatProvides prv( caps );
308       for ( ui::Selectable::Ptr sel : prv.selectable() )
309       {
310         const PoolItem & pi( sel->theObj() );
311         if ( pi.isKind<Package>() )
312           set_r.insert( pi );
313       }
314     }
315
316     // Get packages referenced by depKeeper.
317     inline void dependsSet( sat::Solvable depKeeper_r, Pattern::ContentsSet & collect_r )
318     {
319       dependsSetDoCollect( depKeeper_r, Dep::REQUIRES,   collect_r.req );
320       dependsSetDoCollect( depKeeper_r, Dep::RECOMMENDS, collect_r.rec ),
321       dependsSetDoCollect( depKeeper_r, Dep::SUGGESTS,   collect_r.sug );
322     }
323
324     // Whether this is a patterns depkeeper.
325     inline bool isPatternsPackage( sat::Solvable depKeeper_r )
326     {
327       static const Capability indicator( "pattern()" );
328       return depKeeper_r.provides().matches( indicator );
329     }
330   } // namespace
331   ///////////////////////////////////////////////////////////////////
332   void Pattern::contentsSet( ContentsSet & collect_r, bool recursively_r ) const
333   {
334     sat::Solvable depKeeper( autoPackage() );   // (my required) patterns-package
335     if ( ! depKeeper )
336       return;
337
338     // step 2 data
339     std::set<sat::Solvable> recTodo;    // recommended patterns-packages to process
340     std::set<sat::Solvable> allDone;    // patterns-packages already expanded
341     {
342       // step 1: Expand requirements, remember recommends....
343       // step 1 data (scoped to step1)
344       std::set<sat::Solvable> reqTodo;  // required patterns-packages to process
345
346       collect_r.req.insert( depKeeper );// collect the depKeeper
347       reqTodo.insert( depKeeper );      // and expand it...
348
349       while ( ! reqTodo.empty() )
350       {
351         // pop one patterns-package from todo
352         depKeeper = ( *reqTodo.begin() );
353         reqTodo.erase( reqTodo.begin() );
354         allDone.insert( depKeeper );
355
356         // collects stats
357         ContentsSet result;
358         dependsSet( depKeeper, result );
359
360         // evaluate result....
361         for ( sat::Solvable solv : result.req ) // remember unprocessed required patterns-packages...
362         {
363           if ( collect_r.req.insert( solv ) && recursively_r && isPatternsPackage( solv ) )
364             reqTodo.insert( solv );
365         }
366         for ( sat::Solvable solv : result.rec ) // remember unprocessed recommended patterns-packages...
367         {
368           if ( collect_r.rec.insert( solv ) && recursively_r && isPatternsPackage( solv ) )
369             recTodo.insert( solv );
370         }
371         for ( sat::Solvable solv : result.sug ) // NOTE: We don't expand suggested patterns!
372         {
373           collect_r.sug.insert( solv );
374         }
375       }
376     }
377     // step 2: All requirements are expanded, now check remaining recommends....
378     while ( ! recTodo.empty() )
379     {
380       // pop one patterns-package from todo
381       depKeeper = ( *recTodo.begin() );
382       recTodo.erase( recTodo.begin() );
383       if ( ! allDone.insert( depKeeper ).second )
384         continue;       // allready expanded (in requires)
385
386       // collects stats
387       ContentsSet result;
388       dependsSet( depKeeper, result );
389
390       // evaluate result....
391       for ( sat::Solvable solv : result.req )   // remember unprocessed required patterns-packages...
392       {
393         // NOTE: Requirements of recommended patterns count as 'recommended'
394         if ( collect_r.rec.insert( solv ) && recursively_r && isPatternsPackage( solv ) )
395           recTodo.insert( solv );
396       }
397       for ( sat::Solvable solv : result.rec )   // remember unprocessed recommended patterns-packages...
398       {
399         if ( collect_r.rec.insert( solv ) && recursively_r && isPatternsPackage( solv ) )
400           recTodo.insert( solv );
401       }
402         for ( sat::Solvable solv : result.sug ) // NOTE: We don't expand suggested patterns!
403         {
404           collect_r.sug.insert( solv );
405         }
406     }
407   }
408
409
410   /////////////////////////////////////////////////////////////////
411 } // namespace zypp
412 ///////////////////////////////////////////////////////////////////