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