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, false ))
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 QueueItemUninstall_Ptr uninstall_item = new QueueItemUninstall (pool, item, QueueItemUninstall::EXPLICIT, soft);
00270 uninstall_item->setUnlink ();
00271 qil.push_back (uninstall_item);
00272 }
00273 return true;
00274 }
00275 };
00276
00277
00278
00279
00280 struct UninstallItem
00281 {
00282 ResPool pool;
00283 ResolverContext_Ptr context;
00284 QueueItemList & qil;
00285 bool soft;
00286
00287 UninstallItem( const ResPool & p, ResolverContext_Ptr ct, QueueItemList & l, bool s )
00288 : pool( p )
00289 , context( ct )
00290 , qil( l )
00291 , soft( s )
00292 { }
00293
00294 bool operator()( const CapAndItem & cai )
00295 {
00296 PoolItem item( cai.item );
00297
00298 _XDEBUG( "UninstallItem (unlink) " << item );
00299 QueueItemUninstall_Ptr uninstall_item = new QueueItemUninstall( pool, item, QueueItemUninstall::EXPLICIT, soft );
00300 uninstall_item->setUnlink();
00301 qil.push_front( uninstall_item );
00302
00303 return true;
00304 }
00305 };
00306
00307
00308
00309
00310
00311 bool
00312 QueueItemUninstall::process (ResolverContext_Ptr context, QueueItemList & qil)
00313 {
00314 ResStatus status = context->getStatus(_item);
00315
00316 _XDEBUG("QueueItemUninstall::process(<" << status << ">" << _item << ( _unlink ? "[unlink]" : ""));
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 if (_unlink) {
00329
00330 if (status.isToBeInstalled()) {
00331 ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_TO_BE_INSTALLED, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00332 context->addInfo (misc_info);
00333 goto finished;
00334
00335 }
00336 else if (status.staysInstalled()) {
00337
00338 UnlinkCheck info;
00339
00340
00341
00342
00343 context->setStatus(_item, ResStatus::toBeUninstalled);
00344
00345 info.context = context;
00346 info.cancel_unlink = false;
00347
00348
00349
00350
00351 CapSet provides = _item->dep(Dep::PROVIDES);
00352 for (CapSet::const_iterator iter = provides.begin(); iter != provides.end() && ! info.cancel_unlink; iter++) {
00353
00354
00355
00356 Dep dep( Dep::REQUIRES);
00357
00358 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00359 pool().byCapabilityIndexEnd( iter->index(), dep ),
00360 resfilter::ByCapMatch( *iter ),
00361 functor::functorRef<bool,CapAndItem>(info) );
00362
00363 }
00364
00365
00366
00367 context->setStatus(_item, status);
00368
00369 if (info.cancel_unlink) {
00370 ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_INSTALLED, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00371 context->addInfo (misc_info);
00372 goto finished;
00373 }
00374 }
00375
00376 }
00377
00378 this->logInfo (context);
00379
00380 context->uninstall (_item, _upgraded_to , _due_to_obsolete, _unlink);
00381 if (status.staysInstalled()) {
00382 if (! _explicitly_requested
00383 && _item.status().isLocked()) {
00384
00385 ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_LOCKED,
00386 _item, RESOLVER_INFO_PRIORITY_VERBOSE,
00387 _cap_leading_to_uninstall);
00388 if (_due_to_obsolete)
00389 {
00390 misc_info->setOtherPoolItem (_obsoletes_item);
00391 misc_info->addTrigger (ResolverInfoMisc::OBSOLETE);
00392 } else if (_due_to_conflict)
00393 {
00394 misc_info->addTrigger (ResolverInfoMisc::CONFLICT);
00395 }
00396
00397 context->addError (misc_info);
00398 goto finished;
00399 }
00400
00401 if (_cap_leading_to_uninstall != Capability()
00402 && !_due_to_conflict
00403 && !_due_to_obsolete)
00404 {
00405 ResolverInfo_Ptr info = new ResolverInfoMissingReq (_item, _cap_leading_to_uninstall);
00406 context->addInfo (info);
00407 }
00408
00409
00410
00411
00412 CapSet provides = _item->dep(Dep::PROVIDES);
00413
00414 for (CapSet::const_iterator iter = provides.begin(); iter != provides.end(); iter++) {
00415 UninstallProcess info ( pool(), context, _item, _upgraded_to, qil, _remove_only, _soft);
00416
00417
00418 Dep dep( Dep::REQUIRES );
00419
00420 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00421 pool().byCapabilityIndexEnd( iter->index(), dep ),
00422 resfilter::ByCapMatch( *iter ),
00423 functor::functorRef<bool,CapAndItem>(info) );
00424
00425
00426
00427 UninstallEstablishItem establish( pool(), qil, _soft );
00428
00429 dep = Dep::SUPPLEMENTS;
00430 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00431 pool().byCapabilityIndexEnd( iter->index(), dep ),
00432 resfilter::ByCapMatch( *iter ),
00433 functor::functorRef<bool,CapAndItem>( establish ) );
00434
00435 dep = Dep::FRESHENS;
00436 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00437 pool().byCapabilityIndexEnd( iter->index(), dep ),
00438 resfilter::ByCapMatch( *iter ),
00439 functor::functorRef<bool,CapAndItem>( establish ) );
00440 }
00441
00442
00443
00444 if (_item->kind() == ResTraits<Patch>::kind) {
00445 Patch::constPtr patch = asKind<Patch>( _item );
00446 Patch::AtomList atoms = patch->atoms();
00447 UninstallItem callback( pool(), context, qil, _soft );
00448 CapFactory factory;
00449 Dep dep(Dep::PROVIDES);
00450
00451
00452
00453 for (Patch::AtomList::const_iterator it = atoms.begin(); it != atoms.end(); ++it) {
00454 Resolvable::constPtr res = *it;
00455 Capability capAtom = factory.parse ( res->kind(), res->name(), Rel::EQ, res->edition());
00456 invokeOnEach( pool().byCapabilityIndexBegin( capAtom.index(), dep ),
00457 pool().byCapabilityIndexEnd( capAtom.index(), dep ),
00458 functor::chain( resfilter::ByCaIInstalled(), resfilter::ByCapMatch( capAtom ) ),
00459 functor::functorRef<bool,CapAndItem>( callback ) );
00460 }
00461 }
00462
00463
00464
00465
00466 if (_upgraded_to
00467 || _item->kind() == ResTraits<Package>::kind)
00468 {
00469 goto finished;
00470 }
00471
00472 CapSet recomments = _item->dep (Dep::RECOMMENDS);
00473 for (CapSet::const_iterator iter = recomments.begin(); iter != recomments.end(); iter++) {
00474 const Capability cap = *iter;
00475 _XDEBUG("this recommends " << cap);
00476 ProvidesItem provides( pool(), qil, true );
00477
00478 Dep dep(Dep::PROVIDES);
00479 invokeOnEach( pool().byCapabilityIndexBegin( iter->index(), dep ),
00480 pool().byCapabilityIndexEnd( iter->index(), dep ),
00481 functor::chain( resfilter::ByCaIInstalled(), resfilter::ByCapMatch( *iter ) ),
00482 functor::functorRef<bool,CapAndItem>( provides ) );
00483 }
00484
00485 }
00486
00487 finished:
00488 return true;
00489 }
00490
00491
00492
00493 int
00494 QueueItemUninstall::cmp (QueueItem_constPtr item) const
00495 {
00496 int cmp = this->compare (item);
00497 if (cmp != 0)
00498 return cmp;
00499
00500 QueueItemUninstall_constPtr uninstall = dynamic_pointer_cast<const QueueItemUninstall>(item);
00501 return compareByNVRA (_item.resolvable(), uninstall->_item.resolvable());
00502 }
00503
00504
00505 QueueItem_Ptr
00506 QueueItemUninstall::copy (void) const
00507 {
00508 QueueItemUninstall_Ptr new_uninstall = new QueueItemUninstall (pool(), _item, _reason);
00509 new_uninstall->QueueItem::copy(this);
00510
00511
00512 new_uninstall->_item = _item;
00513 new_uninstall->_cap_leading_to_uninstall = _cap_leading_to_uninstall;
00514 new_uninstall->_upgraded_to = _upgraded_to;
00515
00516 new_uninstall->_explicitly_requested = _explicitly_requested;
00517 new_uninstall->_remove_only = _remove_only;
00518 new_uninstall->_due_to_conflict = _due_to_conflict;
00519 new_uninstall->_due_to_obsolete = _due_to_obsolete;
00520 new_uninstall->_obsoletes_item = _obsoletes_item;
00521 new_uninstall->_unlink = _unlink;
00522
00523 return new_uninstall;
00524 }
00525
00527 };
00530 };
00533 };
00535