QueueItemConflict.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /* QueueItemConflict.cc
00003  *
00004  * Copyright (C) 2000-2002 Ximian, Inc.
00005  * Copyright (C) 2005 SUSE Linux Products GmbH
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License,
00009  * version 2, as published by the Free Software Foundation.
00010  *
00011  * This program is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019  * 02111-1307, USA.
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 // on conflict, try to find upgrade candidates for the installed item triggering the conflict
00098 // there are cases where upgrading prevents the conflict
00099 // rc tends to uninstall the item
00100 // phi tends to upgrade the item
00101 // testcases: exercise-02conflict-08-test.xml, exercise-02conflict-09-test.xml
00102 
00103 struct UpgradeCandidate
00104 {
00105     PoolItem_Ref item; // the conflicting resolvable, used to filter upgrades with an identical resolvable
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 //MIL << "UpgradeCandidate? " << candidate << ":[" << context->getStatus (candidate) << "]" << (item->edition().compare(candidate->edition())) << "<" << item->arch() << "," << candidate->arch() << ">" << endl;
00120 // FIXME put this in the resfilter chain
00121         ResStatus status = context->getStatus (candidate);
00122         if ((item->edition().compare(candidate->edition()) < 0)         // look at real upgrades
00123             && item->arch() == candidate->arch()                        // keep the architecture
00124             && (status.wasUninstalled()
00125                 || status.isToBeUninstalled())                          // FIXME: just for exercise-02conflict-03-test.xml
00126                                                                         // the original solver found the uninstalled foo-2.0.1 first, this solver
00127                                                                         // finds the uninstallable first. In the end, we had a duplicate solution
00128                                                                         // now we have no solution. Both results are right.
00129            && (!status.isImpossible()) )
00130         {
00131 //MIL << "UpgradeCandidate! " << candidate << endl;
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;                       // the item which issues 'conflicts:'
00147     const Capability conflict_capability;               // the capability mentioned in the 'conflicts'
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         /* We conflict with ourself.  For the purpose of installing ourself, we
00174          * just ignore it, but it's Debian's way of saying that one and only one
00175          * item with this provide may exist on the system at a time. */
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         /* FIXME: This should probably be a GVersion capability. */
00188         /* Obsoletes don't apply to virtual provides, only the items
00189          * themselves.  A provide is "virtual" if it's not the same spec
00190          * as the item that's providing it.  This, of course, only
00191          * applies to RPM, since it's the only one with obsoletes right
00192          * now. */
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             // maybe an upgrade can resolve the conflict ?
00217             //        check if other item is available which upgrades
00218 
00219             // find non-installed packages which provide the conflicting name
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             // pool->foreachProvidingResItem (maybe_upgrade_dep, upgrade_candidates_cb, (void *)&upgrade_info);
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                 // there are upgrade candidates for the conflicting item
00262                 // branch to: 1. uninstall, 2. upgrade (for each upgrading item)
00263                 _DEBUG("Branching: uninstall vs. upgrade");
00264                 QueueItemBranch_Ptr branch = new QueueItemBranch (pool);
00265 
00266                 branch->addItem (uninstall);                    // try 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);                  // try 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             /* This is the easy case -- we do nothing. */
00304         }
00305         else {
00306             ZYPP_THROW (Exception ("Unhandled status in ConflictProcess"));
00307         }
00308 
00309         return true;
00310 
00311     } // operator ()
00312 
00313 }; // struct ConflictProcess
00314 
00315 
00316 bool
00317 QueueItemConflict::process (ResolverContext_Ptr context, QueueItemList & new_items)
00318 {
00319     _XDEBUG("QueueItemConflict::process(" << *this << ")");
00320 
00321     // checking for ignoring dependencies
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     // world()->foreachProvidingPoolItem (_capability, conflict_process_cb, (void *)&info);
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     // _actually_an_obsolete is not being copied !
00357 
00358     return new_conflict;
00359 }
00360 
00361 
00362 int
00363 QueueItemConflict::cmp (QueueItem_constPtr item) const
00364 {
00365     int cmp = this->compare (item);             // assures equal type
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     };// namespace detail
00380   };// namespace solver
00383 };// namespace zypp

Generated on Tue Nov 28 16:49:31 2006 for zypp by  doxygen 1.5.0