00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "zypp/CapFactory.h"
00023 #include "zypp/CapSet.h"
00024 #include "zypp/CapMatch.h"
00025 #include "zypp/base/Logger.h"
00026 #include "zypp/base/String.h"
00027 #include "zypp/base/Gettext.h"
00028 #include "zypp/base/Exception.h"
00029
00030 #include "zypp/base/Algorithm.h"
00031 #include "zypp/ResPool.h"
00032 #include "zypp/ResFilters.h"
00033 #include "zypp/CapFilters.h"
00034 #include "zypp/CapAndItem.h"
00035
00036 #include "zypp/solver/detail/Types.h"
00037
00038 #include "zypp/solver/detail/QueueItemConflict.h"
00039 #include "zypp/solver/detail/QueueItemBranch.h"
00040 #include "zypp/solver/detail/QueueItemInstall.h"
00041 #include "zypp/solver/detail/QueueItemUninstall.h"
00042 #include "zypp/solver/detail/QueueItem.h"
00043 #include "zypp/solver/detail/ResolverContext.h"
00044 #include "zypp/solver/detail/ResolverInfoConflictsWith.h"
00045 #include "zypp/solver/detail/ResolverInfoMisc.h"
00046 #include "zypp/solver/detail/ResolverInfoObsoletes.h"
00047
00049 namespace zypp
00050 {
00051
00052 namespace solver
00053 {
00054
00055 namespace detail
00056 {
00057
00058 using namespace std;
00059
00060 IMPL_PTR_TYPE(QueueItemConflict);
00061
00062
00063
00064 std::ostream &
00065 QueueItemConflict::dumpOn( std::ostream & os ) const
00066 {
00067 os << "[" << (_soft?"Soft":"") << "Conflict: ";
00068 os << _capability;
00069 os << ", Triggered by ";
00070 os << _conflicting_item;
00071 if (_actually_an_obsolete) os << ", Obsolete !";
00072 os << "]";
00073 return os;
00074 }
00075
00076
00077
00078 QueueItemConflict::QueueItemConflict (const ResPool & pool, const Capability & cap, PoolItem_Ref item, bool soft)
00079 : QueueItem (QUEUE_ITEM_TYPE_CONFLICT, pool)
00080 , _capability (cap)
00081 , _conflicting_item (item)
00082 , _soft (soft)
00083 , _actually_an_obsolete (false)
00084 {
00085 _XDEBUG("QueueItemConflict::QueueItemConflict(" << cap << ", " << item << (soft?", soft":"") << ")");
00086 }
00087
00088
00089 QueueItemConflict::~QueueItemConflict()
00090 {
00091 }
00092
00093
00094
00095 #if PHI
00096
00097
00098
00099
00100
00101
00102
00103 struct UpgradeCandidate
00104 {
00105 PoolItem_Ref item;
00106 ResolverContext_Ptr context;
00107 PoolItemList upgrades;
00108
00109 UpgradeCandidate (PoolItem_Ref pi, ResolverContext_Ptr ctx)
00110 : item (pi)
00111 , context (ctx)
00112 { }
00113
00114 bool operator() (const CapAndItem & cai)
00115 {
00116
00117 PoolItem candidate = cai.item;
00118
00119
00120
00121 ResStatus status = context->getStatus (candidate);
00122 if ((item->edition().compare(candidate->edition()) < 0)
00123 && item->arch() == candidate->arch()
00124 && (status.wasUninstalled()
00125 || status.isToBeUninstalled())
00126
00127
00128
00129 && (!status.isImpossible()) )
00130 {
00131
00132 upgrades.push_back (candidate);
00133 }
00134 return true;
00135 }
00136 };
00137
00138 #endif // PHI
00139
00140
00141
00142
00143 struct ConflictProcess
00144 {
00145 ResPool pool;
00146 PoolItem_Ref conflict_issuer;
00147 const Capability conflict_capability;
00148 ResolverContext_Ptr context;
00149 QueueItemList & new_items;
00150 bool actually_an_obsolete;
00151
00152 ConflictProcess (const ResPool & pl, PoolItem_Ref ci, const Capability & cc, ResolverContext_Ptr ct, QueueItemList & ni, bool ao)
00153 : pool (pl)
00154 , conflict_issuer (ci)
00155 , conflict_capability (cc)
00156 , context (ct)
00157 , new_items (ni)
00158 , actually_an_obsolete (ao)
00159 { }
00160
00161 bool operator()( const CapAndItem & cai )
00162 {
00163 ResStatus status;
00164 ResolverInfo_Ptr log_info;
00165 CapFactory factory;
00166
00167 PoolItem provider = cai.item;
00168 Capability provides = cai.cap;
00169
00170 _XDEBUG("conflict_process_cb (resolvable[" << provider <<"], provides[" << provides << "], conflicts with [" <<
00171 conflict_issuer << " conflicts: " << conflict_capability);
00172
00173
00174
00175
00176
00177 if (conflict_issuer
00178 && compareByNVRA (provider.resolvable(), conflict_issuer.resolvable()) == 0)
00179 {
00180 _XDEBUG("self-conflict");
00181 return true;
00182 }
00183
00184 #if 0 // Bug 220999; RPM does obsolete virtual provides too
00185
00186
00187
00188
00189
00190
00191
00192
00193 Capability capTest = factory.parse ( provider->kind(), provider->name(), Rel::EQ, provider->edition());
00194
00195 if (actually_an_obsolete
00196 && capTest.matches (provides) != CapMatch::yes )
00197 {
00198 _XDEBUG("obsolete to virtual provide - ignoring");
00199 return true;
00200 }
00201
00202 #endif // Bug 220999; RPM does obsolete virtual provides too
00203
00204 status = context->getStatus(provider);
00205
00206 _XDEBUG("ConflictProcess (provider[" << provider << "]<" << status << ">");
00207
00208 if (status.staysInstalled()
00209 || status.isToBeInstalledSoft())
00210 {
00211 ResolverInfo_Ptr log_info;
00212
00213 #if PHI
00214 _XDEBUG("Provider is installed - try upgrade");
00215
00216
00217
00218
00219
00220
00221 UpgradeCandidate upgrade_info (provider, context);
00222
00223 Capability maybe_upgrade_cap = factory.parse ( provider->kind(), provider->name(), Rel::ANY, Edition::noedition );
00224
00225
00226 Dep dep( Dep::PROVIDES );
00227
00228 invokeOnEach( pool.byCapabilityIndexBegin( maybe_upgrade_cap.index(), dep ),
00229 pool.byCapabilityIndexEnd( maybe_upgrade_cap.index(), dep ),
00230 resfilter::ByCapMatch( maybe_upgrade_cap ),
00231 functor::functorRef<bool,CapAndItem>(upgrade_info) );
00232
00233 _XDEBUG("found " << upgrade_info.upgrades.size() << " upgrade candidates");
00234 #endif
00235
00236 QueueItemUninstall_Ptr uninstall = new QueueItemUninstall (pool, provider, actually_an_obsolete ? QueueItemUninstall::OBSOLETE : QueueItemUninstall::CONFLICT);
00237 uninstall->setCapability (conflict_capability);
00238
00239 if (actually_an_obsolete) {
00240 uninstall->setDueToObsolete (conflict_issuer);
00241 log_info = new ResolverInfoObsoletes (provider,
00242 conflict_issuer);
00243 } else {
00244 uninstall->setDueToConflict ();
00245 log_info = new ResolverInfoConflictsWith (provider,
00246 conflict_issuer,
00247 conflict_capability);
00248 }
00249
00250 uninstall->addInfo (log_info);
00251
00252 #if PHI
00253 if (upgrade_info.upgrades.empty ()) {
00254 #endif
00255
00256 new_items.push_back (uninstall);
00257
00258 #if PHI
00259 }
00260 else {
00261
00262
00263 _DEBUG("Branching: uninstall vs. upgrade");
00264 QueueItemBranch_Ptr branch = new QueueItemBranch (pool);
00265
00266 branch->addItem (uninstall);
00267
00268 for (PoolItemList::const_iterator iter = upgrade_info.upgrades.begin(); iter != upgrade_info.upgrades.end(); iter++) {
00269 QueueItemInstall_Ptr upgrade = new QueueItemInstall (pool, *iter);
00270 upgrade->setUpgrades (provider);
00271 branch->addItem (upgrade);
00272 }
00273 new_items.push_back (branch);
00274 }
00275 #endif
00276
00277 }
00278 else if (status.isToBeInstalled()) {
00279 ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CONFLICT_CANT_INSTALL, provider, RESOLVER_INFO_PRIORITY_VERBOSE, provides);
00280 if (conflict_issuer) {
00281 misc_info->setOtherPoolItem (conflict_issuer);
00282 misc_info->setOtherCapability (conflict_capability);
00283 }
00284 context->addError (misc_info);
00285
00286 }
00287 else if (status.wasUninstalled()) {
00288
00289 context->setStatus (provider, ResStatus::impossible);
00290
00291 ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CONFLICT_UNINSTALLABLE, provider, RESOLVER_INFO_PRIORITY_VERBOSE, provides);
00292
00293 misc_info->setOtherPoolItem (conflict_issuer);
00294 misc_info->setOtherCapability (conflict_capability);
00295
00296 context->addInfo (misc_info);
00297
00298 }
00299 else if ((status.isToBeUninstalled() && !status.isToBeUninstalledDueToUnlink())
00300 || status.isImpossible()
00301 || status.isToBeUninstalledDueToObsolete()) {
00302
00303
00304 }
00305 else {
00306 ZYPP_THROW (Exception ("Unhandled status in ConflictProcess"));
00307 }
00308
00309 return true;
00310
00311 }
00312
00313 };
00314
00315
00316 bool
00317 QueueItemConflict::process (ResolverContext_Ptr context, QueueItemList & new_items)
00318 {
00319 _XDEBUG("QueueItemConflict::process(" << *this << ")");
00320
00321
00322 IgnoreMap ignoreMap = context->getIgnoreConflicts();
00323 for (IgnoreMap::iterator it = ignoreMap.begin();
00324 it != ignoreMap.end(); it++) {
00325 if (it->first == _conflicting_item
00326 && it->second == _capability) {
00327 _XDEBUG("Found ignoring requires " << _capability << " for " << _conflicting_item);
00328 return true;
00329 } else {
00330 _XDEBUG("Ignoring requires " << it->second << " for " << it->first << " does not fit");
00331 }
00332 }
00333
00334 ConflictProcess info (pool(), _conflicting_item, _capability, context, new_items, _actually_an_obsolete);
00335
00336
00337
00338 Dep dep( Dep::PROVIDES );
00339 invokeOnEach( pool().byCapabilityIndexBegin( _capability.index(), dep ),
00340 pool().byCapabilityIndexEnd( _capability.index(), dep ),
00341 resfilter::ByCapMatch( _capability ),
00342 functor::functorRef<bool,CapAndItem>(info) );
00343
00344 return true;
00345 }
00346
00347
00348
00349
00350 QueueItem_Ptr
00351 QueueItemConflict::copy (void) const
00352 {
00353 QueueItemConflict_Ptr new_conflict = new QueueItemConflict (pool(), _capability, _conflicting_item);
00354 new_conflict->QueueItem::copy(this);
00355
00356
00357
00358 return new_conflict;
00359 }
00360
00361
00362 int
00363 QueueItemConflict::cmp (QueueItem_constPtr item) const
00364 {
00365 int cmp = this->compare (item);
00366 if (cmp != 0)
00367 return cmp;
00368
00369 QueueItemConflict_constPtr conflict = dynamic_pointer_cast<const QueueItemConflict>(item);
00370 if ( _capability != conflict->capability())
00371 cmp = -1;
00372
00373 return cmp;
00374 }
00375
00377 };
00380 };
00383 };