libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00012 #include <iostream> 00013 //#include "zypp/base/Logger.h" 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; // restore is done on error - return restore(); 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 // CLASS NAME : StatusHelper 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 // Queries 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 // This is what the solver most probabely will do. 00172 // If we are wrong the solver will correct it. But 00173 // this way we will get a better disk usage result, 00174 // even if no autosolving is on. 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 ) // by user only 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 ) // by user only 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 // CLASS NAME : Selectable::Impl 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 // KEEP state: 00323 if ( installedObj() ) 00324 return S_KeepInstalled; 00325 // Report pseudo installed items as installed, if they are satisfied. 00326 if ( traits::isPseudoInstalled( kind() ) 00327 && cand.status().isSatisfied() ) // no installed, so we must have candidate 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 // Auto level is SOLVER level. UI may query, but not 00347 // set at this level. 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 ) // must be in available list 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 // adjust transact to the new cancidate 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 // No permission to change a transacting candidate. 00405 // Leave _candidate untouched and return NULL. 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; // not my PoolItem 00432 00433 if ( ! multiversionInstall() ) 00434 return false; // We're not yet ready for this. 00435 // TODO: Without multiversionInstall take care at most ONE available is set 00436 // to install. Upon install ALL installed get deleted. Only upon deletetion 00437 // one might pick individual versions (but more than one would be an error here). 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 // Auto level is SOLVER level. UI may query, but not 00473 // set at this level. 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 // maybe unlock candidate only? 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 ); // status already backed up above 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 // maybe unlock candidate only? 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 ); // status already backed up above 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); // not my PoolItem 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 // KEEP state: 00586 if ( ! i.empty() ) 00587 return S_KeepInstalled; 00588 // Report pseudo installed items as installed, if they are satisfied. 00589 if ( traits::isPseudoInstalled( kind() ) 00590 && ( ta ? ta : *a.begin() ).status().isSatisfied() ) // no installed, so we must have candidate 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 } // namespace ui 00620 } // namespace zypp