ui::Selectable: PickList and status interface for multiinstallable items.
[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/ZConfig.h"
21 #include "zypp/ui/Selectable.h"
22 #include "zypp/ui/SelectableTraits.h"
23
24 using std::endl;
25
26 ///////////////////////////////////////////////////////////////////
27 namespace zypp
28 { /////////////////////////////////////////////////////////////////
29   ///////////////////////////////////////////////////////////////////
30   namespace ui
31   { /////////////////////////////////////////////////////////////////
32
33     ///////////////////////////////////////////////////////////////////
34     //
35     //  CLASS NAME : Selectable::Impl
36     //
37     /** Selectable implementation.
38      * \note Implementation is based in PoolItem, just the Selectable
39      * inteface restricts them to ResObject::constPtr.
40     */
41     struct Selectable::Impl
42     {
43     public:
44
45       typedef SelectableTraits::AvailableItemSet         AvailableItemSet;
46       typedef SelectableTraits::available_iterator       available_iterator;
47       typedef SelectableTraits::available_const_iterator available_const_iterator;
48       typedef SelectableTraits::available_size_type      available_size_type;
49
50       typedef SelectableTraits::InstalledItemSet         InstalledItemSet;
51       typedef SelectableTraits::installed_iterator       installed_iterator;
52       typedef SelectableTraits::installed_const_iterator installed_const_iterator;
53       typedef SelectableTraits::installed_size_type      installed_size_type;
54
55       typedef SelectableTraits::PickList                PickList;
56
57     public:
58       template <class _Iterator>
59       Impl( const ResObject::Kind & kind_r,
60             const std::string & name_r,
61             _Iterator begin_r,
62             _Iterator end_r )
63       : _ident( sat::Solvable::SplitIdent( kind_r, name_r ).ident() )
64       , _kind( kind_r )
65       , _name( name_r )
66       {
67         for_( it, begin_r, end_r )
68         {
69           if ( it->status().isInstalled() )
70             _installedItems.insert( *it );
71           else
72             _availableItems.insert( *it );
73         }
74         _defaultCandidate = defaultCandidate();
75       }
76
77     public:
78       /**  */
79       IdString ident() const
80       { return _ident; }
81
82       /**  */
83       ResObject::Kind 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( const 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_( it, availableBegin(), availableEnd() )
131         {
132           if ( (*it)->repository() == repo_r )
133             return *it;
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         if ( multiversionInstall() || installedEmpty() || ! _defaultCandidate )
147           return _defaultCandidate;
148         // Here: installed and _defaultCandidate are non NULL and it's not a
149         //       multiversion install.
150
151         // update candidate must come from the highest priority repo
152         if ( _defaultCandidate->repoInfo().priority() != (*availableBegin())->repoInfo().priority() )
153           return PoolItem();
154
155         PoolItem installed( installedObj() );
156         // check vendor change
157         if ( ! ( ZConfig::instance().solver_allowVendorChange()
158                  || VendorAttr::instance().equivalent( _defaultCandidate->vendor(), installed->vendor() ) ) )
159           return PoolItem();
160
161         // check arch change (arch noarch changes are allowed)
162         if ( _defaultCandidate->arch() != installed->arch()
163            && ! ( _defaultCandidate->arch() == Arch_noarch || installed->arch() == Arch_noarch ) )
164           return PoolItem();
165
166         // check greater edition
167         if ( _defaultCandidate->edition() <= installed->edition() )
168           return PoolItem();
169
170         return _defaultCandidate;
171       }
172
173       /** \copydoc Selectable::highestAvailableVersionObj()const */
174       PoolItem highestAvailableVersionObj() const
175       {
176         PoolItem ret;
177         for_( it, availableBegin(), availableEnd() )
178         {
179           if ( !ret || (*it).satSolvable().edition() > ret.satSolvable().edition() )
180             ret = *it;
181         }
182         return ret;
183       }
184
185       /** \copydoc Selectable::identicalAvailable( const PoolItem & )const */
186       bool identicalAvailable( const PoolItem & rhs ) const
187       {
188         if ( !availableEmpty() && rhs )
189         {
190           for_( it, _availableItems.begin(), _availableItems.end() )
191           {
192             if ( identical( *it, rhs ) )
193               return true;
194           }
195         }
196         return false;
197       }
198
199       /** \copydoc Selectable::identicalInstalled( const PoolItem & )const */
200       bool identicalInstalled( const PoolItem & rhs ) const
201       {
202         if ( !installedEmpty() && rhs )
203         {
204           for_( it, _installedItems.begin(), _installedItems.end() )
205           {
206             if ( identical( *it, rhs ) )
207               return true;
208           }
209         }
210         return false;
211       }
212
213       /** Best among all objects. */
214       PoolItem theObj() const
215       {
216         PoolItem ret( candidateObj() );
217         if ( ret )
218           return ret;
219         return installedObj();
220       }
221
222       ////////////////////////////////////////////////////////////////////////
223
224       bool availableEmpty() const
225       { return _availableItems.empty(); }
226
227       available_size_type availableSize() const
228       { return _availableItems.size(); }
229
230       available_const_iterator availableBegin() const
231       { return _availableItems.begin(); }
232
233       available_const_iterator availableEnd() const
234       { return _availableItems.end(); }
235
236       ////////////////////////////////////////////////////////////////////////
237
238       bool installedEmpty() const
239       { return _installedItems.empty(); }
240
241       installed_size_type installedSize() const
242       { return _installedItems.size(); }
243
244       installed_iterator installedBegin() const
245       { return _installedItems.begin(); }
246
247       installed_iterator installedEnd() const
248       { return _installedItems.end(); }
249
250       ////////////////////////////////////////////////////////////////////////
251
252       const PickList & picklist() const
253       {
254         if ( ! _picklistPtr )
255         {
256           _picklistPtr.reset( new PickList( _availableItems.size() ) );
257           // installed without identical avaialble first:
258           for_( it, _installedItems.begin(), _installedItems.end() )
259           {
260             if ( ! identicalAvailable( *it ) )
261               _picklistPtr->push_back( *it );
262           }
263           _picklistPtr->insert( _picklistPtr->end(), availableBegin(), availableEnd() );
264         }
265         return *_picklistPtr;
266       }
267
268       bool picklistEmpty() const
269       { return picklist().empty(); }
270
271       picklist_size_type picklistSize() const
272       { return picklist().size(); }
273
274       picklist_iterator picklistBegin() const
275       { return picklist().begin(); }
276
277       picklist_iterator picklistEnd() const
278       { return picklist().end(); }
279
280       ////////////////////////////////////////////////////////////////////////
281
282       bool isUnmaintained() const
283       { return availableEmpty(); }
284
285       bool multiversionInstall() const
286       { return theObj().satSolvable().multiversionInstall(); }
287
288       bool pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
289
290       bool pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
291
292       Status pickStatus( const PoolItem & pi_r ) const;
293
294       ////////////////////////////////////////////////////////////////////////
295
296       bool isUndetermined() const
297       {
298         PoolItem cand( candidateObj() );
299         return ! cand || cand.isUndetermined();
300       }
301       bool isRelevant() const
302       {
303         PoolItem cand( candidateObj() );
304         return cand && cand.isRelevant();
305       }
306       bool isSatisfied() const
307        {
308         PoolItem cand( candidateObj() );
309         return cand && cand.isSatisfied();
310       }
311       bool isBroken() const
312       {
313         PoolItem cand( candidateObj() );
314         return cand && cand.isBroken();
315       }
316
317       /** Return who caused the modification. */
318       ResStatus::TransactByValue modifiedBy() const;
319
320       /** Return value of LicenceConfirmed bit. */
321       bool hasLicenceConfirmed() const
322       { return candidateObj() && candidateObj().status().isLicenceConfirmed(); }
323
324       /** Set LicenceConfirmed bit. */
325       void setLicenceConfirmed( bool val_r )
326       { if ( candidateObj() ) candidateObj().status().setLicenceConfirmed( val_r ); }
327
328     private:
329       PoolItem transactingInstalled() const
330       {
331         for_( it, installedBegin(), installedEnd() )
332           {
333             if ( (*it).status().transacts() )
334               return (*it);
335           }
336         return PoolItem();
337       }
338
339       PoolItem transactingCandidate() const
340       {
341         for_( it, availableBegin(), availableEnd() )
342           {
343             if ( (*it).status().transacts() )
344               return (*it);
345           }
346         return PoolItem();
347       }
348
349       PoolItem defaultCandidate() const
350       {
351         if ( ! ( multiversionInstall() || installedEmpty() ) )
352         {
353           // prefer the installed objects arch and vendor
354           bool solver_allowVendorChange( ZConfig::instance().solver_allowVendorChange() );
355           for ( installed_const_iterator iit = installedBegin();
356                 iit != installedEnd(); ++iit )
357           {
358             PoolItem sameArch; // in case there's no same vendor at least stay with same arch.
359             for ( available_const_iterator it = availableBegin();
360                   it != availableEnd(); ++it )
361             {
362               // 'same arch' includes allowed changes to/from noarch.
363               if ( (*iit)->arch() == (*it)->arch() || (*iit)->arch() == Arch_noarch || (*it)->arch() == Arch_noarch )
364               {
365                 if ( ! solver_allowVendorChange )
366                 {
367                   if ( VendorAttr::instance().equivalent( (*iit), (*it) ) )
368                     return *it;
369                   else if ( ! sameArch ) // remember best same arch in case no same vendor found
370                      sameArch = *it;
371                 }
372                 else // same arch is sufficient
373                   return *it;
374               }
375             }
376             if ( sameArch )
377               return sameArch;
378           }
379         }
380         if ( _availableItems.empty() )
381           return PoolItem();
382
383         return *_availableItems.begin();
384       }
385
386       bool allCandidatesLocked() const
387       {
388         for ( available_const_iterator it = availableBegin();
389               it != availableEnd(); ++it )
390           {
391             if ( ! (*it).status().isLocked() )
392               return false;
393           }
394         return( ! _availableItems.empty() );
395       }
396
397     private:
398       const IdString         _ident;
399       const ResObject::Kind  _kind;
400       const std::string      _name;
401       InstalledItemSet       _installedItems;
402       AvailableItemSet       _availableItems;
403       //! Best among availabe with restpect to installed.
404       PoolItem               _defaultCandidate;
405       //! The object selected by setCandidateObj() method.
406       PoolItem               _candidate;
407       //! lazy initialized picklist
408       mutable scoped_ptr<PickList> _picklistPtr;
409     };
410     ///////////////////////////////////////////////////////////////////
411
412     /** \relates Selectable::Impl Stream output */
413     inline std::ostream & operator<<( std::ostream & str, const Selectable::Impl & obj )
414     {
415       return str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
416                  << " (I " << obj.installedSize() << ")"
417                  << " (A " << obj.availableSize() << ")"
418                  << obj.candidateObj();
419     }
420
421     /** \relates Selectable::Impl Stream output */
422     inline std::ostream & dumpOn( std::ostream & str, const Selectable::Impl & obj )
423     {
424       str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
425           << ( obj.multiversionInstall() ? " (multiversion)" : "") << endl;
426
427       if ( obj.installedEmpty() )
428         str << "   (I 0) {}" << endl << "   ";
429       else
430       {
431         PoolItem icand( obj.installedObj() );
432         str << "   (I " << obj.installedSize() << ") {" << endl;
433         for_( it, obj.installedBegin(), obj.installedEnd() )
434         {
435           char t = ' ';
436           if ( *it == icand )
437           {
438             t = 'i';
439           }
440           str << " " << t << " " << *it << endl;
441         }
442         str << "}  ";
443       }
444
445       if ( obj.availableEmpty() )
446       {
447         str << "(A 0) {}";
448       }
449       else
450       {
451         PoolItem cand( obj.candidateObj() );
452         PoolItem up( obj.updateCandidateObj() );
453         str << "(A " << obj.availableSize() << ") {" << endl;
454         for_( it, obj.availableBegin(), obj.availableEnd() )
455         {
456           char t = ' ';
457           if ( *it == cand )
458           {
459             t = *it == up ? 'C' : 'c';
460           }
461           else if ( *it == up )
462           {
463             t = 'u';
464           }
465           str << " " << t << " " << *it << endl;
466         }
467         str << "}  ";
468       }
469
470       return str;
471     }
472     /////////////////////////////////////////////////////////////////
473   } // namespace ui
474   ///////////////////////////////////////////////////////////////////
475   /////////////////////////////////////////////////////////////////
476 } // namespace zypp
477 ///////////////////////////////////////////////////////////////////
478 #endif // ZYPP_UI_SELECTABLEIMPL_H