Add Selectable::highestAvailableVersionObj. (bnc #557557)
[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     public:
56       template <class _Iterator>
57       Impl( const ResObject::Kind & kind_r,
58             const std::string & name_r,
59             _Iterator begin_r,
60             _Iterator end_r )
61       : _ident( sat::Solvable::SplitIdent( kind_r, name_r ).ident() )
62       , _kind( kind_r )
63       , _name( name_r )
64       {
65         for_( it, begin_r, end_r )
66         {
67           if ( it->status().isInstalled() )
68             _installedItems.insert( *it );
69           else
70             _availableItems.insert( *it );
71         }
72         _defaultCandidate = defaultCandidate();
73       }
74
75     public:
76       /**  */
77       IdString ident() const
78       { return _ident; }
79
80       /**  */
81       ResObject::Kind kind() const
82       { return _kind; }
83
84       /**  */
85       const std::string & name() const
86       { return _name; }
87
88       /**  */
89       Status status() const;
90
91       /**  */
92       bool setStatus( const Status state_r, ResStatus::TransactByValue causer_r );
93
94       /** Installed object (transacting ot highest version). */
95       PoolItem installedObj() const
96       {
97         if ( installedEmpty() )
98           return PoolItem();
99         PoolItem ret( transactingInstalled() );
100         return ret ? ret : *_installedItems.begin();
101       }
102
103       /** Best among available objects.
104        * The transacting candidate or the one scheduled to receive
105        * the transact bit.
106       */
107       PoolItem candidateObj() const
108       {
109         PoolItem ret( transactingCandidate() );
110         if ( ret )
111           return ret;
112         return _candidate ? _candidate : _defaultCandidate;
113       }
114
115       /** Set a userCandidate (out of available objects).
116        * \return The new userCandidate or NULL if choice was invalid
117        * (not among availableObjs).
118       */
119       PoolItem setCandidate( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r );
120
121       /** The best candidate provided by a specific \ref Repository, if there is one.
122        * In contrary to \ref candidateObj, this may return no item even if
123        * there are available objects. This simply means the \ref Repository
124        * does not provide this object.
125        */
126       PoolItem candidateObjFrom( Repository repo_r ) const
127       {
128         for_( it, availableBegin(), availableEnd() )
129         {
130           if ( (*it)->repository() == repo_r )
131             return *it;
132         }
133         return PoolItem();
134       }
135
136       /** The best candidate for update, if there is one.
137        * In contrary to \ref candidateObj, this may return no item even if
138        * there are available objects. This simply means the best object is
139        * already installed, and all available objects violate at least one
140        * update policy.
141        */
142       PoolItem updateCandidateObj() const
143       {
144         if ( multiversionInstall() || installedEmpty() || ! _defaultCandidate )
145           return _defaultCandidate;
146         // Here: installed and _defaultCandidate are non NULL and it's not a
147         //       multiversion install.
148
149         // update candidate must come from the highest priority repo
150         if ( _defaultCandidate->repoInfo().priority() != (*availableBegin())->repoInfo().priority() )
151           return PoolItem();
152
153         PoolItem installed( installedObj() );
154         // check vendor change
155         if ( ! ( ZConfig::instance().solver_allowVendorChange()
156                  || VendorAttr::instance().equivalent( _defaultCandidate->vendor(), installed->vendor() ) ) )
157           return PoolItem();
158
159         // check arch change (arch noarch changes are allowed)
160         if ( _defaultCandidate->arch() != installed->arch()
161            && ! ( _defaultCandidate->arch() == Arch_noarch || installed->arch() == Arch_noarch ) )
162           return PoolItem();
163
164         // check greater edition
165         if ( _defaultCandidate->edition() <= installed->edition() )
166           return PoolItem();
167
168         return _defaultCandidate;
169       }
170
171       /** \copydoc Selectable::highestAvailableVersionObj() */
172       PoolItem highestAvailableVersionObj() const
173       {
174         PoolItem ret;
175         for_( it, availableBegin(), availableEnd() )
176         {
177           if ( !ret || (*it).satSolvable().edition() > ret.satSolvable().edition() )
178             ret = *it;
179         }
180         return ret;
181       }
182
183       /** \c True if \a rhs has the same content as an installed one.
184        * \see \ref sat::Solvable::identical
185        */
186       bool identicalInstalled( const PoolItem & rhs ) const
187       {
188         if ( !installedEmpty() && rhs )
189         {
190           for_( it, _installedItems.begin(), _installedItems.end() )
191           {
192             if ( identical( *it, rhs ) )
193               return true;
194           }
195         }
196         return false;
197       }
198
199       /** Best among all objects. */
200       PoolItem theObj() const
201       {
202         PoolItem ret( candidateObj() );
203         if ( ret )
204           return ret;
205         return installedObj();
206       }
207
208       ////////////////////////////////////////////////////////////////////////
209
210       bool availableEmpty() const
211       { return _availableItems.empty(); }
212
213       available_size_type availableSize() const
214       { return _availableItems.size(); }
215
216       available_const_iterator availableBegin() const
217       { return _availableItems.begin(); }
218
219       available_const_iterator availableEnd() const
220       { return _availableItems.end(); }
221
222       ////////////////////////////////////////////////////////////////////////
223
224       bool installedEmpty() const
225       { return _installedItems.empty(); }
226
227       installed_size_type installedSize() const
228       { return _installedItems.size(); }
229
230       installed_iterator installedBegin() const
231       { return _installedItems.begin(); }
232
233       installed_iterator installedEnd() const
234       { return _installedItems.end(); }
235
236       ////////////////////////////////////////////////////////////////////////
237
238       bool isUnmaintained() const
239       { return availableEmpty(); }
240
241       bool multiversionInstall() const
242       { return theObj().satSolvable().multiversionInstall(); }
243
244       bool pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
245
246       bool pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
247
248       ////////////////////////////////////////////////////////////////////////
249
250       bool isUndetermined() const
251       {
252         PoolItem cand( candidateObj() );
253         return ! cand || cand.isUndetermined();
254       }
255       bool isRelevant() const
256       {
257         PoolItem cand( candidateObj() );
258         return cand && cand.isRelevant();
259       }
260       bool isSatisfied() const
261        {
262         PoolItem cand( candidateObj() );
263         return cand && cand.isSatisfied();
264       }
265       bool isBroken() const
266       {
267         PoolItem cand( candidateObj() );
268         return cand && cand.isBroken();
269       }
270
271       /** Return who caused the modification. */
272       ResStatus::TransactByValue modifiedBy() const;
273
274       /** Return value of LicenceConfirmed bit. */
275       bool hasLicenceConfirmed() const
276       { return candidateObj() && candidateObj().status().isLicenceConfirmed(); }
277
278       /** Set LicenceConfirmed bit. */
279       void setLicenceConfirmed( bool val_r )
280       { if ( candidateObj() ) candidateObj().status().setLicenceConfirmed( val_r ); }
281
282     private:
283       PoolItem transactingInstalled() const
284       {
285         for_( it, installedBegin(), installedEnd() )
286           {
287             if ( (*it).status().transacts() )
288               return (*it);
289           }
290         return PoolItem();
291       }
292
293       PoolItem transactingCandidate() const
294       {
295         for_( it, availableBegin(), availableEnd() )
296           {
297             if ( (*it).status().transacts() )
298               return (*it);
299           }
300         return PoolItem();
301       }
302
303       PoolItem defaultCandidate() const
304       {
305         if ( ! ( multiversionInstall() || installedEmpty() ) )
306         {
307           // prefer the installed objects arch and vendor
308           bool solver_allowVendorChange( ZConfig::instance().solver_allowVendorChange() );
309           for ( installed_const_iterator iit = installedBegin();
310                 iit != installedEnd(); ++iit )
311           {
312             PoolItem sameArch; // in case there's no same vendor at least stay with same arch.
313             for ( available_const_iterator it = availableBegin();
314                   it != availableEnd(); ++it )
315             {
316               // 'same arch' includes allowed changes to/from noarch.
317               if ( (*iit)->arch() == (*it)->arch() || (*iit)->arch() == Arch_noarch || (*it)->arch() == Arch_noarch )
318               {
319                 if ( ! solver_allowVendorChange )
320                 {
321                   if ( VendorAttr::instance().equivalent( (*iit), (*it) ) )
322                     return *it;
323                   else if ( ! sameArch ) // remember best same arch in case no same vendor found
324                      sameArch = *it;
325                 }
326                 else // same arch is sufficient
327                   return *it;
328               }
329             }
330             if ( sameArch )
331               return sameArch;
332           }
333         }
334         if ( _availableItems.empty() )
335           return PoolItem();
336
337         return *_availableItems.begin();
338       }
339
340       bool allCandidatesLocked() const
341       {
342         for ( available_const_iterator it = availableBegin();
343               it != availableEnd(); ++it )
344           {
345             if ( ! (*it).status().isLocked() )
346               return false;
347           }
348         return( ! _availableItems.empty() );
349       }
350
351     private:
352       const IdString         _ident;
353       const ResObject::Kind  _kind;
354       const std::string      _name;
355       InstalledItemSet       _installedItems;
356       AvailableItemSet       _availableItems;
357       //! Best among availabe with restpect to installed.
358       PoolItem               _defaultCandidate;
359
360       //! The object selected by setCandidateObj() method.
361       PoolItem               _candidate;
362     };
363     ///////////////////////////////////////////////////////////////////
364
365     /** \relates Selectable::Impl Stream output */
366     inline std::ostream & operator<<( std::ostream & str, const Selectable::Impl & obj )
367     {
368       return str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
369                  << " (I " << obj.installedSize() << ")"
370                  << " (A " << obj.availableSize() << ")"
371                  << obj.candidateObj();
372     }
373
374     /** \relates Selectable::Impl Stream output */
375     inline std::ostream & dumpOn( std::ostream & str, const Selectable::Impl & obj )
376     {
377       str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
378           << ( obj.multiversionInstall() ? " (multiversion)" : "") << endl;
379
380       if ( obj.installedEmpty() )
381         str << "   (I 0) {}" << endl << "   ";
382       else
383       {
384         PoolItem icand( obj.installedObj() );
385         str << "   (I " << obj.installedSize() << ") {" << endl;
386         for_( it, obj.installedBegin(), obj.installedEnd() )
387         {
388           char t = ' ';
389           if ( *it == icand )
390           {
391             t = 'i';
392           }
393           str << " " << t << " " << *it << endl;
394         }
395         str << "}  ";
396       }
397
398       if ( obj.availableEmpty() )
399       {
400         str << "(A 0) {}";
401       }
402       else
403       {
404         PoolItem cand( obj.candidateObj() );
405         PoolItem up( obj.updateCandidateObj() );
406         str << "(A " << obj.availableSize() << ") {" << endl;
407         for_( it, obj.availableBegin(), obj.availableEnd() )
408         {
409           char t = ' ';
410           if ( *it == cand )
411           {
412             t = *it == up ? 'C' : 'c';
413           }
414           else if ( *it == up )
415           {
416             t = 'u';
417           }
418           str << " " << t << " " << *it << endl;
419         }
420         str << "}  ";
421       }
422
423       return str;
424     }
425     /////////////////////////////////////////////////////////////////
426   } // namespace ui
427   ///////////////////////////////////////////////////////////////////
428   /////////////////////////////////////////////////////////////////
429 } // namespace zypp
430 ///////////////////////////////////////////////////////////////////
431 #endif // ZYPP_UI_SELECTABLEIMPL_H