00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "zypp/CapSet.h"
00023 #include "zypp/base/Logger.h"
00024 #include "zypp/base/String.h"
00025 #include "zypp/base/Gettext.h"
00026
00027 #include "zypp/base/Algorithm.h"
00028 #include "zypp/ResPool.h"
00029 #include "zypp/ResFilters.h"
00030 #include "zypp/CapFilters.h"
00031 #include "zypp/CapFactory.h"
00032 #include "zypp/Patch.h"
00033
00034 #include "zypp/solver/detail/QueueItemUninstall.h"
00035 #include "zypp/solver/detail/QueueItemEstablish.h"
00036 #include "zypp/solver/detail/QueueItemRequire.h"
00037 #include "zypp/solver/detail/QueueItem.h"
00038 #include "zypp/solver/detail/ResolverContext.h"
00039 #include "zypp/solver/detail/ResolverInfoMisc.h"
00040 #include "zypp/solver/detail/ResolverInfoMissingReq.h"
00041
00043 namespace zypp
00044 {
00045
00046 namespace solver
00047 {
00048
00049 namespace detail
00050 {
00051
00052 using namespace std;
00053
00054 IMPL_PTR_TYPE(QueueItemUninstall);
00055
00056
00057
00058 std::ostream &
00059 QueueItemUninstall::dumpOn( std::ostream & os ) const
00060 {
00061 os << "[" << (_soft?"Soft":"") << "Uninstall: ";
00062
00063 os << _item;
00064 os << " (";
00065 switch (_reason) {
00066 case QueueItemUninstall::CONFLICT: os << "conflicts"; break;
00067 case QueueItemUninstall::OBSOLETE: os << "obsoletes"; break;
00068 case QueueItemUninstall::UNSATISFIED: os << "unsatisfied dependency"; break;
00069 case QueueItemUninstall::BACKOUT: os << "uninstallable"; break;
00070 case QueueItemUninstall::UPGRADE: os << "upgrade"; break;
00071 case QueueItemUninstall::DUPLICATE: os << "duplicate"; break;
00072 case QueueItemUninstall::EXPLICIT: os << "explicit"; break;
00073 }
00074 os << ")";
00075 if (_cap_leading_to_uninstall != Capability::noCap) {
00076 os << ", Triggered By ";
00077 os << _cap_leading_to_uninstall;
00078 }
00079 if (_upgraded_to) {
00080 os << ", Upgraded To ";
00081 os << _upgraded_to;
00082 }
00083 if (_explicitly_requested) os << ", Explicit";
00084 if (_remove_only) os << ", Remove Only";
00085 if (_due_to_conflict) os << ", Due To Conflict";
00086 if (_due_to_obsolete)
00087 os << ", Due To Obsolete:" << _obsoletes_item;
00088 if (_unlink) os << ", Unlink";
00089 os << "]";
00090 return os;
00091 }
00092
00093
00094
00095 QueueItemUninstall::QueueItemUninstall (const ResPool & pool, PoolItem_Ref item, UninstallReason reason, bool soft)
00096 : QueueItem (QUEUE_ITEM_TYPE_UNINSTALL, pool)
00097 , _item (item)
00098 , _reason (reason)
00099 , _soft (soft)
00100 , _cap_leading_to_uninstall (Capability())
00101 , _upgraded_to (NULL)
00102 , _explicitly_requested (false)
00103 , _remove_only (false)
00104 , _due_to_conflict (false)
00105 , _due_to_obsolete (false)
00106 , _unlink (false)
00107 , _obsoletes_item (NULL)
00108 {
00109 _XDEBUG("QueueItemUninstall::QueueItemUninstall(" << item << ")");
00110 }
00111
00112
00113 QueueItemUninstall::~QueueItemUninstall()
00114 {
00115 }
00116
00117
00118
00119 void
00120 QueueItemUninstall::setUnlink ()
00121 {
00122 _unlink = true;
00123
00124
00125
00126 setPriority (0);
00127
00128 return;
00129 }
00130
00131
00132
00133 struct UnlinkCheck
00134 {
00135 ResolverContext_Ptr context;
00136 bool cancel_unlink;
00137
00138
00139
00140
00141
00142
00143
00144
00145 bool operator()( const CapAndItem & cai )
00146 {
00147 if (cancel_unlink)
00148 return true;
00149
00150 if (! context->isPresent (cai.item))
00151 return true;
00152
00153 if (context->requirementIsMet (cai.cap))
00154 return true;
00155
00156 cancel_unlink = true;
00157
00158 return true;
00159 }
00160 };
00161
00162
00163
00164
00165 struct UninstallProcess
00166 {
00167 ResPool pool;
00168 ResolverContext_Ptr context;
00169 PoolItem_Ref uninstalled_item;
00170 PoolItem_Ref upgraded_item;
00171 QueueItemList & qil;
00172 bool remove_only;
00173 bool soft;
00174
00175 UninstallProcess (const ResPool & p, ResolverContext_Ptr ct, PoolItem_Ref u1, PoolItem_Ref u2, QueueItemList & l, bool ro, bool s)
00176 : pool (p)
00177 , context (ct)
00178 , uninstalled_item (u1)
00179 , upgraded_item (u2)
00180 , qil (l)
00181 , remove_only (ro)
00182 , soft (s)
00183 { }
00184
00185
00186
00187 bool operator()( const CapAndItem & cai )
00188 {
00189 PoolItem requirer( cai.item );
00190 if (! context->isPresent (requirer))
00191 return true;
00192
00193 if (context->requirementIsMet( cai.cap ))
00194 return true;
00195
00196 if (context->getStatus(requirer).isSatisfied()) {
00197 #warning If an uninstall incompletes a satisfied, the uninstall should be cancelled
00198 QueueItemEstablish_Ptr establish_item = new QueueItemEstablish (pool, requirer, soft);
00199 qil.push_back (establish_item);
00200 return true;
00201 }
00202 QueueItemRequire_Ptr require_item = new QueueItemRequire( pool, cai.cap );
00203 require_item->addPoolItem (requirer);
00204 if (remove_only) {
00205 require_item->setRemoveOnly ();
00206 }
00207 require_item->setUpgradedPoolItem (upgraded_item);
00208 require_item->setLostPoolItem (uninstalled_item);
00209
00210 qil.push_front (require_item);
00211
00212 return true;
00213 }
00214 };
00215
00216
00217
00218
00219 struct UninstallEstablishItem
00220 {
00221 const ResPool & pool;
00222 QueueItemList & qil;
00223 bool soft;
00224
00225 UninstallEstablishItem (const ResPool & p, QueueItemList &l, bool s)
00226 : pool(p)
00227 , qil(l)
00228 , soft(s)
00229 { }
00230
00231
00232
00233
00234
00235 bool operator()( const CapAndItem & cai )
00236 {
00237 _XDEBUG("QueueItemUninstall::UninstallEstablishItem (" << cai.item << ", " << cai.cap << ")");
00238
00239
00240
00241 if (cai.item.status().staysInstalled()) {
00242 QueueItemEstablish_Ptr establish_item = new QueueItemEstablish (pool, cai.item, soft);
00243 qil.push_back (establish_item);
00244 }
00245 return true;
00246 }
00247 };
00248
00249
00250
00251 struct ProvidesItem
00252 {
00253 const ResPool & pool;
00254 QueueItemList & qil;
00255 bool soft;
00256
00257 ProvidesItem (const ResPool & p, QueueItemList &l, bool s)
00258 : pool(p)
00259 , qil(l)
00260 , soft(s)
00261 { }
00262
00263
00264 bool operator()( const CapAndItem & cai )
00265 {
00266 _XDEBUG("remove soft item (" << cai.item << ", " << cai.cap << ")");
00267 PoolItem_Ref item( cai.item );
00268 if (!item.status().transacts()
00269 && item.status().maySetToBeUninstalledSoft())
00270 {
00271 QueueItemUninstall_Ptr uninstall_item = new QueueItemUninstall (pool, item, QueueItemUninstall::EXPLICIT, soft);
00272 uninstall_item->setUnlink ();
00273 qil.push_back (uninstall_item);
00274 } else {
00275 _XDEBUG(" ---> do not remove cause it has been set for transaction or can not set for uninstallation due right problems.");
00276 }
00277 return true;
00278 }
00279 };
00280
00281
00282
00283
00284 struct UninstallItem
00285 {
00286 ResPool pool;
00287 ResolverContext_Ptr context;
00288 QueueItemList & qil;
00289 bool soft;
00290
00291 UninstallItem( const ResPool & p, ResolverContext_Ptr ct, QueueItemList & l, bool s )
00292 : pool( p )
00293 , context( ct )
00294 , qil( l )
00295 , soft( s )
00296 { }
00297
00298 bool operator()( const CapAndItem & cai )
00299 {
00300 PoolItem item( cai.item );
00301
00302 _XDEBUG( "UninstallItem (unlink) " << item );
00303 QueueItemUninstall_Ptr uninstall_item = new QueueItemUninstall( pool, item, QueueItemUninstall::EXPLICIT, soft );
00304 uninstall_item->setUnlink();
00305 qil.push_front( uninstall_item );
00306
00307 return true;
00308 }
00309 };
00310
00311
00312
00313
00314
00315 bool
00316 QueueItemUninstall::process (ResolverContext_Ptr context, QueueItemList & qil)
00317 {
00318 ResStatus status = context->getStatus(_item);
00319
00320 _XDEBUG("QueueItemUninstall::process(<" << status << ">" << _item << ( _unlink ? "[unlink]" : ""));
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 if (_unlink) {
00333
00334 if (status.isToBeInstalled()) {
00335 ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_TO_BE_INSTALLED, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00336 context->addInfo (misc_info);
00337 goto finished;
00338
00339 }
00340 else if (status.staysInstalled()) {
00341
00342 UnlinkCheck info;
00343
00344
00345
00346
00347 context->setStatus(_item, ResStatus::toBeUninstalled);
00348
00349 info.context = context;
00350 info.cancel_unlink = false;
00351
00352
00353
00354
00355 CapSet provides = _item->dep(Dep::PROVIDES);
00356 for (CapSet::const_iterator iter = provides.begin(); iter != provides.end() && ! info.cancel_unlink; iter++) {
00357
00358
00359
00360 Dep dep( Dep::REQUIRES);
00361
00362 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00363 pool().byCapabilityIndexEnd( iter->index(), dep ),
00364 resfilter::ByCapMatch( *iter ),
00365 functor::functorRef<bool,CapAndItem>(info) );
00366
00367 }
00368
00369
00370
00371 context->setStatus(_item, status);
00372
00373 if (info.cancel_unlink) {
00374 ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_INSTALLED, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00375 context->addInfo (misc_info);
00376 goto finished;
00377 }
00378 }
00379
00380 }
00381
00382 this->logInfo (context);
00383
00384 context->uninstall (_item, _upgraded_to , _due_to_obsolete, _unlink);
00385 if (status.staysInstalled()) {
00386 if (! _explicitly_requested
00387 && _item.status().isLocked()) {
00388
00389 ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_LOCKED,
00390 _item, RESOLVER_INFO_PRIORITY_VERBOSE,
00391 _cap_leading_to_uninstall);
00392 if (_due_to_obsolete)
00393 {
00394 misc_info->setOtherPoolItem (_obsoletes_item);
00395 misc_info->addTrigger (ResolverInfoMisc::OBSOLETE);
00396 } else if (_due_to_conflict)
00397 {
00398 misc_info->addTrigger (ResolverInfoMisc::CONFLICT);
00399 }
00400
00401 context->addError (misc_info);
00402 goto finished;
00403 }
00404
00405 if (_cap_leading_to_uninstall != Capability()
00406 && !_due_to_conflict
00407 && !_due_to_obsolete)
00408 {
00409 ResolverInfo_Ptr info = new ResolverInfoMissingReq (_item, _cap_leading_to_uninstall);
00410 context->addInfo (info);
00411 }
00412
00413
00414
00415
00416 CapSet provides = _item->dep(Dep::PROVIDES);
00417
00418 for (CapSet::const_iterator iter = provides.begin(); iter != provides.end(); iter++) {
00419 UninstallProcess info ( pool(), context, _item, _upgraded_to, qil, _remove_only, _soft);
00420
00421
00422 Dep dep( Dep::REQUIRES );
00423
00424 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00425 pool().byCapabilityIndexEnd( iter->index(), dep ),
00426 resfilter::ByCapMatch( *iter ),
00427 functor::functorRef<bool,CapAndItem>(info) );
00428
00429
00430
00431 UninstallEstablishItem establish( pool(), qil, _soft );
00432
00433 dep = Dep::SUPPLEMENTS;
00434 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00435 pool().byCapabilityIndexEnd( iter->index(), dep ),
00436 resfilter::ByCapMatch( *iter ),
00437 functor::functorRef<bool,CapAndItem>( establish ) );
00438
00439 dep = Dep::FRESHENS;
00440 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00441 pool().byCapabilityIndexEnd( iter->index(), dep ),
00442 resfilter::ByCapMatch( *iter ),
00443 functor::functorRef<bool,CapAndItem>( establish ) );
00444 }
00445
00446
00447
00448 if (_item->kind() == ResTraits<Patch>::kind) {
00449 Patch::constPtr patch = asKind<Patch>( _item );
00450 Patch::AtomList atoms = patch->atoms();
00451 UninstallItem callback( pool(), context, qil, _soft );
00452 CapFactory factory;
00453 Dep dep(Dep::PROVIDES);
00454
00455
00456
00457 for (Patch::AtomList::const_iterator it = atoms.begin(); it != atoms.end(); ++it) {
00458 Resolvable::constPtr res = *it;
00459 Capability capAtom = factory.parse ( res->kind(), res->name(), Rel::EQ, res->edition());
00460 invokeOnEach( pool().byCapabilityIndexBegin( capAtom.index(), dep ),
00461 pool().byCapabilityIndexEnd( capAtom.index(), dep ),
00462 functor::chain( resfilter::ByCaIInstalled(), resfilter::ByCapMatch( capAtom ) ),
00463 functor::functorRef<bool,CapAndItem>( callback ) );
00464 }
00465 }
00466
00467
00468
00469
00470 if (_upgraded_to
00471 || _item->kind() == ResTraits<Package>::kind)
00472 {
00473 goto finished;
00474 }
00475
00476 CapSet recomments = _item->dep (Dep::RECOMMENDS);
00477 for (CapSet::const_iterator iter = recomments.begin(); iter != recomments.end(); iter++) {
00478 const Capability cap = *iter;
00479 _XDEBUG("this recommends " << cap);
00480 ProvidesItem provides( pool(), qil, true );
00481
00482 Dep dep(Dep::PROVIDES);
00483 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00484 pool().byCapabilityIndexEnd( iter->index(), dep ),
00485 functor::chain( resfilter::ByCaIInstalled(), resfilter::ByCapMatch( *iter ) ),
00486 functor::functorRef<bool,CapAndItem>( provides ) );
00487 }
00488
00489 }
00490
00491 finished:
00492 return true;
00493 }
00494
00495
00496
00497 int
00498 QueueItemUninstall::cmp (QueueItem_constPtr item) const
00499 {
00500 int cmp = this->compare (item);
00501 if (cmp != 0)
00502 return cmp;
00503
00504 QueueItemUninstall_constPtr uninstall = dynamic_pointer_cast<const QueueItemUninstall>(item);
00505 return compareByNVRA (_item.resolvable(), uninstall->_item.resolvable());
00506 }
00507
00508
00509 QueueItem_Ptr
00510 QueueItemUninstall::copy (void) const
00511 {
00512 QueueItemUninstall_Ptr new_uninstall = new QueueItemUninstall (pool(), _item, _reason);
00513 new_uninstall->QueueItem::copy(this);
00514
00515
00516 new_uninstall->_item = _item;
00517 new_uninstall->_cap_leading_to_uninstall = _cap_leading_to_uninstall;
00518 new_uninstall->_upgraded_to = _upgraded_to;
00519
00520 new_uninstall->_explicitly_requested = _explicitly_requested;
00521 new_uninstall->_remove_only = _remove_only;
00522 new_uninstall->_due_to_conflict = _due_to_conflict;
00523 new_uninstall->_due_to_obsolete = _due_to_obsolete;
00524 new_uninstall->_obsoletes_item = _obsoletes_item;
00525 new_uninstall->_unlink = _unlink;
00526
00527 return new_uninstall;
00528 }
00529
00531 };
00534 };
00537 };
00539