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         /* FIXME: This should probably be a GVersion capability. */
00185         /* Obsoletes don't apply to virtual provides, only the items
00186          * themselves.  A provide is "virtual" if it's not the same spec
00187          * as the item that's providing it.  This, of course, only
00188          * applies to RPM, since it's the only one with obsoletes right
00189          * now. */
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             // maybe an upgrade can resolve the conflict ?
00212             //        check if other item is available which upgrades
00213 
00214             // find non-installed packages which provide the conflicting name
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             // pool->foreachProvidingResItem (maybe_upgrade_dep, upgrade_candidates_cb, (void *)&upgrade_info);
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                 // there are upgrade candidates for the conflicting item
00257                 // branch to: 1. uninstall, 2. upgrade (for each upgrading item)
00258                 _DEBUG("Branching: uninstall vs. upgrade");
00259                 QueueItemBranch_Ptr branch = new QueueItemBranch (pool);
00260 
00261                 branch->addItem (uninstall);                    // try 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);                  // try 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             /* This is the easy case -- we do nothing. */
00299         }
00300         else {
00301             ZYPP_THROW (Exception ("Unhandled status in ConflictProcess"));
00302         }
00303 
00304         return true;
00305 
00306     } // operator ()
00307 
00308 }; // struct ConflictProcess
00309 
00310 
00311 bool
00312 QueueItemConflict::process (ResolverContext_Ptr context, QueueItemList & new_items)
00313 {
00314     _XDEBUG("QueueItemConflict::process(" << *this << ")");
00315 
00316     // checking for ignoring dependencies
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     // world()->foreachProvidingPoolItem (_capability, conflict_process_cb, (void *)&info);
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     // _actually_an_obsolete is not being copied !
00352 
00353     return new_conflict;
00354 }
00355 
00356 
00357 int
00358 QueueItemConflict::cmp (QueueItem_constPtr item) const
00359 {
00360     int cmp = this->compare (item);             // assures equal type
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     };// namespace detail
00375   };// namespace solver
00378 };// namespace zypp

Generated on Thu Jul 6 00:07:23 2006 for zypp by  doxygen 1.4.6