Provide Selectable::identicalAvailable as counterpart to identicalInstalled.
[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()const */
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       /** \copydoc Selectable::identicalAvailable( const PoolItem & )const */
184       bool identicalAvailable( const PoolItem & rhs ) const
185       {
186         if ( !availableEmpty() && rhs )
187         {
188           for_( it, _availableItems.begin(), _availableItems.end() )
189           {
190             if ( identical( *it, rhs ) )
191               return true;
192           }
193         }
194         return false;
195       }
196
197       /** \copydoc Selectable::identicalInstalled( const PoolItem & )const */
198       bool identicalInstalled( const PoolItem & rhs ) const
199       {
200         if ( !installedEmpty() && rhs )
201         {
202           for_( it, _installedItems.begin(), _installedItems.end() )
203           {
204             if ( identical( *it, rhs ) )
205               return true;
206           }
207         }
208         return false;
209       }
210
211       /** Best among all objects. */
212       PoolItem theObj() const
213       {
214         PoolItem ret( candidateObj() );
215         if ( ret )
216           return ret;
217         return installedObj();
218       }
219
220       ////////////////////////////////////////////////////////////////////////
221
222       bool availableEmpty() const
223       { return _availableItems.empty(); }
224
225       available_size_type availableSize() const
226       { return _availableItems.size(); }
227
228       available_const_iterator availableBegin() const
229       { return _availableItems.begin(); }
230
231       available_const_iterator availableEnd() const
232       { return _availableItems.end(); }
233
234       ////////////////////////////////////////////////////////////////////////
235
236       bool installedEmpty() const
237       { return _installedItems.empty(); }
238
239       installed_size_type installedSize() const
240       { return _installedItems.size(); }
241
242       installed_iterator installedBegin() const
243       { return _installedItems.begin(); }
244
245       installed_iterator installedEnd() const
246       { return _installedItems.end(); }
247
248       ////////////////////////////////////////////////////////////////////////
249
250       bool isUnmaintained() const
251       { return availableEmpty(); }
252
253       bool multiversionInstall() const
254       { return theObj().satSolvable().multiversionInstall(); }
255
256       bool pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
257
258       bool pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r );
259
260       ////////////////////////////////////////////////////////////////////////
261
262       bool isUndetermined() const
263       {
264         PoolItem cand( candidateObj() );
265         return ! cand || cand.isUndetermined();
266       }
267       bool isRelevant() const
268       {
269         PoolItem cand( candidateObj() );
270         return cand && cand.isRelevant();
271       }
272       bool isSatisfied() const
273        {
274         PoolItem cand( candidateObj() );
275         return cand && cand.isSatisfied();
276       }
277       bool isBroken() const
278       {
279         PoolItem cand( candidateObj() );
280         return cand && cand.isBroken();
281       }
282
283       /** Return who caused the modification. */
284       ResStatus::TransactByValue modifiedBy() const;
285
286       /** Return value of LicenceConfirmed bit. */
287       bool hasLicenceConfirmed() const
288       { return candidateObj() && candidateObj().status().isLicenceConfirmed(); }
289
290       /** Set LicenceConfirmed bit. */
291       void setLicenceConfirmed( bool val_r )
292       { if ( candidateObj() ) candidateObj().status().setLicenceConfirmed( val_r ); }
293
294     private:
295       PoolItem transactingInstalled() const
296       {
297         for_( it, installedBegin(), installedEnd() )
298           {
299             if ( (*it).status().transacts() )
300               return (*it);
301           }
302         return PoolItem();
303       }
304
305       PoolItem transactingCandidate() const
306       {
307         for_( it, availableBegin(), availableEnd() )
308           {
309             if ( (*it).status().transacts() )
310               return (*it);
311           }
312         return PoolItem();
313       }
314
315       PoolItem defaultCandidate() const
316       {
317         if ( ! ( multiversionInstall() || installedEmpty() ) )
318         {
319           // prefer the installed objects arch and vendor
320           bool solver_allowVendorChange( ZConfig::instance().solver_allowVendorChange() );
321           for ( installed_const_iterator iit = installedBegin();
322                 iit != installedEnd(); ++iit )
323           {
324             PoolItem sameArch; // in case there's no same vendor at least stay with same arch.
325             for ( available_const_iterator it = availableBegin();
326                   it != availableEnd(); ++it )
327             {
328               // 'same arch' includes allowed changes to/from noarch.
329               if ( (*iit)->arch() == (*it)->arch() || (*iit)->arch() == Arch_noarch || (*it)->arch() == Arch_noarch )
330               {
331                 if ( ! solver_allowVendorChange )
332                 {
333                   if ( VendorAttr::instance().equivalent( (*iit), (*it) ) )
334                     return *it;
335                   else if ( ! sameArch ) // remember best same arch in case no same vendor found
336                      sameArch = *it;
337                 }
338                 else // same arch is sufficient
339                   return *it;
340               }
341             }
342             if ( sameArch )
343               return sameArch;
344           }
345         }
346         if ( _availableItems.empty() )
347           return PoolItem();
348
349         return *_availableItems.begin();
350       }
351
352       bool allCandidatesLocked() const
353       {
354         for ( available_const_iterator it = availableBegin();
355               it != availableEnd(); ++it )
356           {
357             if ( ! (*it).status().isLocked() )
358               return false;
359           }
360         return( ! _availableItems.empty() );
361       }
362
363     private:
364       const IdString         _ident;
365       const ResObject::Kind  _kind;
366       const std::string      _name;
367       InstalledItemSet       _installedItems;
368       AvailableItemSet       _availableItems;
369       //! Best among availabe with restpect to installed.
370       PoolItem               _defaultCandidate;
371
372       //! The object selected by setCandidateObj() method.
373       PoolItem               _candidate;
374     };
375     ///////////////////////////////////////////////////////////////////
376
377     /** \relates Selectable::Impl Stream output */
378     inline std::ostream & operator<<( std::ostream & str, const Selectable::Impl & obj )
379     {
380       return str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
381                  << " (I " << obj.installedSize() << ")"
382                  << " (A " << obj.availableSize() << ")"
383                  << obj.candidateObj();
384     }
385
386     /** \relates Selectable::Impl Stream output */
387     inline std::ostream & dumpOn( std::ostream & str, const Selectable::Impl & obj )
388     {
389       str << '[' << obj.kind() << ']' << obj.name() << ": " << obj.status()
390           << ( obj.multiversionInstall() ? " (multiversion)" : "") << endl;
391
392       if ( obj.installedEmpty() )
393         str << "   (I 0) {}" << endl << "   ";
394       else
395       {
396         PoolItem icand( obj.installedObj() );
397         str << "   (I " << obj.installedSize() << ") {" << endl;
398         for_( it, obj.installedBegin(), obj.installedEnd() )
399         {
400           char t = ' ';
401           if ( *it == icand )
402           {
403             t = 'i';
404           }
405           str << " " << t << " " << *it << endl;
406         }
407         str << "}  ";
408       }
409
410       if ( obj.availableEmpty() )
411       {
412         str << "(A 0) {}";
413       }
414       else
415       {
416         PoolItem cand( obj.candidateObj() );
417         PoolItem up( obj.updateCandidateObj() );
418         str << "(A " << obj.availableSize() << ") {" << endl;
419         for_( it, obj.availableBegin(), obj.availableEnd() )
420         {
421           char t = ' ';
422           if ( *it == cand )
423           {
424             t = *it == up ? 'C' : 'c';
425           }
426           else if ( *it == up )
427           {
428             t = 'u';
429           }
430           str << " " << t << " " << *it << endl;
431         }
432         str << "}  ";
433       }
434
435       return str;
436     }
437     /////////////////////////////////////////////////////////////////
438   } // namespace ui
439   ///////////////////////////////////////////////////////////////////
440   /////////////////////////////////////////////////////////////////
441 } // namespace zypp
442 ///////////////////////////////////////////////////////////////////
443 #endif // ZYPP_UI_SELECTABLEIMPL_H