902358bf352061d2fa37b9b0c11ebd4996d30baa
[platform/upstream/libzypp.git] / zypp / ui / SelectableImpl.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/ui/SelectableImpl.h
10  *
11 */
12 #ifndef ZYPP_UI_SELECTABLEIMPL_H
13 #define ZYPP_UI_SELECTABLEIMPL_H
14
15 #include <iostream>
16 #include "zypp/base/LogTools.h"
17
18 #include "zypp/base/PtrTypes.h"
19
20 #include "zypp/ResPool.h"
21 #include "zypp/Resolver.h"
22 #include "zypp/ui/Selectable.h"
23 #include "zypp/ui/SelectableTraits.h"
24
25 using std::endl;
26
27 ///////////////////////////////////////////////////////////////////
28 namespace zypp
29 { /////////////////////////////////////////////////////////////////
30   ///////////////////////////////////////////////////////////////////
31   namespace ui
32   { /////////////////////////////////////////////////////////////////
33
34     ///////////////////////////////////////////////////////////////////
35     //
36     //  CLASS NAME : Selectable::Impl
37     //
38     /** Selectable implementation.
39      * \note Implementation is based in PoolItem, just the Selectable
40      * inteface restricts them to ResObject::constPtr.
41     */
42     struct Selectable::Impl
43     {
44     public:
45
46       typedef SelectableTraits::AvailableItemSet         AvailableItemSet;
47       typedef SelectableTraits::available_iterator       available_iterator;
48       typedef SelectableTraits::available_const_iterator available_const_iterator;
49       typedef SelectableTraits::available_size_type      available_size_type;
50
51       typedef SelectableTraits::InstalledItemSet         InstalledItemSet;
52       typedef SelectableTraits::installed_iterator       installed_iterator;
53       typedef SelectableTraits::installed_const_iterator installed_const_iterator;
54       typedef SelectableTraits::installed_size_type      installed_size_type;
55
56       typedef SelectableTraits::PickList                PickList;
57
58     public:
59       template <class TIterator>
60       Impl( const ResKind & kind_r,
61             const std::string & name_r,
62             TIterator begin_r,
63             TIterator end_r )
64       : _ident( sat::Solvable::SplitIdent( kind_r, name_r ).ident() )
65       , _kind( kind_r )
66       , _name( name_r )
67       {
68         for_( it, begin_r, end_r )
69         {
70           if ( it->status().isInstalled() )
71             _installedItems.insert( *it );
72           else
73             _availableItems.insert( *it );
74         }
75       }
76
77     public:
78       /**  */
79       IdString ident() const
80       { return _ident; }
81
82       /**  */
83       ResKind kind() const
84       { return _kind; }
85
86       /**  */
87       const std::string & name() const
88       { return _name; }
89
90       /**  */
91       Status status() const;
92
93       /**  */
94       bool setStatus( Status state_r, ResStatus::TransactByValue causer_r );
95
96       /** Installed object (transacting ot highest version). */
97       PoolItem installedObj() const
98       {
99         if ( installedEmpty() )
100           return PoolItem();
101         PoolItem ret( transactingInstalled() );
102         return ret ? ret : *_installedItems.begin();
103       }
104
105       /** Best among available objects.
106        * The transacting candidate or the one scheduled to receive
107        * the transact bit.
108       */
109       PoolItem candidateObj() const
110       {
111         PoolItem ret( transactingCandidate() );
112         if ( ret )
113           return ret;
114         return _candidate ? _candidate : defaultCandidate();
115       }
116
117       /** Set a userCandidate (out of available objects).
118        * \return The new userCandidate or NULL if choice was invalid
119        * (not among availableObjs).
120       */
121       PoolItem setCandidate( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r );
122
123       /** The best candidate provided by a specific \ref Repository, if there is one.
124        * In contrary to \ref candidateObj, this may return no item even if
125        * there are available objects. This simply means the \ref Repository
126        * does not provide this object.
127        */
128       PoolItem candidateObjFrom( Repository repo_r ) const
129       {
130         for ( const PoolItem & pi : available() )
131         {
132           if ( pi.repository() == repo_r )
133             return pi;
134         }
135         return PoolItem();
136       }
137
138       /** The best candidate for update, if there is one.
139        * In contrary to \ref candidateObj, this may return no item even if
140        * there are available objects. This simply means the best object is
141        * already installed, and all available objects violate at least one
142        * update policy.
143        */
144       PoolItem updateCandidateObj() const
145       {
146         PoolItem defaultCand( defaultCandidate() );
147
148         // multiversionInstall: This returns the candidate for the last
149         // instance installed. Actually we'd need a list here.
150
151         if ( installedEmpty() || ! defaultCand )
152           return defaultCand;
153         // Here: installed and defaultCand are non NULL and it's not a
154         //       multiversion install.
155
156         PoolItem installed( installedObj() );
157         // check vendor change
158         if ( ! ( ResPool::instance().resolver().allowVendorChange()
159                  || VendorAttr::instance().equivalent( defaultCand->vendor(), installed->vendor() ) ) )
160           return PoolItem();
161
162         // check arch change (arch noarch changes are allowed)
163         if ( defaultCand->arch() != installed->arch()
164            && ! ( defaultCand->arch() == Arch_noarch || installed->arch() == Arch_noarch ) )
165           return PoolItem();
166
167         // check greater edition
168         if ( defaultCand->edition() <= installed->edition() )
169           return PoolItem();
170
171         return defaultCand;
172       }
173
174       /** \copydoc Selectable::highestAvailableVersionObj()const */
175       PoolItem highestAvailableVersionObj() const
176       {
177         PoolItem ret;
178         for ( const PoolItem & pi : available() )
179         {
180           if ( !ret || pi.edition() > ret.edition() )
181             ret = pi;
182         }
183         return ret;
184       }
185
186       /** \copydoc Selectable::identIsAutoInstalled()const */
187       bool identIsAutoInstalled() const
188       { return sat::Solvable::identIsAutoInstalled( ident() ); }
189
190       /** \copydoc Selectable::identicalAvailable( const PoolItem & )const */
191       bool identicalAvailable( const PoolItem & rhs ) const
192       { return bool(identicalAvailableObj( rhs )); }
193
194       /** \copydoc Selectable::identicalInstalled( const PoolItem & )const */
195       bool identicalInstalled( const PoolItem & rhs ) const
196       { return bool(identicalInstalledObj( rhs )); }
197
198       /** \copydoc Selectable::identicalAvailableObj( const PoolItem & rhs ) const */
199       PoolItem identicalAvailableObj( const PoolItem & rhs ) const
200       {
201         if ( !availableEmpty() && rhs )
202         {
203           for_( it, _availableItems.begin(), _availableItems.end() )
204           {
205             if ( identical( *it, rhs ) )
206               return *it;
207           }
208         }
209         return PoolItem();
210       }
211
212       /** \copydoc Selectable::identicalInstalledObj( const PoolItem & rhs ) const */
213       PoolItem identicalInstalledObj( const PoolItem & rhs ) const
214       {
215         if ( !installedEmpty() && rhs )
216         {
217           for_( it, _installedItems.begin(), _installedItems.end() )
218           {
219             if ( identical( *it, rhs ) )
220               return *it;
221           }
222         }
223         return PoolItem();
224       }
225
226       /** Best among all objects. */
227       PoolItem theObj() const
228       {
229         PoolItem ret( candidateObj() );
230         if ( ret )
231           return ret;
232         return installedObj();
233       }
234
235       ////////////////////////////////////////////////////////////////////////
236
237       bool availableEmpty() const
238       { return _availableItems.empty(); }
239
240       available_size_type availableSize() const
241       { return _availableItems.size(); }
242
243       available_iterator availableBegin() const
244       { return _availableItems.begin(); }
245
246       available_iterator availableEnd() const
247       { return _availableItems.end(); }
248
249       inline Iterable<available_iterator>  available() const
250       { return makeIterable( availableBegin(), availableEnd() ); }
251
252       ////////////////////////////////////////////////////////////////////////
253
254       bool installedEmpty() const
255       { return _installedItems.empty(); }
256
257       installed_size_type installedSize() const
258       { return _installedItems.size(); }
259
260       installed_iterator installedBegin() const
261       { return _installedItems.begin(); }
262
263       installed_iterator installedEnd() const
264       { return _installedItems.end(); }
265
266       inline Iterable<installed_iterator>  installed() const
267       { return makeIterable( installedBegin(), installedEnd() ); }
268
269       ////////////////////////////////////////////////////////////////////////
270
271       const PickList & picklist() const
272       {
273         if ( ! _picklistPtr )
274         {
275           _picklistPtr.reset( new PickList );
276           // installed without identical avaialble first:
277           for ( const PoolItem & pi : installed() )
278           {
279             if ( ! identicalAvailable( pi ) )
280               _picklistPtr->push_back( pi );
281           }
282           _picklistPtr->insert( _picklistPtr->end(), availableBegin(), availableEnd() );
283         }
284         return *_picklistPtr;
285       }
286
287       bool picklistEmpty() const
288       { return picklist().empty(); }
289
290       picklist_size_type picklistSize() const
291       { return picklist().size(); }
292
293       picklist_iterator picklistBegin() const
294       { return picklist().begin(); }
295
296       picklist_iterator picklistEnd() const
297       { return picklist().end(); }
298
299       ////////////////////////////////////////////////////////////////////////
300
301       bool isUnmaintained() const
302       { return availableEmpty(); }
303
304       bool multiversionInstall() const
305       {
306         for ( const PoolItem & pi : picklist() )
307         {
308           if ( pi.multiversionInstall() )
309             return true;
310         }
311         return false;
312       }
313
314       bool pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
315
316       bool pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
317
318       Status pickStatus( const PoolItem & pi_r ) const;
319
320       bool setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r );
321
322       ////////////////////////////////////////////////////////////////////////
323
324       bool isUndetermined() const
325       {
326         PoolItem cand( candidateObj() );
327         return ! cand || cand.isUndetermined();
328       }
329       bool isRelevant() const
330       {
331         PoolItem cand( candidateObj() );
332         return cand && cand.isRelevant();
333       }
334       bool isSatisfied() const
335        {
336         PoolItem cand( candidateObj() );
337         return cand && cand.isSatisfied();
338       }
339       bool isBroken() const
340       {
341         PoolItem cand( candidateObj() );
342         return cand && cand.isBroken();
343       }
344
345       /** Return who caused the modification. */
346       ResStatus::TransactByValue modifiedBy() const;
347
348       /** Return value of LicenceConfirmed bit. */
349       bool hasLicenceConfirmed() const
350       { return candidateObj() && candidateObj().status().isLicenceConfirmed(); }
351
352       /** Set LicenceConfirmed bit. */
353       void setLicenceConfirmed( bool val_r )
354       { if ( candidateObj() ) candidateObj().status().setLicenceConfirmed( val_r ); }
355
356     private:
357       PoolItem transactingInstalled() const
358       {
359         for ( const PoolItem & pi : installed() )
360           {
361             if ( pi.status().transacts() )
362               return pi;
363           }
364         return PoolItem();
365       }
366
367       PoolItem transactingCandidate() const
368       {
369         for ( const PoolItem & pi : available() )
370           {
371             if ( pi.status().transacts() )
372               return pi;
373           }
374         return PoolItem();
375       }
376
377       PoolItem defaultCandidate() const
378       {
379         if ( ! installedEmpty() )
380         {
381           // prefer the installed objects arch and vendor
382           bool solver_allowVendorChange( ResPool::instance().resolver().allowVendorChange() );
383           for ( const PoolItem & ipi : installed() )
384           {
385             PoolItem sameArch; // in case there's no same vendor at least stay with same arch.
386             for (  const PoolItem & api : available() )
387             {
388               // 'same arch' includes allowed changes to/from noarch.
389               if ( ipi.arch() == api.arch() || ipi.arch() == Arch_noarch || api.arch() == Arch_noarch )
390               {
391                 if ( ! solver_allowVendorChange )
392                 {
393                   if ( VendorAttr::instance().equivalent( ipi, api ) )
394                     return api;
395                   else if ( ! sameArch ) // remember best same arch in case no same vendor found
396                      sameArch = api;
397                 }
398                 else // same arch is sufficient
399                   return api;
400               }
401             }
402             if ( sameArch )
403               return sameArch;
404           }
405         }
406         if ( _availableItems.empty() )
407           return PoolItem();
408
409         return *_availableItems.begin();
410       }
411
412       bool allCandidatesLocked() const
413       {
414         for ( const PoolItem & pi : available() )
415           {
416             if ( ! pi.status().isLocked() )
417               return false;
418           }
419         return( ! _availableItems.empty() );
420       }
421
422       bool allInstalledLocked() const
423       {
424         for ( const PoolItem & pi : installed() )
425           {
426             if ( ! pi.status().isLocked() )
427               return false;
428           }
429         return( ! _installedItems.empty() );
430       }
431
432
433     private:
434       const IdString         _ident;
435       const ResKind          _kind;
436       const std::string      _name;
437       InstalledItemSet       _installedItems;
438       AvailableItemSet       _availableItems;
439       //! The object selected by setCandidateObj() method.
440       PoolItem               _candidate;
441       //! lazy initialized picklist
442       mutable scoped_ptr<PickList> _picklistPtr;
443     };
444     ///////////////////////////////////////////////////////////////////
445
446     /** \relates Selectable::Impl Stream output */
447     inline std::ostream & operator<<( std::ostream & str, const Selectable::Impl & obj )
448     {
449       return str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
450                  << " (I " << obj.installedSize() << ")"
451                  << " (A " << obj.availableSize() << ")"
452                  << obj.candidateObj();
453     }
454
455     /** \relates Selectable::Impl Stream output */
456     inline std::ostream & dumpOn( std::ostream & str, const Selectable::Impl & obj )
457     {
458       str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
459           << ( obj.multiversionInstall() ? " (multiversion)" : "") << endl;
460
461       if ( obj.installedEmpty() )
462         str << "   (I 0) {}" << endl << "   ";
463       else
464       {
465         PoolItem icand( obj.installedObj() );
466         str << "   (I " << obj.installedSize() << ") {" << endl;
467         for ( const PoolItem & pi : obj.installed() )
468         {
469           char t = ' ';
470           if ( pi == icand )
471           {
472             t = 'i';
473           }
474           str << " " << t << " " << pi << endl;
475         }
476         str << "}  ";
477       }
478
479       if ( obj.availableEmpty() )
480       {
481         str << "(A 0) {}" << endl << "   ";
482       }
483       else
484       {
485         PoolItem cand( obj.candidateObj() );
486         PoolItem up( obj.updateCandidateObj() );
487         str << "(A " << obj.availableSize() << ") {" << endl;
488         for ( const PoolItem & pi : obj.available() )
489         {
490           char t = ' ';
491           if ( pi == cand )
492           {
493             t = pi == up ? 'C' : 'c';
494           }
495           else if ( pi == up )
496           {
497             t = 'u';
498           }
499           str << " " << t << " " << pi << endl;
500         }
501         str << "}  ";
502       }
503
504       if ( obj.picklistEmpty() )
505       {
506         str << "(P 0) {}";
507       }
508       else
509       {
510         PoolItem cand( obj.candidateObj() );
511         PoolItem up( obj.updateCandidateObj() );
512         str << "(P " << obj.picklistSize() << ") {" << endl;
513         for ( const PoolItem & pi : obj.picklist() )
514         {
515           char t = ' ';
516           if ( pi == cand )
517           {
518             t = pi == up ? 'C' : 'c';
519           }
520           else if ( pi == up )
521           {
522             t = 'u';
523           }
524           str << " " << t << " " << pi << "\t" << obj.pickStatus( pi ) << endl;
525         }
526         str << "}  ";
527       }
528
529       return str;
530     }
531     /////////////////////////////////////////////////////////////////
532   } // namespace ui
533   ///////////////////////////////////////////////////////////////////
534   /////////////////////////////////////////////////////////////////
535 } // namespace zypp
536 ///////////////////////////////////////////////////////////////////
537 #endif // ZYPP_UI_SELECTABLEIMPL_H