00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013
00014
00015 #include "zypp/ui/SelectableImpl.h"
00016
00017 using std::endl;
00018
00020 namespace zypp
00021 {
00022
00023 namespace ui
00024 {
00025
00029 class StatusBackup
00030 {
00031 public:
00032 typedef ResStatus::TransactByValue Causer;
00033
00034 public:
00036 ResStatus & backup( ResStatus & status_r )
00037 {
00038 _backup.push_back( status_r );
00039 return status_r;
00040 }
00042 ResStatus & backup( const PoolItem & pi_r )
00043 { return backup( pi_r.status() ); }
00044
00046 ResStatus & operator()( ResStatus & status_r )
00047 { return backup( status_r ); }
00049 ResStatus & operator()( const PoolItem & pi_r )
00050 { return backup( pi_r.status() ); }
00051
00053 bool restore()
00054 {
00055 for_( rit, _backup.rbegin(), _backup.rend() )
00056 rit->replay();
00057 return false;
00058 }
00059
00060 public:
00062 bool setTransact( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
00063 { return backup( pi_r ).setTransact( yesno_r, causer_r ); }
00064
00066 bool setLock( const PoolItem & pi_r, bool yesno_r, Causer causer_r )
00067 { return backup( pi_r ).setLock( yesno_r, causer_r ); }
00068
00070 bool setTransactTrue( const PoolItem & pi_r, Causer causer_r )
00071 { return setTransact( pi_r, true, causer_r ); }
00072
00074 bool setTransactFalse( const PoolItem & pi_r, Causer causer_r )
00075 { return setTransact( pi_r, false, causer_r ); }
00076
00077 public:
00079 bool transact( const PoolItem & pi_r, Causer causer_r )
00080 {
00081 ResStatus & status( backup( pi_r ) );
00082 if ( ! status.setLock( false, causer_r ) ) return false;
00083 if ( ! status.setTransact( true, causer_r ) ) return false;
00084 return true;
00085 }
00086
00088 bool lock( const PoolItem & pi_r, Causer causer_r )
00089 {
00090 ResStatus & status( backup( pi_r ) );
00091 if ( ! status.setTransact( false, causer_r ) ) return false;
00092 if ( ! status.setLock( true, causer_r ) ) return false;
00093 return true;
00094 }
00095
00097 bool unlock( const PoolItem & pi_r, Causer causer_r )
00098 {
00099 ResStatus & status( backup( pi_r ) );
00100 if ( ! status.setTransact( false, causer_r ) ) return false;
00101 if ( ! status.setLock( false, causer_r ) ) return false;
00102 return true;
00103 }
00104
00106 typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
00107
00109 template <class _Iter>
00110 bool forEach( _Iter begin_r, _Iter end_r, Action action_r, Causer causer_r )
00111 {
00112 for_( it, begin_r, end_r )
00113 if ( ! (this->*action_r)( *it, causer_r ) )
00114 return false;
00115 return true;
00116 }
00117
00118 private:
00119 std::vector<resstatus::StatusBackup> _backup;
00120 };
00121
00123
00124
00125
00128 struct StatusHelper
00129 {
00130 StatusHelper( const Selectable::Impl & impl, ResStatus::TransactByValue causer_r )
00131 : _impl( impl )
00132 , inst( impl.installedObj() )
00133 , cand( impl.candidateObj() )
00134 , causer( causer_r )
00135 {}
00136
00137 typedef Selectable::Impl::available_const_iterator available_const_iterator;
00138
00139
00140
00141
00142 bool hasInstalled() const
00143 { return inst; }
00144
00145 bool hasCandidate() const
00146 { return cand; }
00147
00148 bool hasInstalledOnly() const
00149 { return inst && !cand; }
00150
00151 bool hasCandidateOnly() const
00152 { return cand && !inst; }
00153
00154 bool hasBoth() const
00155 { return inst && cand; }
00156
00159 bool setInstall()
00160 {
00161 if ( cand )
00162 {
00163 if ( inst ) {
00164 for_( it, _impl.installedBegin(), _impl.installedEnd() )
00165 {
00166 ResStatus & inststatus( backup( it->status() ) );
00167 if ( ! inststatus.setTransact( false, causer ) ) return restore();
00168 if ( ! inststatus.setLock ( false, causer ) ) return restore();
00169 if ( ! cand->multiversionInstall() )
00170 {
00171
00172
00173
00174
00175 inststatus.setTransact( true, ResStatus::SOLVER );
00176 }
00177 }
00178 }
00179 if ( ! unlockCandidates() ) return restore();
00180 ResStatus & candstatus( backup( cand.status() ) );
00181 if ( ! candstatus.setTransact( true, causer ) ) return restore();
00182 return true;
00183 }
00184 return false;
00185 }
00186
00187 bool setDelete()
00188 {
00189 if ( inst )
00190 {
00191 if ( ! resetTransactingCandidates() ) return restore();
00192 for_( it, _impl.installedBegin(), _impl.installedEnd() )
00193 {
00194 ResStatus & inststatus( backup( it->status() ) );
00195 if ( ! inststatus.setLock( false, causer ) ) return restore();
00196 if ( ! inststatus.setTransact( true, causer ) ) return restore();
00197 }
00198 return true;
00199 }
00200 return false;
00201 }
00202
00203 bool unset()
00204 {
00205 if ( inst )
00206 {
00207 for_( it, _impl.installedBegin(), _impl.installedEnd() )
00208 {
00209 ResStatus & inststatus( backup( it->status() ) );
00210 if ( ! inststatus.setTransact( false, causer ) ) return restore();
00211 if ( ! inststatus.setLock( false, causer ) ) return restore();
00212 }
00213 }
00214 if ( ! unlockCandidates() ) return restore();
00215 return true;
00216 }
00217
00218 bool setProtected()
00219 {
00220 if ( causer != ResStatus::USER )
00221 return false;
00222
00223 if ( inst ) {
00224 resetTransactingCandidates();
00225 for_( it, _impl.installedBegin(), _impl.installedEnd() )
00226 {
00227 it->status().setTransact( false, causer );
00228 it->status().setLock( true, causer );
00229 }
00230 return true;
00231 } else
00232 return false;
00233 }
00234
00235 bool setTaboo()
00236 {
00237 if ( causer != ResStatus::USER )
00238 return false;
00239
00240 if ( cand ) {
00241 lockCandidates();
00242 return true;
00243 } else
00244 return false;
00245 }
00247
00248 private:
00251 bool resetTransactingCandidates()
00252 {
00253 for_( it, _impl.availableBegin(), _impl.availableEnd() )
00254 {
00255 ResStatus & status( backup( (*it).status() ) );
00256 if ( ! status.setTransact( false, causer ) ) return false;
00257 }
00258 return true;
00259 }
00260 bool unlockCandidates()
00261 {
00262 for_( it, _impl.availableBegin(), _impl.availableEnd() )
00263 {
00264 ResStatus & status( backup( (*it).status() ) );
00265 if ( ! status.setTransact( false, causer ) ) return false;
00266 if ( ! status.setLock( false, causer ) ) return false;
00267 }
00268 return true;
00269 }
00270 bool lockCandidates()
00271 {
00272 for_( it, _impl.availableBegin(), _impl.availableEnd() )
00273 {
00274 ResStatus & status( backup( (*it).status() ) );
00275 if ( ! status.setTransact( false, causer ) ) return false;
00276 if ( ! status.setLock( true, causer ) ) return false;
00277 }
00278 return true;
00279 }
00281
00282 private:
00283 const Selectable::Impl & _impl;
00284 PoolItem inst;
00285 PoolItem cand;
00286 ResStatus::TransactByValue causer;
00287
00288 private:
00289 bool restore() { return backup.restore(); }
00290 StatusBackup backup;
00291 };
00293
00295
00296
00297
00299
00300 Status Selectable::Impl::status() const
00301 {
00302 PoolItem cand( candidateObj() );
00303 if ( cand && cand.status().transacts() )
00304 {
00305 if ( cand.status().isByUser() )
00306 return( installedObj() ? S_Update : S_Install );
00307 else
00308 return( installedObj() ? S_AutoUpdate : S_AutoInstall );
00309 }
00310
00311 if ( installedObj() && installedObj().status().transacts() )
00312 {
00313 return( installedObj().status().isByUser() ? S_Del : S_AutoDel );
00314 }
00315
00316 if ( installedObj() && allInstalledLocked() )
00317 return S_Protected;
00318
00319 if ( !installedObj() && allCandidatesLocked() )
00320 return S_Taboo;
00321
00322
00323 if ( installedObj() )
00324 return S_KeepInstalled;
00325
00326 if ( traits::isPseudoInstalled( kind() )
00327 && cand.status().isSatisfied() )
00328 return S_KeepInstalled;
00329
00330 return S_NoInst;
00331 }
00332
00333 bool Selectable::Impl::setStatus( Status state_r, ResStatus::TransactByValue causer_r )
00334 {
00335 StatusHelper self( *this, causer_r );
00336
00337 switch ( state_r )
00338 {
00339 case S_Protected:
00340 return self.setProtected();
00341 case S_Taboo:
00342 return self.setTaboo();
00343 case S_AutoDel:
00344 case S_AutoInstall:
00345 case S_AutoUpdate:
00346
00347
00348 break;
00349
00350 case S_Del:
00351 return self.setDelete();
00352 break;
00353
00354 case S_Install:
00355 return self.hasCandidateOnly() && self.setInstall();
00356 break;
00357
00358 case S_Update:
00359 return self.hasBoth() && self.setInstall();
00360 break;
00361
00362 case S_KeepInstalled:
00363 return self.hasInstalled() && self.unset();
00364 break;
00365
00366 case S_NoInst:
00367 return !self.hasInstalled() && self.unset();
00368 break;
00369 }
00370
00371 return false;
00372 }
00373
00374 PoolItem Selectable::Impl::setCandidate( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r )
00375 {
00376 PoolItem newCandidate;
00377
00378 if ( newCandidate_r )
00379 {
00380 for_( it, availableBegin(), availableEnd() )
00381 {
00382 if ( *it == newCandidate_r )
00383 {
00384 newCandidate = *it;
00385 break;
00386 }
00387 }
00388 }
00389
00390 if ( newCandidate )
00391 {
00392 PoolItem trans( transactingCandidate() );
00393 if ( trans && trans != newCandidate )
00394 {
00395
00396 if ( trans.status().maySetTransact( false, causer_r )
00397 && newCandidate.status().maySetTransact( true, causer_r ) )
00398 {
00399 trans.status().setTransact( false, causer_r );
00400 newCandidate.status().setTransact( true, causer_r );
00401 }
00402 else
00403 {
00404
00405
00406 return PoolItem();
00407 }
00408 }
00409 }
00410
00411 return _candidate = newCandidate;
00412 }
00413
00415
00416 bool Selectable::Impl::pickInstall( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
00417 {
00418 if ( identicalInstalled( pi_r ) )
00419 return setPickStatus( pi_r, ( yesno_r ? S_Update : S_KeepInstalled ), causer_r );
00420 return setPickStatus( pi_r, ( yesno_r ? S_Install : S_NoInst ), causer_r );
00421 }
00422
00423 bool Selectable::Impl::pickDelete( const PoolItem & pi_r, ResStatus::TransactByValue causer_r, bool yesno_r )
00424 {
00425 return setPickStatus( pi_r, ( yesno_r ? S_Del : S_KeepInstalled ), causer_r );
00426 }
00427
00428 bool Selectable::Impl::setPickStatus( const PoolItem & pi_r, Status state_r, ResStatus::TransactByValue causer_r )
00429 {
00430 if ( pi_r.satSolvable().ident() != ident() )
00431 return false;
00432
00433 if ( ! multiversionInstall() )
00434 return false;
00435
00436
00437
00438
00439 StatusBackup backup;
00440 std::vector<PoolItem> i;
00441 std::vector<PoolItem> a;
00442
00443 for_( it, installedBegin(), installedEnd() )
00444 if ( identical( *it, pi_r ) )
00445 i.push_back( *it );
00446 for_( it, availableBegin(), availableEnd() )
00447 if ( identical( *it, pi_r ) )
00448 a.push_back( *it );
00449
00450 switch ( state_r )
00451 {
00452 case S_Protected:
00453 if ( causer_r == ResStatus::USER && ! i.empty() )
00454 {
00455 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
00456 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
00457 return true;
00458 }
00459 break;
00460
00461 case S_Taboo:
00462 if ( causer_r == ResStatus::USER && ! a.empty() )
00463 {
00464 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::lock, causer_r ) ) return backup.restore();
00465 return true;
00466 }
00467 break;
00468
00469 case S_AutoDel:
00470 case S_AutoInstall:
00471 case S_AutoUpdate:
00472
00473
00474 break;
00475
00476 case S_Del:
00477 if ( ! i.empty() )
00478 {
00479 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::transact, causer_r ) ) return backup.restore();
00480 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::setTransactFalse, causer_r ) ) return backup.restore();
00481 return true;
00482 }
00483 break;
00484
00485 case S_Install:
00486 if ( i.empty() && ! a.empty() )
00487 {
00488
00489 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00490 const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
00491 if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
00492 return true;
00493 }
00494 break;
00495
00496 case S_Update:
00497 if ( ! i.empty() && ! a.empty() )
00498 {
00499 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00500 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
00501
00502 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00503 const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
00504 if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
00505 return true;
00506 }
00507 break;
00508
00509 case S_KeepInstalled:
00510 if ( ! i.empty() )
00511 {
00512 if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00513 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00514 return true;
00515 }
00516 break;
00517
00518 case S_NoInst:
00519 if ( i.empty() )
00520 {
00521 if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
00522 return true;
00523 }
00524 break;
00525 }
00526 return false;
00527 }
00528
00529 Status Selectable::Impl::pickStatus( const PoolItem & pi_r ) const
00530 {
00531 if ( pi_r.satSolvable().ident() != ident() )
00532 return Status(-1);
00533
00534 std::vector<PoolItem> i;
00535 std::vector<PoolItem> a;
00536 PoolItem ti;
00537 PoolItem ta;
00538
00539 for_( it, installedBegin(), installedEnd() )
00540 if ( identical( *it, pi_r ) )
00541 {
00542 i.push_back( *it );
00543 if ( ! ti && it->status().transacts() )
00544 ti = *it;
00545 }
00546
00547 for_( it, availableBegin(), availableEnd() )
00548 if ( identical( *it, pi_r ) )
00549 {
00550 a.push_back( *it );
00551 if ( ! ta && it->status().transacts() )
00552 ta = *it;
00553 }
00554
00555 if ( ta )
00556 {
00557 if ( ta.status().isByUser() )
00558 return( i.empty() ? S_Install : S_Update );
00559 else
00560 return( i.empty() ? S_AutoInstall : S_AutoUpdate );
00561 }
00562
00563 if ( ti )
00564 {
00565 return( ti.status().isByUser() ? S_Del : S_AutoDel );
00566 }
00567
00568 for_( it, i.begin(), i.end() )
00569 if ( it->status().isLocked() )
00570 return S_Protected;
00571
00572 if ( i.empty() )
00573 {
00574 bool allALocked = true;
00575 for_( it, a.begin(), a.end() )
00576 if ( ! it->status().isLocked() )
00577 {
00578 allALocked = false;
00579 break;
00580 }
00581 if ( allALocked )
00582 return S_Taboo;
00583 }
00584
00585
00586 if ( ! i.empty() )
00587 return S_KeepInstalled;
00588
00589 if ( traits::isPseudoInstalled( kind() )
00590 && ( ta ? ta : *a.begin() ).status().isSatisfied() )
00591 return S_KeepInstalled;
00592
00593 return S_NoInst;
00594 }
00595
00597
00598 ResStatus::TransactByValue Selectable::Impl::modifiedBy() const
00599 {
00600 PoolItem cand( candidateObj() );
00601 if ( cand && cand.status().transacts() )
00602 return cand.status().getTransactByValue();
00603
00604 if ( installedObj() && installedObj().status().transacts() )
00605 return installedObj().status().getTransactByValue();
00606
00607 if ( cand )
00608 return cand.status().getTransactByValue();
00609
00610 if ( installedObj() )
00611 return installedObj().status().getTransactByValue();
00612
00613 return ResStatus::SOLVER;
00614 }
00615
00617 }
00620 }