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 (1);
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 PoolItem provider( cai.item );
00148 if (cancel_unlink)
00149 return true;
00150
00151 if (! context->isPresent (cai.item))
00152 return true;
00153
00154 if (context->requirementIsMet (cai.cap, provider, Dep::REQUIRES))
00155 return true;
00156
00157 cancel_unlink = true;
00158
00159 return true;
00160 }
00161 };
00162
00163
00164
00165
00166 struct UninstallProcess
00167 {
00168 ResPool pool;
00169 ResolverContext_Ptr context;
00170 PoolItem_Ref uninstalled_item;
00171 PoolItem_Ref upgraded_item;
00172 QueueItemList & qil;
00173 bool remove_only;
00174 bool soft;
00175
00176 UninstallProcess (const ResPool & p, ResolverContext_Ptr ct, PoolItem_Ref u1, PoolItem_Ref u2, QueueItemList & l, bool ro, bool s)
00177 : pool (p)
00178 , context (ct)
00179 , uninstalled_item (u1)
00180 , upgraded_item (u2)
00181 , qil (l)
00182 , remove_only (ro)
00183 , soft (s)
00184 { }
00185
00186
00187
00188 bool operator()( const CapAndItem & cai )
00189 {
00190 PoolItem requirer( cai.item );
00191 if (! context->isPresent (requirer))
00192 return true;
00193
00194 if (context->requirementIsMet( cai.cap, requirer, Dep::REQUIRES ))
00195 return true;
00196
00197 if (context->getStatus(requirer).isSatisfied()) {
00198 #warning If an uninstall incompletes a satisfied, the uninstall should be cancelled
00199 QueueItemEstablish_Ptr establish_item = new QueueItemEstablish (pool, requirer, soft);
00200 qil.push_back (establish_item);
00201 return true;
00202 }
00203 QueueItemRequire_Ptr require_item = new QueueItemRequire( pool, cai.cap );
00204 require_item->addPoolItem (requirer);
00205 if (remove_only) {
00206 require_item->setRemoveOnly ();
00207 }
00208 require_item->setUpgradedPoolItem (upgraded_item);
00209 require_item->setLostPoolItem (uninstalled_item);
00210
00211 qil.push_front (require_item);
00212
00213 return true;
00214 }
00215 };
00216
00217
00218
00219
00220 struct UninstallEstablishItem
00221 {
00222 const ResPool & pool;
00223 QueueItemList & qil;
00224 bool soft;
00225
00226 UninstallEstablishItem (const ResPool & p, QueueItemList &l, bool s)
00227 : pool(p)
00228 , qil(l)
00229 , soft(s)
00230 { }
00231
00232
00233
00234
00235
00236 bool operator()( const CapAndItem & cai )
00237 {
00238 _XDEBUG("QueueItemUninstall::UninstallEstablishItem (" << cai.item << ", " << cai.cap << ")");
00239
00240
00241
00242 if (cai.item.status().staysInstalled()) {
00243 QueueItemEstablish_Ptr establish_item = new QueueItemEstablish (pool, cai.item, soft);
00244 qil.push_back (establish_item);
00245 }
00246 return true;
00247 }
00248 };
00249
00250
00251
00252 struct ProvidesItem
00253 {
00254 const ResPool & pool;
00255 QueueItemList & qil;
00256 bool soft;
00257
00258 ProvidesItem (const ResPool & p, QueueItemList &l, bool s)
00259 : pool(p)
00260 , qil(l)
00261 , soft(s)
00262 { }
00263
00264
00265 bool operator()( const CapAndItem & cai )
00266 {
00267 _XDEBUG("remove soft item (" << cai.item << ", " << cai.cap << ")");
00268 PoolItem_Ref item( cai.item );
00269 if (!item.status().transacts()
00270 && item.status().maySetToBeUninstalledSoft())
00271 {
00272 QueueItemUninstall_Ptr uninstall_item = new QueueItemUninstall (pool, item, QueueItemUninstall::EXPLICIT, soft);
00273 uninstall_item->setUnlink ();
00274 qil.push_back (uninstall_item);
00275 } else {
00276 _XDEBUG(" ---> do not remove cause it has been set for transaction or can not set for uninstallation due right problems.");
00277 }
00278 return true;
00279 }
00280 };
00281
00282
00283
00284
00285 struct UninstallItem
00286 {
00287 ResPool pool;
00288 ResolverContext_Ptr context;
00289 QueueItemList & qil;
00290 bool soft;
00291
00292 UninstallItem( const ResPool & p, ResolverContext_Ptr ct, QueueItemList & l, bool s )
00293 : pool( p )
00294 , context( ct )
00295 , qil( l )
00296 , soft( s )
00297 { }
00298
00299 bool operator()( const CapAndItem & cai )
00300 {
00301 PoolItem item( cai.item );
00302
00303 _XDEBUG( "UninstallItem (unlink) " << item );
00304 QueueItemUninstall_Ptr uninstall_item = new QueueItemUninstall( pool, item, QueueItemUninstall::EXPLICIT, soft );
00305 uninstall_item->setUnlink();
00306 qil.push_front( uninstall_item );
00307
00308 return true;
00309 }
00310 };
00311
00312
00313
00314
00315
00316 bool
00317 QueueItemUninstall::process (const QueueItemList & mainQueue, ResolverContext_Ptr context, QueueItemList & qil)
00318 {
00319 ResStatus status = context->getStatus(_item);
00320
00321 _XDEBUG("QueueItemUninstall::process(<" << status << ">" << _item << ( _unlink ? "[unlink]" : ""));
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 if (_unlink) {
00334
00335 if (status.isToBeInstalled()) {
00336 ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_TO_BE_INSTALLED, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00337 context->addInfo (misc_info);
00338 goto finished;
00339
00340 }
00341 else if (status.staysInstalled()) {
00342
00343 UnlinkCheck info;
00344
00345
00346
00347
00348 context->setStatus(_item, ResStatus::toBeUninstalled);
00349
00350 info.context = context;
00351 info.cancel_unlink = false;
00352
00353
00354
00355
00356 CapSet provides = _item->dep(Dep::PROVIDES);
00357 for (CapSet::const_iterator iter = provides.begin(); iter != provides.end() && ! info.cancel_unlink; iter++) {
00358
00359
00360
00361 Dep dep( Dep::REQUIRES);
00362
00363 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00364 pool().byCapabilityIndexEnd( iter->index(), dep ),
00365 resfilter::ByCapMatch( *iter ),
00366 functor::functorRef<bool,CapAndItem>(info) );
00367
00368 }
00369
00370
00371
00372 context->setStatus(_item, status);
00373
00374 if (info.cancel_unlink) {
00375 ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_INSTALLED, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00376 context->addInfo (misc_info);
00377 goto finished;
00378 }
00379 }
00380
00381 }
00382
00383 this->logInfo (context);
00384
00385 context->uninstall (_item, _upgraded_to , _due_to_obsolete, _unlink, _explicitly_requested);
00386 if (status.staysInstalled()) {
00387 if (! _explicitly_requested
00388 && _item.status().isLocked()) {
00389
00390 ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_LOCKED,
00391 _item, RESOLVER_INFO_PRIORITY_VERBOSE,
00392 _cap_leading_to_uninstall);
00393 if (_due_to_obsolete)
00394 {
00395 misc_info->setOtherPoolItem (_obsoletes_item);
00396 misc_info->addTrigger (ResolverInfoMisc::OBSOLETE);
00397 } else if (_due_to_conflict)
00398 {
00399 misc_info->addTrigger (ResolverInfoMisc::CONFLICT);
00400 }
00401
00402 context->addError (misc_info);
00403 goto finished;
00404 }
00405
00406 if (_cap_leading_to_uninstall != Capability()
00407 && !_due_to_conflict
00408 && !_due_to_obsolete)
00409 {
00410 ResolverInfo_Ptr info = new ResolverInfoMissingReq (_item, _cap_leading_to_uninstall);
00411 context->addInfo (info);
00412 }
00413
00414
00415
00416
00417 CapSet provides = _item->dep(Dep::PROVIDES);
00418
00419 for (CapSet::const_iterator iter = provides.begin(); iter != provides.end(); iter++) {
00420 UninstallProcess info ( pool(), context, _item, _upgraded_to, qil, _remove_only, _soft);
00421
00422
00423 Dep dep( Dep::REQUIRES );
00424
00425 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00426 pool().byCapabilityIndexEnd( iter->index(), dep ),
00427 resfilter::ByCapMatch( *iter ),
00428 functor::functorRef<bool,CapAndItem>(info) );
00429
00430
00431
00432 UninstallEstablishItem establish( pool(), qil, _soft );
00433
00434 dep = Dep::SUPPLEMENTS;
00435 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00436 pool().byCapabilityIndexEnd( iter->index(), dep ),
00437 resfilter::ByCapMatch( *iter ),
00438 functor::functorRef<bool,CapAndItem>( establish ) );
00439
00440 dep = Dep::FRESHENS;
00441 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00442 pool().byCapabilityIndexEnd( iter->index(), dep ),
00443 resfilter::ByCapMatch( *iter ),
00444 functor::functorRef<bool,CapAndItem>( establish ) );
00445 }
00446
00447
00448
00449 if (_item->kind() == ResTraits<Patch>::kind) {
00450 Patch::constPtr patch = asKind<Patch>( _item );
00451 Patch::AtomList atoms = patch->atoms();
00452 UninstallItem callback( pool(), context, qil, _soft );
00453 CapFactory factory;
00454 Dep dep(Dep::PROVIDES);
00455
00456
00457
00458 for (Patch::AtomList::const_iterator it = atoms.begin(); it != atoms.end(); ++it) {
00459 Resolvable::constPtr res = *it;
00460 Capability capAtom = factory.parse ( res->kind(), res->name(), Rel::EQ, res->edition());
00461 invokeOnEach( pool().byCapabilityIndexBegin( capAtom.index(), dep ),
00462 pool().byCapabilityIndexEnd( capAtom.index(), dep ),
00463 functor::chain( resfilter::ByCaIInstalled(), resfilter::ByCapMatch( capAtom ) ),
00464 functor::functorRef<bool,CapAndItem>( callback ) );
00465 }
00466 }
00467
00468
00469
00470
00471 if (_upgraded_to
00472 || _item->kind() == ResTraits<Package>::kind)
00473 {
00474 goto finished;
00475 }
00476
00477 CapSet recomments = _item->dep (Dep::RECOMMENDS);
00478 for (CapSet::const_iterator iter = recomments.begin(); iter != recomments.end(); iter++) {
00479 const Capability cap = *iter;
00480 _XDEBUG("this recommends " << cap);
00481 ProvidesItem provides( pool(), qil, true );
00482
00483 Dep dep(Dep::PROVIDES);
00484 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00485 pool().byCapabilityIndexEnd( iter->index(), dep ),
00486 functor::chain( resfilter::ByCaIInstalled(), resfilter::ByCapMatch( *iter ) ),
00487 functor::functorRef<bool,CapAndItem>( provides ) );
00488 }
00489
00490 }
00491
00492 finished:
00493 return true;
00494 }
00495
00496
00497
00498 int
00499 QueueItemUninstall::cmp (QueueItem_constPtr item) const
00500 {
00501 int cmp = this->compare (item);
00502 if (cmp != 0)
00503 return cmp;
00504
00505 QueueItemUninstall_constPtr uninstall = dynamic_pointer_cast<const QueueItemUninstall>(item);
00506 return compareByNVRA (_item.resolvable(), uninstall->_item.resolvable());
00507 }
00508
00509
00510 QueueItem_Ptr
00511 QueueItemUninstall::copy (void) const
00512 {
00513 QueueItemUninstall_Ptr new_uninstall = new QueueItemUninstall (pool(), _item, _reason);
00514 new_uninstall->QueueItem::copy(this);
00515
00516
00517 new_uninstall->_item = _item;
00518 new_uninstall->_cap_leading_to_uninstall = _cap_leading_to_uninstall;
00519 new_uninstall->_upgraded_to = _upgraded_to;
00520
00521 new_uninstall->_explicitly_requested = _explicitly_requested;
00522 new_uninstall->_remove_only = _remove_only;
00523 new_uninstall->_due_to_conflict = _due_to_conflict;
00524 new_uninstall->_due_to_obsolete = _due_to_obsolete;
00525 new_uninstall->_obsoletes_item = _obsoletes_item;
00526 new_uninstall->_unlink = _unlink;
00527
00528 return new_uninstall;
00529 }
00530
00532 };
00535 };
00538 };
00540