libzypp  11.13.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 
23  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  typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
107 
109  template <class _Iter>
110  bool forEach( _Iter begin_r, _Iter end_r, Action action_r, Causer causer_r )
111  {
112  for_( it, begin_r, end_r )
113  if ( ! (this->*action_r)( *it, causer_r ) )
114  return false;
115  return true;
116  }
117 
118  private:
119  std::vector<resstatus::StatusBackup> _backup;
120  };
121 
123  //
124  // CLASS NAME : StatusHelper
125  //
129  {
131  : _impl( impl )
132  , inst( impl.installedObj() )
133  , cand( impl.candidateObj() )
134  , causer( causer_r )
135  {}
136 
138 
139  //
140  // Queries
141  //
142  bool hasInstalled() const
143  { return inst; }
144 
145  bool hasCandidate() const
146  { return cand; }
147 
148  bool hasInstalledOnly() const
149  { return inst && !cand; }
150 
151  bool hasCandidateOnly() const
152  { return cand && !inst; }
153 
154  bool hasBoth() const
155  { return inst && cand; }
156 
159  bool setInstall()
160  {
161  if ( cand )
162  {
163  if ( inst ) {
165  {
166  ResStatus & inststatus( backup( it->status() ) );
167  if ( ! inststatus.setTransact( false, causer ) ) return restore();
168  if ( ! inststatus.setLock ( false, causer ) ) return restore();
169  if ( ! cand->multiversionInstall() )
170  {
171  // This is what the solver most probabely will do.
172  // If we are wrong the solver will correct it. But
173  // this way we will get a better disk usage result,
174  // even if no autosolving is on.
175  inststatus.setTransact( true, ResStatus::SOLVER );
176  }
177  }
178  }
179  if ( ! unlockCandidates() ) return restore();
180  ResStatus & candstatus( backup( cand.status() ) );
181  if ( ! candstatus.setTransact( true, causer ) ) return restore();
182  return true;
183  }
184  return false;
185  }
186 
187  bool setDelete()
188  {
189  if ( inst )
190  {
191  if ( ! resetTransactingCandidates() ) return restore();
193  {
194  ResStatus & inststatus( backup( it->status() ) );
195  if ( ! inststatus.setLock( false, causer ) ) return restore();
196  if ( ! inststatus.setTransact( true, causer ) ) return restore();
197  }
198  return true;
199  }
200  return false;
201  }
202 
203  bool unset()
204  {
205  if ( inst )
206  {
208  {
209  ResStatus & inststatus( backup( it->status() ) );
210  if ( ! inststatus.setTransact( false, causer ) ) return restore();
211  if ( ! inststatus.setLock( false, causer ) ) return restore();
212  }
213  }
214  if ( ! unlockCandidates() ) return restore();
215  return true;
216  }
217 
219  {
220  if ( causer != ResStatus::USER ) // by user only
221  return false;
222 
223  if ( inst ) {
226  {
227  it->status().setTransact( false, causer );
228  it->status().setLock( true, causer );
229  }
230  return true;
231  } else
232  return false;
233  }
234 
235  bool setTaboo()
236  {
237  if ( causer != ResStatus::USER ) // by user only
238  return false;
239 
240  if ( cand ) {
241  lockCandidates();
242  return true;
243  } else
244  return false;
245  }
247 
248  private:
252  {
254  {
255  ResStatus & status( backup( (*it).status() ) );
256  if ( ! status.setTransact( false, causer ) ) return false;
257  }
258  return true;
259  }
261  {
263  {
264  ResStatus & status( backup( (*it).status() ) );
265  if ( ! status.setTransact( false, causer ) ) return false;
266  if ( ! status.setLock( false, causer ) ) return false;
267  }
268  return true;
269  }
271  {
273  {
274  ResStatus & status( backup( (*it).status() ) );
275  if ( ! status.setTransact( false, causer ) ) return false;
276  if ( ! status.setLock( true, causer ) ) return false;
277  }
278  return true;
279  }
281 
282  private:
287 
288  private:
289  bool restore() { return backup.restore(); }
291  };
293 
295  //
296  // CLASS NAME : Selectable::Impl
297  //
299 
301  {
302  PoolItem cand( candidateObj() );
303  if ( cand && cand.status().transacts() )
304  {
305  if ( cand.status().isByUser() )
306  return( installedObj() ? S_Update : S_Install );
307  else
308  return( installedObj() ? S_AutoUpdate : S_AutoInstall );
309  }
310 
311  if ( installedObj() && installedObj().status().transacts() )
312  {
313  return( installedObj().status().isByUser() ? S_Del : S_AutoDel );
314  }
315 
316  if ( installedObj() && allInstalledLocked() )
317  return S_Protected;
318 
319  if ( !installedObj() && allCandidatesLocked() )
320  return S_Taboo;
321 
322  // KEEP state:
323  if ( installedObj() )
324  return S_KeepInstalled;
325  // Report pseudo installed items as installed, if they are satisfied.
327  && cand.status().isSatisfied() ) // no installed, so we must have candidate
328  return S_KeepInstalled;
329 
330  return S_NoInst;
331  }
332 
334  {
335  StatusHelper self( *this, causer_r );
336 
337  switch ( state_r )
338  {
339  case S_Protected:
340  return self.setProtected();
341  case S_Taboo:
342  return self.setTaboo();
343  case S_AutoDel:
344  case S_AutoInstall:
345  case S_AutoUpdate:
346  // Auto level is SOLVER level. UI may query, but not
347  // set at this level.
348  break;
349 
350  case S_Del:
351  return self.setDelete();
352  break;
353 
354  case S_Install:
355  return self.hasCandidateOnly() && self.setInstall();
356  break;
357 
358  case S_Update:
359  return self.hasBoth() && self.setInstall();
360  break;
361 
362  case S_KeepInstalled:
363  return self.hasInstalled() && self.unset();
364  break;
365 
366  case S_NoInst:
367  return !self.hasInstalled() && self.unset();
368  break;
369  }
370 
371  return false;
372  }
373 
375  {
376  PoolItem newCandidate;
377 
378  if ( newCandidate_r ) // must be in available list
379  {
380  for_( it, availableBegin(), availableEnd() )
381  {
382  if ( *it == newCandidate_r )
383  {
384  newCandidate = *it;
385  break;
386  }
387  }
388  }
389 
390  if ( newCandidate )
391  {
392  PoolItem trans( transactingCandidate() );
393  if ( trans && trans != newCandidate )
394  {
395  // adjust transact to the new cancidate
396  if ( trans.status().maySetTransact( false, causer_r )
397  && newCandidate.status().maySetTransact( true, causer_r ) )
398  {
399  trans.status().setTransact( false, causer_r );
400  newCandidate.status().setTransact( true, causer_r );
401  }
402  else
403  {
404  // No permission to change a transacting candidate.
405  // Leave _candidate untouched and return NULL.
406  return PoolItem();
407  }
408  }
409  }
410 
411  return _candidate = newCandidate;
412  }
413 
415 
416  bool Selectable::Impl::pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
417  {
418  if ( identicalInstalled( pi_r ) )
419  return setPickStatus( pi_r, ( yesno_r ? S_Update : S_KeepInstalled ), causer_r );
420  return setPickStatus( pi_r, ( yesno_r ? S_Install : S_NoInst ), causer_r );
421  }
422 
423  bool Selectable::Impl::pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
424  {
425  return setPickStatus( pi_r, ( yesno_r ? S_Del : S_KeepInstalled ), causer_r );
426  }
427 
429  {
430  if ( pi_r.satSolvable().ident() != ident() )
431  return false; // not my PoolItem
432 
433  if ( ! multiversionInstall() )
434  return false; // We're not yet ready for this.
435  // TODO: Without multiversionInstall take care at most ONE available is set
436  // to install. Upon install ALL installed get deleted. Only upon deletetion
437  // one might pick individual versions (but more than one would be an error here).
438 
439  StatusBackup backup;
440  std::vector<PoolItem> i;
441  std::vector<PoolItem> a;
442 
443  for_( it, installedBegin(), installedEnd() )
444  if ( identical( *it, pi_r ) )
445  i.push_back( *it );
446  for_( it, availableBegin(), availableEnd() )
447  if ( identical( *it, pi_r ) )
448  a.push_back( *it );
449 
450  switch ( state_r )
451  {
452  case S_Protected:
453  if ( causer_r == ResStatus::USER && ! i.empty() )
454  {
455  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
456  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
457  return true;
458  }
459  break;
460 
461  case S_Taboo:
462  if ( causer_r == ResStatus::USER && ! a.empty() )
463  {
464  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
465  return true;
466  }
467  break;
468 
469  case S_AutoDel:
470  case S_AutoInstall:
471  case S_AutoUpdate:
472  // Auto level is SOLVER level. UI may query, but not
473  // set at this level.
474  break;
475 
476  case S_Del:
477  if ( ! i.empty() )
478  {
479  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::transact, causer_r ) ) return backup.restore();
480  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
481  return true;
482  }
483  break;
484 
485  case S_Install:
486  if ( i.empty() && ! a.empty() )
487  {
488  // maybe unlock candidate only?
489  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
490  const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
491  if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
492  return true;
493  }
494  break;
495 
496  case S_Update:
497  if ( ! i.empty() && ! a.empty() )
498  {
499  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
500  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
501  // maybe unlock candidate only?
502  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
503  const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
504  if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
505  return true;
506  }
507  break;
508 
509  case S_KeepInstalled:
510  if ( ! i.empty() )
511  {
512  if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
513  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
514  return true;
515  }
516  break;
517 
518  case S_NoInst:
519  if ( i.empty() )
520  {
521  if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
522  return true;
523  }
524  break;
525  }
526  return false;
527  }
528 
530  {
531  if ( pi_r.satSolvable().ident() != ident() )
532  return Status(-1); // not my PoolItem
533 
534  std::vector<PoolItem> i;
535  std::vector<PoolItem> a;
536  PoolItem ti;
537  PoolItem ta;
538 
539  for_( it, installedBegin(), installedEnd() )
540  if ( identical( *it, pi_r ) )
541  {
542  i.push_back( *it );
543  if ( ! ti && it->status().transacts() )
544  ti = *it;
545  }
546 
547  for_( it, availableBegin(), availableEnd() )
548  if ( identical( *it, pi_r ) )
549  {
550  a.push_back( *it );
551  if ( ! ta && it->status().transacts() )
552  ta = *it;
553  }
554 
555  if ( ta )
556  {
557  if ( ta.status().isByUser() )
558  return( i.empty() ? S_Install : S_Update );
559  else
560  return( i.empty() ? S_AutoInstall : S_AutoUpdate );
561  }
562 
563  if ( ti )
564  {
565  return( ti.status().isByUser() ? S_Del : S_AutoDel );
566  }
567 
568  for_( it, i.begin(), i.end() )
569  if ( it->status().isLocked() )
570  return S_Protected;
571 
572  if ( i.empty() )
573  {
574  bool allALocked = true;
575  for_( it, a.begin(), a.end() )
576  if ( ! it->status().isLocked() )
577  {
578  allALocked = false;
579  break;
580  }
581  if ( allALocked )
582  return S_Taboo;
583  }
584 
585  // KEEP state:
586  if ( ! i.empty() )
587  return S_KeepInstalled;
588  // Report pseudo installed items as installed, if they are satisfied.
590  && ( ta ? ta : *a.begin() ).status().isSatisfied() ) // no installed, so we must have candidate
591  return S_KeepInstalled;
592 
593  return S_NoInst;
594  }
595 
597 
599  {
600  PoolItem cand( candidateObj() );
601  if ( cand && cand.status().transacts() )
602  return cand.status().getTransactByValue();
603 
604  if ( installedObj() && installedObj().status().transacts() )
606 
607  if ( cand )
608  return cand.status().getTransactByValue();
609 
610  if ( installedObj() )
612 
613  return ResStatus::SOLVER;
614  }
615 
617  } // namespace ui
620 } // namespace zypp