libzypp  16.22.5
SelectableImpl.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 //#include "zypp/base/Logger.h"
14 
15 #include "zypp/ui/SelectableImpl.h"
16 
17 using std::endl;
18 
20 namespace zypp
21 {
22  namespace ui
24  {
25 
30  {
31  public:
33 
34  public:
36  ResStatus & backup( ResStatus & status_r )
37  {
38  _backup.push_back( status_r );
39  return status_r;
40  }
42  ResStatus & backup( const PoolItem & pi_r )
43  { return backup( pi_r.status() ); }
44 
46  ResStatus & operator()( ResStatus & status_r )
47  { return backup( status_r ); }
49  ResStatus & operator()( const PoolItem & pi_r )
50  { return backup( pi_r.status() ); }
51 
53  bool restore()
54  {
55  for_( rit, _backup.rbegin(), _backup.rend() )
56  rit->replay();
57  return false; // restore is done on error - return restore();
58  }
59 
60  public:
62  bool setTransact( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
63  { return backup( pi_r ).setTransact( yesno_r, causer_r ); }
64 
66  bool setLock( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
67  { return backup( pi_r ).setLock( yesno_r, causer_r ); }
68 
70  bool setTransactTrue( const PoolItem & pi_r, Causer causer_r )
71  { return setTransact( pi_r, true, causer_r ); }
72 
74  bool setTransactFalse( const PoolItem & pi_r, Causer causer_r )
75  { return setTransact( pi_r, false, causer_r ); }
76 
77  public:
79  bool transact( const PoolItem & pi_r, Causer causer_r )
80  {
81  ResStatus & status( backup( pi_r ) );
82  if ( ! status.setLock( false, causer_r ) ) return false;
83  if ( ! status.setTransact( true, causer_r ) ) return false;
84  return true;
85  }
86 
88  bool lock( const PoolItem & pi_r, Causer causer_r )
89  {
90  ResStatus & status( backup( pi_r ) );
91  if ( ! status.setTransact( false, causer_r ) ) return false;
92  if ( ! status.setLock( true, causer_r ) ) return false;
93  return true;
94  }
95 
97  bool unlock( const PoolItem & pi_r, Causer causer_r )
98  {
99  ResStatus & status( backup( pi_r ) );
100  if ( ! status.setTransact( false, causer_r ) ) return false;
101  if ( ! status.setLock( false, causer_r ) ) return false;
102  return true;
103  }
104 
106  bool unsetNonMultiTransact( const PoolItem & pi_r, Causer causer_r )
107  {
108  ResStatus & status( backup( pi_r ) );
109  if ( status.transacts() && ! pi_r.multiversionInstall() )
110  {
111  if ( ! status.setTransact( false, causer_r ) ) return false;
112  }
113  return true;
114  }
115 
117  bool unsetMultiTransact( const PoolItem & pi_r, Causer causer_r )
118  {
119  ResStatus & status( backup( pi_r ) );
120  if ( status.transacts() && pi_r.multiversionInstall() )
121  {
122  if ( ! status.setTransact( false, causer_r ) ) return false;
123  }
124  return true;
125  }
126 
128  typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
129 
131  template <class TIter>
132  bool forEach( TIter begin_r, TIter end_r, Action action_r, Causer causer_r )
133  {
134  for_( it, begin_r, end_r )
135  if ( ! (this->*action_r)( *it, causer_r ) )
136  return false;
137  return true;
138  }
139 
140  private:
141  std::vector<resstatus::StatusBackup> _backup;
142  };
143 
145  //
146  // CLASS NAME : StatusHelper
147  //
151  {
153  : _impl( impl )
154  , inst( impl.installedObj() )
155  , cand( impl.candidateObj() )
156  , causer( causer_r )
157  {}
158 
160 
161  //
162  // Queries
163  //
164  bool hasInstalled() const
165  { return bool(inst); }
166 
167  bool hasCandidate() const
168  { return bool(cand); }
169 
170  bool hasInstalledOnly() const
171  { return inst && !cand; }
172 
173  bool hasCandidateOnly() const
174  { return cand && !inst; }
175 
176  bool hasBoth() const
177  { return inst && cand; }
178 
181  bool setInstall()
182  {
183  if ( cand )
184  {
185  if ( inst ) {
187  {
188  ResStatus & inststatus( backup( it->status() ) );
189  if ( ! inststatus.setTransact( false, causer ) ) return restore();
190  if ( ! inststatus.setLock ( false, causer ) ) return restore();
191  if ( ! cand->multiversionInstall() )
192  {
193  // This is what the solver most probabely will do.
194  // If we are wrong the solver will correct it. But
195  // this way we will get a better disk usage result,
196  // even if no autosolving is on.
197  inststatus.setTransact( true, ResStatus::SOLVER );
198  }
199  }
200  }
201  if ( ! unlockCandidates() ) return restore();
202  ResStatus & candstatus( backup( cand.status() ) );
203  if ( ! candstatus.setTransact( true, causer ) ) return restore();
204  return true;
205  }
206  return false;
207  }
208 
209  bool setDelete()
210  {
211  if ( inst )
212  {
213  if ( ! resetTransactingCandidates() ) return restore();
215  {
216  ResStatus & inststatus( backup( it->status() ) );
217  if ( ! inststatus.setLock( false, causer ) ) return restore();
218  if ( ! inststatus.setTransact( true, causer ) ) return restore();
219  }
220  return true;
221  }
222  return false;
223  }
224 
225  bool unset()
226  {
227  if ( inst )
228  {
230  {
231  ResStatus & inststatus( backup( it->status() ) );
232  if ( ! inststatus.setTransact( false, causer ) ) return restore();
233  if ( ! inststatus.setLock( false, causer ) ) return restore();
234  }
235  }
236  if ( ! unlockCandidates() ) return restore();
237  return true;
238  }
239 
241  {
242  if ( causer != ResStatus::USER ) // by user only
243  return false;
244 
245  if ( inst ) {
248  {
249  it->status().setTransact( false, causer );
250  it->status().setLock( true, causer );
251  }
252  return true;
253  } else
254  return false;
255  }
256 
257  bool setTaboo()
258  {
259  if ( causer != ResStatus::USER ) // by user only
260  return false;
261 
262  if ( cand ) {
263  lockCandidates();
264  return true;
265  } else
266  return false;
267  }
269 
270  private:
274  {
276  {
277  ResStatus & status( backup( (*it).status() ) );
278  if ( ! status.setTransact( false, causer ) ) return false;
279  }
280  return true;
281  }
283  {
285  {
286  ResStatus & status( backup( (*it).status() ) );
287  if ( ! status.setTransact( false, causer ) ) return false;
288  if ( ! status.setLock( false, causer ) ) return false;
289  }
290  return true;
291  }
293  {
295  {
296  ResStatus & status( backup( (*it).status() ) );
297  if ( ! status.setTransact( false, causer ) ) return false;
298  if ( ! status.setLock( true, causer ) ) return false;
299  }
300  return true;
301  }
303 
304  private:
309 
310  private:
311  bool restore() { return backup.restore(); }
313  };
315 
317  //
318  // CLASS NAME : Selectable::Impl
319  //
321 
323  {
324  PoolItem cand( candidateObj() );
325  if ( cand && cand.status().transacts() )
326  {
327  if ( cand.status().isByUser() )
328  return( installedObj() ? S_Update : S_Install );
329  else
330  return( installedObj() ? S_AutoUpdate : S_AutoInstall );
331  }
332 
333  if ( installedObj() && installedObj().status().transacts() )
334  {
335  return( installedObj().status().isByUser() ? S_Del : S_AutoDel );
336  }
337 
338  if ( installedObj() && allInstalledLocked() )
339  return S_Protected;
340 
341  if ( !installedObj() && allCandidatesLocked() )
342  return S_Taboo;
343 
344  // KEEP state:
345  if ( installedObj() )
346  return S_KeepInstalled;
347  // Report pseudo installed items as installed, if they are satisfied.
349  && cand.status().isSatisfied() ) // no installed, so we must have candidate
350  return S_KeepInstalled;
351 
352  return S_NoInst;
353  }
354 
356  {
357  StatusHelper self( *this, causer_r );
358 
359  switch ( state_r )
360  {
361  case S_Protected:
362  return self.setProtected();
363  case S_Taboo:
364  return self.setTaboo();
365  case S_AutoDel:
366  case S_AutoInstall:
367  case S_AutoUpdate:
368  // Auto level is SOLVER level. UI may query, but not
369  // set at this level.
370  break;
371 
372  case S_Del:
373  return self.setDelete();
374  break;
375 
376  case S_Install:
377  return self.hasCandidateOnly() && self.setInstall();
378  break;
379 
380  case S_Update:
381  return self.hasBoth() && self.setInstall();
382  break;
383 
384  case S_KeepInstalled:
385  return self.hasInstalled() && self.unset();
386  break;
387 
388  case S_NoInst:
389  return !self.hasInstalled() && self.unset();
390  break;
391  }
392 
393  return false;
394  }
395 
397  {
398  PoolItem newCandidate;
399 
400  if ( newCandidate_r ) // must be in available list
401  {
402  for_( it, availableBegin(), availableEnd() )
403  {
404  if ( *it == newCandidate_r )
405  {
406  newCandidate = *it;
407  break;
408  }
409  }
410  }
411 
412  if ( newCandidate )
413  {
414  PoolItem trans( transactingCandidate() );
415  if ( trans && trans != newCandidate )
416  {
417  // adjust transact to the new cancidate
418  if ( trans.status().maySetTransact( false, causer_r )
419  && newCandidate.status().maySetTransact( true, causer_r ) )
420  {
421  trans.status().setTransact( false, causer_r );
422  newCandidate.status().setTransact( true, causer_r );
423  }
424  else
425  {
426  // No permission to change a transacting candidate.
427  // Leave _candidate untouched and return NULL.
428  return PoolItem();
429  }
430  }
431  }
432 
433  return _candidate = newCandidate;
434  }
435 
437 
438  bool Selectable::Impl::pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
439  {
440  if ( identicalInstalled( pi_r ) )
441  return setPickStatus( pi_r, ( yesno_r ? S_Update : S_KeepInstalled ), causer_r );
442  return setPickStatus( pi_r, ( yesno_r ? S_Install : S_NoInst ), causer_r );
443  }
444 
445  bool Selectable::Impl::pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
446  {
447  return setPickStatus( pi_r, ( yesno_r ? S_Del : S_KeepInstalled ), causer_r );
448  }
449 
451  {
452  if ( pi_r.ident() != ident() )
453  return false; // not my PoolItem
454 
455  StatusBackup backup;
456  std::vector<PoolItem> i;
457  std::vector<PoolItem> a;
458 
459  for_( it, installedBegin(), installedEnd() )
460  if ( identical( *it, pi_r ) )
461  i.push_back( *it );
462  for_( it, availableBegin(), availableEnd() )
463  if ( identical( *it, pi_r ) )
464  a.push_back( *it );
465 
466  switch ( state_r )
467  {
468  case S_Protected:
469  if ( causer_r == ResStatus::USER && ! i.empty() )
470  {
471  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
472  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
473  return true;
474  }
475  break;
476 
477  case S_Taboo:
478  if ( causer_r == ResStatus::USER && ! a.empty() )
479  {
480  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
481  return true;
482  }
483  break;
484 
485  case S_AutoDel:
486  case S_AutoInstall:
487  case S_AutoUpdate:
488  // Auto level is SOLVER level. UI may query, but not
489  // set at this level.
490  break;
491 
492  case S_Del:
493  if ( ! i.empty() )
494  {
495  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::transact, causer_r ) ) return backup.restore();
496  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
497  return true;
498  }
499  break;
500 
501  case S_Install:
502  if ( i.empty() && ! a.empty() )
503  {
504  const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
505  if ( cand.multiversionInstall() )
506  {
507  if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetNonMultiTransact, causer_r ) ) return backup.restore();
508  // maybe unlock candidate only?
509  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
510  if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
511  return true;
512  }
513  else
514  {
515  // For non-multiversion use ordinary setStatus
516  // NOTE that S_Update/S_Install here depends on !installedEmpty()
517  // and not on picklists identicalInstalled.
518  if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetMultiTransact, causer_r ) ) return backup.restore();
519  if ( ! setCandidate( cand, causer_r ) ) return backup.restore();
520  if ( ! setStatus( installedEmpty() ? S_Install : S_Update, causer_r ) ) return backup.restore();
521  return true;
522  }
523  }
524  break;
525 
526  case S_Update:
527  if ( ! i.empty() && ! a.empty() )
528  {
529  const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
530  if ( cand.multiversionInstall() )
531  {
532  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
533  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
534  if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetNonMultiTransact, causer_r ) ) return backup.restore();
535  // maybe unlock candidate only?
536  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
537  if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
538  return true;
539  }
540  else
541  {
542  // For non-multiversion use ordinary setStatus
543  // NOTE that S_Update/S_Install here depends on !installedEmpty()
544  // and not on picklists identicalInstalled.
545  if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetMultiTransact, causer_r ) ) return backup.restore();
546  if ( ! setCandidate( cand, causer_r ) ) return backup.restore();
547  if ( ! setStatus( installedEmpty() ? S_Install : S_Update, causer_r ) ) return backup.restore();
548  return true;
549  }
550  }
551  break;
552 
553  case S_KeepInstalled:
554  if ( ! i.empty() )
555  {
556  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
557  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
558  return true;
559  }
560  break;
561 
562  case S_NoInst:
563  if ( i.empty() )
564  {
565  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
566  return true;
567  }
568  break;
569  }
570  return false;
571  }
572 
574  {
575  if ( pi_r.satSolvable().ident() != ident() )
576  return Status(-1); // not my PoolItem
577 
578  std::vector<PoolItem> i;
579  std::vector<PoolItem> a;
580  PoolItem ti;
581  PoolItem ta;
582 
583  for_( it, installedBegin(), installedEnd() )
584  if ( identical( *it, pi_r ) )
585  {
586  i.push_back( *it );
587  if ( ! ti && it->status().transacts() )
588  ti = *it;
589  }
590 
591  for_( it, availableBegin(), availableEnd() )
592  if ( identical( *it, pi_r ) )
593  {
594  a.push_back( *it );
595  if ( ! ta && it->status().transacts() )
596  ta = *it;
597  }
598 
599  if ( ta )
600  {
601  if ( ta.status().isByUser() )
602  return( i.empty() ? S_Install : S_Update );
603  else
604  return( i.empty() ? S_AutoInstall : S_AutoUpdate );
605  }
606 
607  if ( ti )
608  {
609  return( ti.status().isByUser() ? S_Del : S_AutoDel );
610  }
611 
612  for_( it, i.begin(), i.end() )
613  if ( it->status().isLocked() )
614  return S_Protected;
615 
616  if ( i.empty() )
617  {
618  bool allALocked = true;
619  for_( it, a.begin(), a.end() )
620  if ( ! it->status().isLocked() )
621  {
622  allALocked = false;
623  break;
624  }
625  if ( allALocked )
626  return S_Taboo;
627  }
628 
629  // KEEP state:
630  if ( ! i.empty() )
631  return S_KeepInstalled;
632  // Report pseudo installed items as installed, if they are satisfied.
634  && ( ta ? ta : *a.begin() ).status().isSatisfied() ) // no installed, so we must have candidate
635  return S_KeepInstalled;
636 
637  return S_NoInst;
638  }
639 
641 
643  {
644  PoolItem cand( candidateObj() );
645  if ( cand && cand.status().transacts() )
646  return cand.status().getTransactByValue();
647 
648  if ( installedObj() && installedObj().status().transacts() )
650 
651  if ( cand )
652  return cand.status().getTransactByValue();
653 
654  if ( installedObj() )
656 
657  return ResStatus::SOLVER;
658  }
659 
661  } // namespace ui
664 } // namespace zypp
ResStatus::TransactByValue Causer
available_iterator availableEnd() const
Definition: Selectable.cc:127
ResStatus::TransactByValue modifiedBy() const
Return who caused the modification.
IdString ident() const
The identifier.
Definition: Selectable.cc:55
installed_iterator installedEnd() const
Definition: Selectable.cc:141
Status
UI status Status values calculated by Selectable.
Definition: Status.h:34
bool transacts() const
Definition: ResStatus.h:267
bool hasCandidate() const
IdString ident() const
The identifier.
Definition: Solvable.cc:269
bool unsetNonMultiTransact(const PoolItem &pi_r, Causer causer_r)
highlevel remove transact from non-multiversion packages.
bool transact(const PoolItem &pi_r, Causer causer_r)
highevel set transact (force unlock).
PoolItem installedObj() const
The last Installed object.
Definition: Selectable.cc:70
PoolItem setCandidate(const PoolItem &newCandidate_r, ResStatus::TransactByValue causer_r=ResStatus::USER)
Set a candidate (out of available objects).
Definition: Selectable.cc:100
bool setStatus(Status state_r, ResStatus::TransactByValue causer_r)
bool setLock(const PoolItem &pi_r, bool yesno_r, Causer causer_r)
lowlevel ResStatus::setLock
Status pickStatus(const PoolItem &pi_r) const
bool setTransactTrue(const PoolItem &pi_r, Causer causer_r)
lowlevel ResStatus::setTransact(true).
bool allCandidatesLocked() const
Status status() const
Return the current Status.
Definition: Selectable.cc:64
bool hasInstalledOnly() const
ResStatus & backup(const PoolItem &pi_r)
Simple ResStatus backup stack.
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
PoolItem candidateObj() const
Best among available objects.
bool multiversionInstall() const
Definition: SolvableType.h:82
bool isSatisfied() const
Definition: ResStatus.h:219
bool isInstalled() const
Definition: ResStatus.h:231
PoolItem setCandidate(const PoolItem &newCandidate_r, ResStatus::TransactByValue causer_r)
Set a userCandidate (out of available objects).
bool setStatus(Status state_r, ResStatus::TransactByValue causer_r=ResStatus::USER)
Try to set a new Status.
Definition: Selectable.cc:67
bool unsetMultiTransact(const PoolItem &pi_r, Causer causer_r)
highlevel remove transact from multiversion packages.
std::vector< resstatus::StatusBackup > _backup
bool hasCandidateOnly() const
ResStatus & operator()(const PoolItem &pi_r)
bool identicalInstalled(const PoolItem &rhs) const
True if rhs has the same content as an installed one.
Definition: Selectable.cc:91
bool isByUser() const
Definition: ResStatus.h:290
bool maySetTransact(bool val_r, TransactByValue causer)
Definition: ResStatus.h:455
bool identical(const SolvableType< Derived > &lhs, const Solvable &rhs)
Definition: SolvableType.h:220
ResStatus::TransactByValue causer
available_iterator availableBegin() const
Definition: Selectable.cc:124
const Selectable::Impl & _impl
SelectableTraits::available_const_iterator available_const_iterator
ResStatus & backup(ResStatus &status_r)
Backup status.
ResStatus & status() const
Returns the current status.
Definition: PoolItem.cc:204
installed_iterator installedBegin() const
bool setLock(bool toLock_r, TransactByValue causer_r)
Apply a lock (prevent transaction).
Definition: ResStatus.h:379
StatusHelper(const Selectable::Impl &impl, ResStatus::TransactByValue causer_r)
Selectable::Impl::available_const_iterator available_const_iterator
bool lock(const PoolItem &pi_r, Causer causer_r)
highlevel set locked.
bool isPseudoInstalled(ResKind kind_r)
Those are denoted to be installed, if the solver verifies them as being satisfied.
Definition: ResTraits.h:28
PoolItem installedObj() const
Installed object (transacting ot highest version).
bool setPickStatus(const PoolItem &pi_r, Status state_r, ResStatus::TransactByValue causer_r=ResStatus::USER)
Assign a new status to a specific item.
Definition: Selectable.cc:194
bool allInstalledLocked() const
bool installedEmpty() const
Definition: Selectable.cc:132
PoolItem candidateObj() const
The 'best' or 'most interesting' among all available objects.
Definition: Selectable.cc:73
bool setTransact(bool toTansact_r, TransactByValue causer_r)
Toggle between TRANSACT and KEEP_STATE.
Definition: ResStatus.h:424
bool forEach(TIter begin_r, TIter end_r, Action action_r, Causer causer_r)
Highlevel action on range of items.
available_iterator availableBegin() const
Selectable implementation.
available_iterator availableEnd() const
ResKind kind() const
The ResObjects kind.
Definition: Selectable.cc:58
Solvable satSolvable() const
Return the corresponding sat::Solvable.
Definition: SolvableType.h:57
bool(StatusBackup::* Action)(const PoolItem &, Causer)
Highlevel action.
bool restore()
Restore all status.
IdString ident() const
Definition: SolvableType.h:61
Status bitfield.
Definition: ResStatus.h:53
installed_iterator installedEnd() const
bool unlock(const PoolItem &pi_r, Causer causer_r)
highlevel unlock (also unsets transact).
Combining sat::Solvable and ResStatus.
Definition: PoolItem.h:50
bool setPickStatus(const PoolItem &pi_r, Status state_r, ResStatus::TransactByValue causer_r)
bool setTransact(const PoolItem &pi_r, bool yesno_r, Causer causer_r)
lowlevel ResStatus::setTransact
bool pickInstall(const PoolItem &pi_r, ResStatus::TransactByValue causer_r, bool yesno_r)
bool hasInstalled() const
bool setTransactFalse(const PoolItem &pi_r, Causer causer_r)
lowlevel ResStatus::setTransact(false).
ResStatus & operator()(ResStatus &status_r)
Backup status.
bool pickDelete(const PoolItem &pi_r, ResStatus::TransactByValue causer_r, bool yesno_r)
TransactByValue getTransactByValue() const
Definition: ResStatus.h:293
installed_iterator installedBegin() const
Definition: Selectable.cc:138