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 #define PHI 1
00063 
00064 //---------------------------------------------------------------------------
00065 
00066 std::ostream &
00067 QueueItemConflict::dumpOn( std::ostream & os ) const
00068 {
00069     os << "[" << (_soft?"Soft":"") << "Conflict: ";
00070     os << _capability;
00071     os << ", Triggered by ";
00072     os << _conflicting_item;
00073     if (_actually_an_obsolete) os << ", Obsolete !";
00074     if (_explicitly_requested) os << ", Explicit";    
00075     os << "]";
00076     return os;
00077 }
00078 
00079 //---------------------------------------------------------------------------
00080 
00081 QueueItemConflict::QueueItemConflict (const ResPool & pool, const Capability & cap, PoolItem_Ref item, bool soft)
00082     : QueueItem (QUEUE_ITEM_TYPE_CONFLICT, pool)
00083     , _capability (cap)
00084     , _conflicting_item (item)
00085     , _soft (soft)
00086     , _actually_an_obsolete (false)
00087     , _explicitly_requested (false)    
00088 {
00089     _XDEBUG("QueueItemConflict::QueueItemConflict(" << cap << ", " << item << (soft?", soft":"") << ")");
00090 }
00091 
00092 
00093 QueueItemConflict::~QueueItemConflict()
00094 {
00095 }
00096 
00097 //---------------------------------------------------------------------------
00098 
00099 #if PHI
00100 
00101 // on conflict, try to find upgrade candidates for the installed item triggering the conflict
00102 // there are cases where upgrading prevents the conflict
00103 // rc tends to uninstall the item
00104 // phi tends to upgrade the item
00105 // testcases: exercise-02conflict-08-test.xml, exercise-02conflict-09-test.xml
00106 
00107 struct UpgradeCandidate
00108 {
00109     PoolItem_Ref item; // the conflicting resolvable, used to filter upgrades with an identical resolvable
00110     ResolverContext_Ptr context;
00111     PoolItemList upgrades;
00112 
00113     UpgradeCandidate (PoolItem_Ref pi, ResolverContext_Ptr ctx)
00114         : item (pi)
00115         , context (ctx)
00116     { }
00117 
00118     bool operator() (const CapAndItem & cai)
00119     {
00120 
00121         PoolItem candidate = cai.item;
00122 
00123 //MIL << "UpgradeCandidate? " << candidate << ":[" << context->getStatus (candidate) << "]" << (item->edition().compare(candidate->edition())) << "<" << item->arch() << "," << candidate->arch() << ">" << endl;
00124 // FIXME put this in the resfilter chain
00125         ResStatus status = context->getStatus (candidate);
00126         if ((item->edition().compare(candidate->edition()) < 0)         // look at real upgrades
00127             && item->arch() == candidate->arch()                        // keep the architecture
00128             && (status.isUninstalled()
00129                 || status.isToBeUninstalled())                          // FIXME: just for exercise-02conflict-03-test.xml
00130                                                                         // the original solver found the uninstalled foo-2.0.1 first, this solver
00131                                                                         // finds the uninstallable first. In the end, we had a duplicate solution
00132                                                                         // now we have no solution. Both results are right.
00133            && (!status.isImpossible()) )
00134         {
00135 //MIL << "UpgradeCandidate! " << candidate << endl;
00136             upgrades.push_back (candidate);
00137         }
00138         return true;
00139     }
00140 };
00141 
00142 #endif  // PHI
00143 
00144 
00145 //---------------------------------------------------------------------------------------
00146 
00147 struct ConflictProcess
00148 {
00149     ResPool pool;
00150     PoolItem_Ref conflict_issuer;                       // the item which issues 'conflicts:'
00151     const Capability conflict_capability;               // the capability mentioned in the 'conflicts'
00152     ResolverContext_Ptr context;
00153     QueueItemList & new_items;
00154     bool actually_an_obsolete;
00155     bool explicitly_requested;
00156 
00157     ConflictProcess (const ResPool & pl, PoolItem_Ref ci, const Capability & cc, ResolverContext_Ptr ct, QueueItemList & ni, bool ao,
00158                      bool er)
00159         : pool (pl)
00160         , conflict_issuer (ci)
00161         , conflict_capability (cc)
00162         , context (ct)
00163         , new_items (ni)
00164         , actually_an_obsolete (ao)
00165         , explicitly_requested (er)
00166     { }
00167 
00168     bool operator()( const CapAndItem & cai )
00169     {
00170         ResStatus status;
00171         ResolverInfo_Ptr log_info;
00172         CapFactory factory;
00173 
00174         PoolItem provider = cai.item;
00175         Capability provides = cai.cap;
00176 
00177         _XDEBUG("conflict_process_cb (resolvable[" << provider <<"], provides[" << provides << "], conflicts with [" <<
00178               conflict_issuer << " conflicts: " << conflict_capability);
00179 
00180         /* We conflict with ourself.  For the purpose of installing ourself, we
00181          * just ignore it, but it's Debian's way of saying that one and only one
00182          * item with this provide may exist on the system at a time. */
00183 
00184         if (conflict_issuer
00185             && compareByNVRA (provider.resolvable(), conflict_issuer.resolvable()) == 0)
00186         {
00187             _XDEBUG("self-conflict");
00188             return true;
00189         }
00190 
00191 #if 0 // Bug    220999; RPM does obsolete virtual provides too
00192 
00193         
00194         /* FIXME: This should probably be a GVersion capability. */
00195         /* Obsoletes don't apply to virtual provides, only the items
00196          * themselves.  A provide is "virtual" if it's not the same spec
00197          * as the item that's providing it.  This, of course, only
00198          * applies to RPM, since it's the only one with obsoletes right
00199          * now. */
00200         Capability capTest =  factory.parse ( provider->kind(), provider->name(), Rel::EQ, provider->edition());
00201 
00202         if (actually_an_obsolete
00203             && capTest.matches (provides) != CapMatch::yes )
00204         {
00205             _XDEBUG("obsolete to virtual provide - ignoring");
00206             return true;
00207         }
00208         
00209 #endif // Bug   220999; RPM does obsolete virtual provides too  
00210 
00211         status = context->getStatus(provider);
00212 
00213         _XDEBUG("ConflictProcess (provider[" << provider << "]<" << status << ">");
00214 
00215         if (status.staysInstalled()
00216             || status.isToBeInstalledSoft())
00217         {
00218             ResolverInfo_Ptr log_info;
00219 
00220 #if PHI
00221             _XDEBUG("Provider is installed - try upgrade");
00222 
00223             // maybe an upgrade can resolve the conflict ?
00224             //        check if other item is available which upgrades
00225 
00226             // find non-installed packages which provide the conflicting name
00227 
00228             UpgradeCandidate upgrade_info (provider, context);
00229 
00230             Capability maybe_upgrade_cap =  factory.parse ( provider->kind(), provider->name(), Rel::ANY, Edition::noedition );
00231 
00232             // pool->foreachProvidingResItem (maybe_upgrade_dep, upgrade_candidates_cb, (void *)&upgrade_info);
00233             Dep dep( Dep::PROVIDES );
00234 
00235             if (!actually_an_obsolete) { // The resolvable will be obsoleted by another. So it is useless finding an update candidate.
00236                 invokeOnEach( pool.byCapabilityIndexBegin( maybe_upgrade_cap.index(), dep ),
00237                               pool.byCapabilityIndexEnd( maybe_upgrade_cap.index(), dep ),
00238                               resfilter::ByCapMatch( maybe_upgrade_cap ),
00239                               functor::functorRef<bool,CapAndItem>(upgrade_info) );
00240 
00241                 _XDEBUG("found " << upgrade_info.upgrades.size() << " upgrade candidates");
00242             }
00243 #endif
00244 
00245             QueueItemUninstall_Ptr uninstall = new QueueItemUninstall (pool, provider, actually_an_obsolete ? QueueItemUninstall::OBSOLETE : QueueItemUninstall::CONFLICT);
00246             uninstall->setCapability (conflict_capability);
00247             if (explicitly_requested)
00248                 uninstall->setExplicitlyRequested();
00249 
00250             if (actually_an_obsolete) {
00251                 uninstall->setDueToObsolete (conflict_issuer);
00252                 log_info = new ResolverInfoObsoletes (provider,
00253                                                       conflict_issuer);
00254             } else {
00255                 uninstall->setDueToConflict ();
00256                 log_info = new ResolverInfoConflictsWith (provider,
00257                                                           conflict_issuer,
00258                                                           conflict_capability);
00259             }
00260 
00261             uninstall->addInfo (log_info);
00262 
00263 #if PHI
00264             if (upgrade_info.upgrades.empty ()) {
00265 #endif
00266 
00267                 new_items.push_back (uninstall);
00268 
00269 #if PHI
00270             }
00271             else {
00272                 // there are upgrade candidates for the conflicting item
00273                 // branch to: 1. uninstall, 2. upgrade (for each upgrading item)
00274                 _DEBUG("Branching: uninstall vs. upgrade");
00275                 QueueItemBranch_Ptr branch = new QueueItemBranch (pool);
00276 
00277                 branch->addItem (uninstall);                    // try uninstall
00278 
00279                 for (PoolItemList::const_iterator iter = upgrade_info.upgrades.begin(); iter != upgrade_info.upgrades.end(); iter++) {
00280                     QueueItemInstall_Ptr upgrade = new QueueItemInstall (pool, *iter);
00281                     upgrade->setUpgrades (provider);
00282                     branch->addItem (upgrade);                  // try upgrade
00283                 }
00284                 new_items.push_back (branch);
00285             }
00286 #endif
00287 
00288         }
00289         else if (status.isToBeInstalled()) {
00290             ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CONFLICT_CANT_INSTALL, provider, RESOLVER_INFO_PRIORITY_VERBOSE, provides);
00291             if (conflict_issuer) {
00292                 misc_info->setOtherPoolItem (conflict_issuer);
00293                 misc_info->setOtherCapability (conflict_capability);
00294             }
00295             context->addError (misc_info);
00296 
00297         }
00298         else if (status.wasUninstalled()) {
00299 
00300             context->setStatus (provider, ResStatus::impossible);
00301 
00302             ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CONFLICT_UNINSTALLABLE, provider, RESOLVER_INFO_PRIORITY_VERBOSE, provides);
00303 
00304             misc_info->setOtherPoolItem (conflict_issuer);
00305             misc_info->setOtherCapability (conflict_capability);
00306 
00307             context->addInfo (misc_info);
00308 
00309         }
00310         else if (status.isToBeUninstalled()
00311                 || status.isImpossible()
00312                 || status.isToBeUninstalledDueToObsolete()) {
00313 
00314             /* This is the easy case -- we do nothing. */
00315         }
00316         else {
00317             ERR << "Unhandled status in ConflictProcess; item: " << provider << " : " << status << endl;
00318         }
00319 
00320         return true;
00321 
00322     } // operator ()
00323 
00324 }; // struct ConflictProcess
00325 
00326 
00327 bool
00328 QueueItemConflict::process (const QueueItemList & mainQueue, ResolverContext_Ptr context, QueueItemList & new_items)
00329 {
00330     _XDEBUG("QueueItemConflict::process(" << *this << ")");
00331 
00332     // checking for ignoring dependencies
00333     IgnoreMap ignoreMap = context->getIgnoreConflicts();    
00334     for (IgnoreMap::iterator it = ignoreMap.begin();
00335          it != ignoreMap.end(); it++) {
00336         if (it->first == _conflicting_item
00337             && it->second == _capability) {
00338             _XDEBUG("Found ignoring requires " << _capability << " for " << _conflicting_item);
00339             return true;
00340         } else {
00341             _XDEBUG("Ignoring requires " << it->second << " for " <<  it->first << " does not fit");        
00342         }
00343     }
00344 
00345     ConflictProcess info (pool(), _conflicting_item, _capability, context, new_items, _actually_an_obsolete, _explicitly_requested);
00346 
00347     // world()->foreachProvidingPoolItem (_capability, conflict_process_cb, (void *)&info);
00348 
00349     Dep dep( Dep::PROVIDES );
00350     invokeOnEach( pool().byCapabilityIndexBegin( _capability.index(), dep ),
00351                   pool().byCapabilityIndexEnd( _capability.index(), dep ),
00352                   resfilter::ByCapMatch( _capability ),
00353                   functor::functorRef<bool,CapAndItem>(info) );
00354 
00355     return true;
00356 }
00357 
00358 
00359 //---------------------------------------------------------------------------
00360 
00361 QueueItem_Ptr
00362 QueueItemConflict::copy (void) const
00363 {
00364     QueueItemConflict_Ptr new_conflict = new QueueItemConflict (pool(), _capability, _conflicting_item);
00365     new_conflict->QueueItem::copy(this);
00366 
00367     // _actually_an_obsolete is not being copied !
00368     new_conflict->_explicitly_requested      = _explicitly_requested;    
00369 
00370     return new_conflict;
00371 }
00372 
00373 
00374 int
00375 QueueItemConflict::cmp (QueueItem_constPtr item) const
00376 {
00377     int cmp = this->compare (item);             // assures equal type
00378     if (cmp != 0)
00379         return cmp;
00380 
00381     QueueItemConflict_constPtr conflict = dynamic_pointer_cast<const QueueItemConflict>(item);
00382     if ( _capability != conflict->capability())
00383         cmp = -1;
00384 
00385     return cmp;
00386 }
00387 
00389     };// namespace detail
00392   };// namespace solver
00395 };// namespace zypp

Generated on Tue Sep 25 19:23:07 2007 for libzypp by  doxygen 1.5.3