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
00185
00186
00187
00188
00189
00190 Capability capTest = factory.parse ( provider->kind(), provider->name(), Rel::EQ, provider->edition());
00191
00192 if (actually_an_obsolete
00193 && capTest.matches (provides) != CapMatch::yes )
00194 {
00195 _XDEBUG("obsolete to virtual provide - ignoring");
00196 return true;
00197 }
00198
00199 status = context->getStatus(provider);
00200
00201 _XDEBUG("ConflictProcess (provider[" << provider << "]<" << status << ">");
00202
00203 if (status.staysInstalled()
00204 || status.isToBeInstalledSoft())
00205 {
00206 ResolverInfo_Ptr log_info;
00207
00208 #if PHI
00209 _XDEBUG("Provider is installed - try upgrade");
00210
00211
00212
00213
00214
00215
00216 UpgradeCandidate upgrade_info (provider, context);
00217
00218 Capability maybe_upgrade_cap = factory.parse ( provider->kind(), provider->name(), Rel::ANY, Edition::noedition );
00219
00220
00221 Dep dep( Dep::PROVIDES );
00222
00223 invokeOnEach( pool.byCapabilityIndexBegin( maybe_upgrade_cap.index(), dep ),
00224 pool.byCapabilityIndexEnd( maybe_upgrade_cap.index(), dep ),
00225 resfilter::ByCapMatch( maybe_upgrade_cap ),
00226 functor::functorRef<bool,CapAndItem>(upgrade_info) );
00227
00228 _XDEBUG("found " << upgrade_info.upgrades.size() << " upgrade candidates");
00229 #endif
00230
00231 QueueItemUninstall_Ptr uninstall = new QueueItemUninstall (pool, provider, actually_an_obsolete ? QueueItemUninstall::OBSOLETE : QueueItemUninstall::CONFLICT);
00232 uninstall->setCapability (conflict_capability);
00233
00234 if (actually_an_obsolete) {
00235 uninstall->setDueToObsolete (conflict_issuer);
00236 log_info = new ResolverInfoObsoletes (provider,
00237 conflict_issuer);
00238 } else {
00239 uninstall->setDueToConflict ();
00240 log_info = new ResolverInfoConflictsWith (provider,
00241 conflict_issuer,
00242 conflict_capability);
00243 }
00244
00245 uninstall->addInfo (log_info);
00246
00247 #if PHI
00248 if (upgrade_info.upgrades.empty ()) {
00249 #endif
00250
00251 new_items.push_back (uninstall);
00252
00253 #if PHI
00254 }
00255 else {
00256
00257
00258 _DEBUG("Branching: uninstall vs. upgrade");
00259 QueueItemBranch_Ptr branch = new QueueItemBranch (pool);
00260
00261 branch->addItem (uninstall);
00262
00263 for (PoolItemList::const_iterator iter = upgrade_info.upgrades.begin(); iter != upgrade_info.upgrades.end(); iter++) {
00264 QueueItemInstall_Ptr upgrade = new QueueItemInstall (pool, *iter);
00265 upgrade->setUpgrades (provider);
00266 branch->addItem (upgrade);
00267 }
00268 new_items.push_back (branch);
00269 }
00270 #endif
00271
00272 }
00273 else if (status.isToBeInstalled()) {
00274 ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CONFLICT_CANT_INSTALL, provider, RESOLVER_INFO_PRIORITY_VERBOSE, provides);
00275 if (conflict_issuer) {
00276 misc_info->setOtherPoolItem (conflict_issuer);
00277 misc_info->setOtherCapability (conflict_capability);
00278 }
00279 context->addError (misc_info);
00280
00281 }
00282 else if (status.wasUninstalled()) {
00283
00284 context->setStatus (provider, ResStatus::impossible);
00285
00286 ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CONFLICT_UNINSTALLABLE, provider, RESOLVER_INFO_PRIORITY_VERBOSE, provides);
00287
00288 misc_info->setOtherPoolItem (conflict_issuer);
00289 misc_info->setOtherCapability (conflict_capability);
00290
00291 context->addInfo (misc_info);
00292
00293 }
00294 else if ((status.isToBeUninstalled() && !status.isToBeUninstalledDueToUnlink())
00295 || status.isImpossible()
00296 || status.isToBeUninstalledDueToObsolete()) {
00297
00298
00299 }
00300 else {
00301 ZYPP_THROW (Exception ("Unhandled status in ConflictProcess"));
00302 }
00303
00304 return true;
00305
00306 }
00307
00308 };
00309
00310
00311 bool
00312 QueueItemConflict::process (ResolverContext_Ptr context, QueueItemList & new_items)
00313 {
00314 _XDEBUG("QueueItemConflict::process(" << *this << ")");
00315
00316
00317 IgnoreMap ignoreMap = context->getIgnoreConflicts();
00318 for (IgnoreMap::iterator it = ignoreMap.begin();
00319 it != ignoreMap.end(); it++) {
00320 if (it->first == _conflicting_item
00321 && it->second == _capability) {
00322 _XDEBUG("Found ignoring requires " << _capability << " for " << _conflicting_item);
00323 return true;
00324 } else {
00325 _XDEBUG("Ignoring requires " << it->second << " for " << it->first << " does not fit");
00326 }
00327 }
00328
00329 ConflictProcess info (pool(), _conflicting_item, _capability, context, new_items, _actually_an_obsolete);
00330
00331
00332
00333 Dep dep( Dep::PROVIDES );
00334 invokeOnEach( pool().byCapabilityIndexBegin( _capability.index(), dep ),
00335 pool().byCapabilityIndexEnd( _capability.index(), dep ),
00336 resfilter::ByCapMatch( _capability ),
00337 functor::functorRef<bool,CapAndItem>(info) );
00338
00339 return true;
00340 }
00341
00342
00343
00344
00345 QueueItem_Ptr
00346 QueueItemConflict::copy (void) const
00347 {
00348 QueueItemConflict_Ptr new_conflict = new QueueItemConflict (pool(), _capability, _conflicting_item);
00349 new_conflict->QueueItem::copy(this);
00350
00351
00352
00353 return new_conflict;
00354 }
00355
00356
00357 int
00358 QueueItemConflict::cmp (QueueItem_constPtr item) const
00359 {
00360 int cmp = this->compare (item);
00361 if (cmp != 0)
00362 return cmp;
00363
00364 QueueItemConflict_constPtr conflict = dynamic_pointer_cast<const QueueItemConflict>(item);
00365 if ( _capability != conflict->capability())
00366 cmp = -1;
00367
00368 return cmp;
00369 }
00370
00372 };
00375 };
00378 };