QueueItemInstall.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /* QueueItemInstall.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/Package.h"
00025 #include "zypp/base/Logger.h"
00026 #include "zypp/base/String.h"
00027 #include "zypp/base/Gettext.h"
00028 
00029 #include "zypp/base/Algorithm.h"
00030 #include "zypp/ResPool.h"
00031 #include "zypp/ResFilters.h"
00032 #include "zypp/CapFilters.h"
00033 
00034 #include "zypp/solver/detail/QueueItemInstall.h"
00035 #include "zypp/solver/detail/QueueItemEstablish.h"
00036 #include "zypp/solver/detail/QueueItemUninstall.h"
00037 #include "zypp/solver/detail/QueueItemRequire.h"
00038 #include "zypp/solver/detail/QueueItemConflict.h"
00039 #include "zypp/solver/detail/QueueItem.h"
00040 #include "zypp/solver/detail/ResolverContext.h"
00041 #include "zypp/solver/detail/ResolverInfoConflictsWith.h"
00042 #include "zypp/solver/detail/ResolverInfoMisc.h"
00043 #include "zypp/solver/detail/ResolverInfoNeededBy.h"
00044 #include "zypp/solver/detail/Helper.h"
00045 
00047 namespace zypp
00048 { 
00049 
00050   namespace solver
00051   { 
00052 
00053     namespace detail
00054     { 
00055 
00056 using namespace std;
00057 
00058 IMPL_PTR_TYPE(QueueItemInstall);
00059 
00060 //---------------------------------------------------------------------------
00061 
00062 std::ostream &
00063 QueueItemInstall::dumpOn( std::ostream & os ) const
00064 {
00065     os << "[" << (_soft?"Soft":"") << "Install: ";
00066     os << _item;
00067     if (_upgrades) {
00068         os << ", Upgrades ";
00069         os << _upgrades;
00070     }
00071     if (!_deps_satisfied_by_this_install.empty()) {
00072         os << ", Satisfies [";
00073         for (CapSet::const_iterator iter = _deps_satisfied_by_this_install.begin();
00074             iter != _deps_satisfied_by_this_install.end(); iter++)
00075         {
00076             if (iter != _deps_satisfied_by_this_install.begin()) os << ", ";
00077             os << (*iter);
00078         }
00079         os << "]";
00080     }
00081     if (!_needed_by.empty()) {
00082         os << ", Needed by ";
00083         for (PoolItemList::const_iterator it = _needed_by.begin(); it != _needed_by.end(); ++it) {
00084             if (it != _needed_by.begin()) os << ", ";
00085             os << *it;
00086         }
00087     }
00088     if (_explicitly_requested) os << ", Explicit !";
00089     os << "]";
00090     return os;
00091 }
00092 
00093 //---------------------------------------------------------------------------
00094 
00095 QueueItemInstall::QueueItemInstall (const ResPool & pool, PoolItem_Ref item, bool soft)
00096     : QueueItem (QUEUE_ITEM_TYPE_INSTALL, pool)
00097     , _item (item)
00098     , _soft (soft)
00099     , _channel_priority (0)
00100     , _other_penalty (0)
00101     , _explicitly_requested (false)
00102 {
00103     Resolvable::constPtr res = item.resolvable();
00104     Package::constPtr pkg = asKind<Package>(res);                       // try to access it as a package
00105     if (pkg == NULL
00106         || !pkg->installOnly()) {
00107 
00108         // check if this install upgrades anything                      // only if its a 'rpm -U' package
00109         _upgrades = Helper::findInstalledItem (pool, item);
00110     }
00111 
00112     _XDEBUG("QueueItemInstall::QueueItemInstall(" << item << (soft?", soft":"") << ") upgrades " << _upgrades);
00113 }
00114  
00115 
00116 QueueItemInstall::~QueueItemInstall()
00117 {
00118 }
00119 
00120 //---------------------------------------------------------------------------
00121 
00122 bool
00123 QueueItemInstall::isSatisfied (ResolverContext_Ptr context) const
00124 {
00125     return context->isPresent (_item);
00126 }
00127 
00128 
00129 //---------------------------------------------------------------------------
00130 
00131 // Handle items which freshen or supplement us -> re-establish them
00132 
00133 // see also FreshenState in Resolver.cc
00134 // see also UninstallEstablishItem in QueueItemUninstall.cc
00135 
00136 typedef map<string, PoolItem_Ref> EstablishMap;
00137 
00138 struct InstallEstablishItem
00139 {
00140     EstablishMap establishmap;
00141 
00142     InstallEstablishItem ()
00143     { }
00144 
00145 
00146     // provider has a freshens on a just to-be-installed item
00147     //   re-establish provider, maybe its incomplete now
00148 
00149     bool operator()( const CapAndItem & cai )
00150     {
00151         _XDEBUG("QueueItemInstall::InstallEstablishItem (" << cai.item << ", " << cai.cap << ")");
00152 
00153         // only consider best architecture, best edition
00154 
00155         PoolItem_Ref item( cai.item );
00156 
00157         EstablishMap::iterator it = establishmap.find( item->name() );
00158 
00159         if (it != establishmap.end()) {                                 // item with same name found
00160             int cmp = it->second->arch().compare( item->arch() );
00161             if (cmp < 0) {                                              // new item has better arch
00162                 it->second = item;
00163             }
00164             else if (cmp == 0) {                                        // new item has equal arch
00165                 if (it->second->edition().compare( item->edition() ) < 0) {
00166                     it->second = item;                          // new item has better edition
00167                 }
00168             }
00169         }
00170         else {
00171             establishmap[item->name()] = item;
00172         }
00173         return true;
00174     }
00175 };
00176 
00177 
00178 
00179 //---------------------------------------------------------------------------
00180 
00181 // Handle items which conflict us -> uninstall them
00182 
00183 struct UninstallConflicting
00184 {
00185     ResolverContext_Ptr _context;
00186     const Capability _provided_cap;
00187     PoolItem _install_item;             // the to-be-installed item issuing the conflict
00188     PoolItem _upgrade_item;             // the installed, to-be-upgraded item (might be empty if its a fresh install)
00189     QueueItemList & _qil;
00190     bool ignored;
00191 
00192     UninstallConflicting( ResolverContext_Ptr ctx, const Capability & provided_cap, PoolItem install_item, PoolItem upgrade_item, QueueItemList & qil )
00193         : _context( ctx )
00194         , _provided_cap( provided_cap )
00195         , _install_item( install_item )
00196         , _upgrade_item( upgrade_item )
00197         , _qil( qil )
00198         , ignored( false )
00199     { }
00200 
00201 
00202     // conflicting_item provides a capability (conflicting_cap), _install_item lists as conflicts.
00203 
00204     bool operator()( const CapAndItem & cai)
00205     {
00206         PoolItem_Ref conflicting_item = cai.item;
00207 
00208         _XDEBUG("UninstallConflicting(" << conflicting_item << ", cap " << cai.cap << ")");
00209 
00210         if (conflicting_item == _install_item) {                                // self conflict ?
00211             WAR << "Ignoring self-conflicts" << endl;
00212             return true;
00213         }
00214         if (conflicting_item == _upgrade_item) {                                // upgrade conflict ?
00215             _XDEBUG("We're upgrading the conflicting item");
00216             return true;
00217         }
00218 
00219         const Capability conflicting_cap = cai.cap;
00220         ResolverInfo_Ptr log_info;
00221         QueueItemUninstall_Ptr uninstall_item;
00222 
00223         IgnoreMap ignoreMap = _context->getIgnoreConflicts();           // ignored conflict ?
00224         // checking for ignoring dependencies
00225         for (IgnoreMap::iterator it = ignoreMap.begin(); it != ignoreMap.end(); it++) {
00226             if (it->first == conflicting_item
00227                 && it->second == conflicting_cap)
00228             {
00229                 _XDEBUG("Found ignoring conflicts " << conflicting_cap << " for " << conflicting_item);
00230                 ignored = true;
00231                 return false;           // stop iteration
00232             } else {
00233                 _XDEBUG("Ignoring conflict " << it->second << " for " <<  it->first << " does not fit");            
00234             }
00235         }
00236 
00237         /* Check to see if we conflict with ourself and don't create
00238          * an uninstall item for it if we do.  This is Debian's way of
00239          * saying that one and only one item with this provide may
00240          * exist on the system at a time.
00241          */
00242 
00243         if (compareByNVR (conflicting_item.resolvable(), _install_item.resolvable()) == 0) {
00244                 return true;
00245         }
00246 
00247 #warning Make behaviour configurable
00248         // If the package is installed or is set to be installed by the user,
00249         // let the user decide deleting conflicting package. This is only an info.
00250         // Try at first updating packages.
00251         //
00252         ResStatus confl_status = _context->getStatus( conflicting_item );
00253         if (confl_status.isToBeInstalled()                      // scheduled for installation
00254             || confl_status.staysInstalled())                   // not scheduled at all but installed
00255         {
00256             ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CONFLICT_CANT_INSTALL,
00257                                                                                _install_item, RESOLVER_INFO_PRIORITY_VERBOSE, _provided_cap);
00258             misc_info->setOtherPoolItem (conflicting_item);
00259             misc_info->setOtherCapability (conflicting_cap);
00260             _context->addInfo (misc_info);
00261         }
00262 
00263         _XDEBUG("because: '" << conflicting_item << "'conflicts " << conflicting_cap);
00264 
00265         QueueItemUninstall_Ptr uninstall_qitem = new QueueItemUninstall (_context->pool(), conflicting_item, QueueItemUninstall::CONFLICT);
00266         uninstall_qitem->setDueToConflict ();
00267         log_info = new ResolverInfoConflictsWith (conflicting_item, _install_item,
00268                                                   conflicting_cap);
00269         uninstall_qitem->addInfo (log_info);
00270         _qil.push_front (uninstall_qitem);
00271 
00272         return true;
00273     }
00274 };
00275 
00276 //---------------------------------------------------------------------------------------
00277 
00278 bool
00279 QueueItemInstall::process (ResolverContext_Ptr context, QueueItemList & qil)
00280 {
00281     ResStatus status = context->getStatus(_item);
00282 
00283     _XDEBUG( "QueueItemInstall::process(" << *this << "):" << status);
00284 
00285     /* If we are trying to upgrade item A with item B and they both have the
00286         same version number, do nothing.  This shouldn't happen in general with
00287         zypp, but can come up with the installer & autopull. */
00288 
00289     if (_upgrades
00290         && compareByNVRA(_item.resolvable(), _upgrades.resolvable()) == 0)
00291     {
00292         if (_item->kind() == ResTraits<Package>::kind) {
00293             ResolverInfo_Ptr info;
00294             _DEBUG("install of " << _item << " upgrades itself, skipping");
00295 
00296             info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_SKIPPING, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00297             context->addInfo (info);
00298             goto finished;
00299         }
00300         else {
00301             _DEBUG("re-install " << _item);
00302         }
00303     }
00304 
00305     // check if this install is still needed
00306     //   (maybe other resolver processing made this install obsolete
00307 
00308     if (!_needed_by.empty()) {
00309         bool still_needed = false;
00310 
00311         _XDEBUG( "still needed ");
00312 
00313         for (PoolItemList::const_iterator iter = _needed_by.begin(); iter != _needed_by.end() && !still_needed; ++iter) {
00314             ResStatus status = iter->status();
00315             _XDEBUG("by: [status: " << status << "] " << *iter);
00316             if (! status.isToBeUninstalled()
00317                 && ! status.isImpossible())
00318             {
00319                 still_needed = true;
00320             }
00321         }
00322 
00323         if (! still_needed)
00324             goto finished;
00325     }
00326 
00327     /* If we are in verify mode and this install is about to fail, don't let it happen...
00328            instead, we try to back out of the install by removing whatever it was that
00329            needed this. */
00330 
00331     if (context->verifying()
00332         && (status.isToBeUninstalled() || status.isImpossible())
00333         && !_needed_by.empty()) {
00334 
00335         QueueItemUninstall_Ptr uninstall_item;
00336 
00337         for (PoolItemList::const_iterator iter = _needed_by.begin(); iter != _needed_by.end(); iter++) {
00338             uninstall_item = new QueueItemUninstall (pool(), *iter, QueueItemUninstall::BACKOUT);
00339             qil.push_front (uninstall_item);
00340         }
00341 
00342         goto finished;
00343     }
00344 
00345     // If this install is due to a needed, convert it to a normal install
00346 
00347     if (status.isNeeded()) {
00348         context->setStatus (_item, _soft ? ResStatus::toBeInstalledSoft :  ResStatus::toBeInstalled);
00349     }
00350 
00351 
00352     // if this install upgrades an installed resolvable, explicitly uninstall this one
00353     //   in order to ensure that all dependencies are still met after the upgrade
00354 
00355     if (!_upgrades) {
00356 
00357         _XDEBUG("trying simple install of " <<  _item);
00358         if (!context->install (_item, context->verifying() || _soft, _other_penalty))
00359             goto finished;
00360 
00361     }
00362     else {
00363 
00364         QueueItemUninstall_Ptr uninstall_item;
00365 
00366         _XDEBUG("trying upgrade install of " << _item);
00367 
00368         if (!context->upgrade (_item, _upgrades, context->verifying() || _soft, _other_penalty)) {
00369             // invalid solution
00370             ResolverInfo_Ptr info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_INVALID_SOLUTION, PoolItem_Ref(), RESOLVER_INFO_PRIORITY_VERBOSE);
00371             context->addError (info);
00372             goto finished;
00373         }
00374 
00375         // the upgrade will uninstall the installed one, take care of this
00376 
00377         uninstall_item = new QueueItemUninstall (pool(), _upgrades, QueueItemUninstall::UPGRADE );
00378         uninstall_item->setUpgradedTo (_item);
00379 
00380         if (_explicitly_requested)
00381             uninstall_item->setExplicitlyRequested ();
00382 
00383         qil.push_front (uninstall_item);
00384 
00385     }
00386 
00387     /* Log which item need this install */
00388 
00389     if (!_needed_by.empty()) {
00390 
00391         ResolverInfoNeededBy_Ptr info;
00392 
00393         info = new ResolverInfoNeededBy (_item);
00394         info->addRelatedPoolItemList (_needed_by);
00395         context->addInfo (info);
00396     }
00397 
00398     // we're done if this isn't currently uninstalled or incomplete
00399 
00400     if (! (status.staysUninstalled()
00401            || status.isToBeUninstalledDueToUnlink()
00402            || status.isIncomplete()
00403            || status.isSatisfied()))
00404     {
00405         _XDEBUG("status " << status << " -> finished");
00406         goto finished;
00407     }
00408 
00409     _XDEBUG("status " << status << " -> NOT finished");
00410     {   // just a block for local initializers, the goto above makes this necessary
00411 
00412         ResolverInfoMisc_Ptr misc_info;
00413 
00414         if (_upgrades) {
00415 
00416             misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UPDATING, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00417             misc_info->setOtherPoolItem (_upgrades);
00418 
00419         } else {
00420 
00421             misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_INSTALLING, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00422 
00423         }
00424 
00425         context->addInfo (misc_info);
00426         logInfo (context);
00427 
00428         /* Construct require items for each of the item's requires that is still unsatisfied. */
00429 
00430         CapSet caps;
00431 
00432         caps = _item->dep (Dep::REQUIRES);
00433 
00434         for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00435 
00436             const Capability cap = *iter;
00437             _XDEBUG("this requires " << cap);
00438 
00439             if (!context->requirementIsMet (cap)) {
00440                 _XDEBUG("this requirement is still unfulfilled");
00441                 QueueItemRequire_Ptr req_item = new QueueItemRequire (pool(), cap );
00442                 req_item->addPoolItem (_item);
00443                 qil.push_front (req_item);
00444             }
00445 
00446         }
00447 
00448         caps = _item->dep (Dep::RECOMMENDS);
00449 
00450         for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00451 
00452             const Capability cap = *iter;
00453             _XDEBUG("this recommends " << cap);
00454 
00455             if (!context->requirementIsMet (cap)) {
00456                 _XDEBUG("this recommends is still unfulfilled");
00457                 QueueItemRequire_Ptr req_item = new QueueItemRequire (pool(), cap, true);       // this is a soft requires
00458                 req_item->addPoolItem (_item);
00459                 qil.push_front (req_item);
00460             }
00461 
00462         }
00463 
00464         /* Construct conflict items for each of the item's conflicts. */
00465 
00466         caps = _item->dep (Dep::CONFLICTS);
00467         for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00468             const Capability cap = *iter;
00469             _XDEBUG("this conflicts with '" << cap << "'");
00470             QueueItemConflict_Ptr conflict_item = new QueueItemConflict (pool(), cap, _item );
00471             // Push the QueueItem at the END of the list in order to favourite conflicts caused
00472             // by obsolating this item.
00473             qil.push_back (conflict_item);
00474         }
00475 
00476         /* Construct conflict items for each of the item's obsoletes. */
00477 
00478         caps = _item->dep (Dep::OBSOLETES);
00479         IgnoreMap ignoreMap = context->getIgnoreObsoletes();
00480         
00481         for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00482             const Capability cap = *iter;
00483             bool found = false;
00484             for (IgnoreMap::iterator it = ignoreMap.begin();
00485                  it != ignoreMap.end(); it++) {
00486                 if (it->first == _item
00487                     && it->second == cap) {
00488                     _XDEBUG("Found ignoring obsoletes " << cap << " for " << _item);
00489                     found = true;
00490                     break;
00491                 }
00492             }
00493             if (!found) {           
00494                 _XDEBUG("this obsoletes " <<  cap);
00495                 QueueItemConflict_Ptr conflict_item = new QueueItemConflict (pool(), cap, _item );
00496                 conflict_item->setActuallyAnObsolete();
00497                 // Push the QueueItem at the BEGIN of the list in order to favourite this confict
00498                 // comparing to "normal" conflicts, cause this item will be deleted. So other
00499                 // conflicts will not be regarded in the future.
00500                 qil.push_front (conflict_item);
00501             }
00502         }
00503 
00504         // Go over each provides of the to-be-uninstalled item and
00505         // - re-establish any freshens
00506         // - re-establish any supplements
00507         // - find items that conflict with us and try to uninstall it if it is useful
00508 
00509         InstallEstablishItem establish;
00510 
00511         caps = _item->dep (Dep::PROVIDES);
00512         bool ignored = false;
00513 
00514         for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00515             const Capability cap = *iter;
00516 
00517             /* Construct establish items for each of those which
00518                 freshen or supplement and provides of this resolvable. */
00519 
00520             _XDEBUG("Re-establish all freshens on " << cap);
00521             // pool ()->foreachFresheningResItem (cap, establish_freshens_cb, &info);
00522 
00523             Dep dep( Dep::FRESHENS);
00524             invokeOnEach( pool().byCapabilityIndexBegin( cap.index(), dep ), // begin()
00525                           pool().byCapabilityIndexEnd( cap.index(), dep ),   // end()
00526                           resfilter::ByCapMatch( cap ),
00527                           functor::functorRef<bool,CapAndItem>( establish ) );
00528 
00529             dep = Dep::SUPPLEMENTS;
00530             invokeOnEach( pool().byCapabilityIndexBegin( cap.index(), dep ), // begin()
00531                           pool().byCapabilityIndexEnd( cap.index(), dep ),   // end()
00532                           resfilter::ByCapMatch( cap ),
00533                           functor::functorRef<bool,CapAndItem>( establish ) );
00534 
00535             if (!ignored) {
00536                 // Search items that conflict with us and try to uninstall it if it is useful
00537 
00538                 UninstallConflicting info( context, cap, _item, _upgrades, qil );
00539 
00540                 Dep dep( Dep::CONFLICTS );
00541                 invokeOnEach( pool().byCapabilityIndexBegin( cap.index(), dep ),
00542                               pool().byCapabilityIndexEnd( cap.index(), dep ),
00543                               resfilter::ByCapMatch( cap ),
00544                               functor::functorRef<bool,CapAndItem>( info ) );
00545 
00546                 ignored = info.ignored;         // user choose to ignore these conflitcs
00547             }
00548 
00549         } // iterate over all provides
00550 
00551         // schedule all collected items for establish
00552 
00553         for (EstablishMap::iterator it = establish.establishmap.begin(); it != establish.establishmap.end(); ++it) {
00554             QueueItemEstablish_Ptr establish_item = new QueueItemEstablish (pool(), it->second, true);
00555             qil.push_front( establish_item );
00556         }
00557 
00558     } // end of goto-over-definitions-to-finished block
00559 
00560  finished:
00561 
00562     return true;
00563 }
00564 
00565 
00566 QueueItem_Ptr
00567 QueueItemInstall::copy (void) const
00568 {
00569     QueueItemInstall_Ptr new_install = new QueueItemInstall (pool(), _item);
00570     new_install->QueueItem::copy(this);
00571 
00572     new_install->_upgrades = _upgrades;
00573     new_install->_deps_satisfied_by_this_install = CapSet(_deps_satisfied_by_this_install.begin(), _deps_satisfied_by_this_install.end());
00574     new_install->_needed_by = PoolItemList (_needed_by.begin(), _needed_by.end());
00575     new_install->_channel_priority = _channel_priority;
00576     new_install->_other_penalty = _other_penalty;
00577     new_install->_explicitly_requested = _explicitly_requested;
00578 
00579     return new_install;
00580 }
00581 
00582 
00583 int
00584 QueueItemInstall::cmp (QueueItem_constPtr item) const
00585 {
00586     int cmp = this->compare (item);
00587     if (cmp != 0)
00588         return cmp;
00589     QueueItemInstall_constPtr install = dynamic_pointer_cast<const QueueItemInstall>(item);
00590     return compareByNVRA (_item.resolvable(), install->_item.resolvable());
00591 }
00592 
00593 //---------------------------------------------------------------------------
00594 
00595 void
00596 QueueItemInstall::addDependency (const Capability & dep)
00597 {
00598     _deps_satisfied_by_this_install.insert (dep);
00599 }
00600 
00601 
00602 void
00603 QueueItemInstall::addNeededBy (PoolItem_Ref item)
00604 {
00605     _needed_by.push_front (item);
00606 }
00607 
00609     };// namespace detail
00612   };// namespace solver
00615 };// namespace zypp
00617 

Generated on Mon Jun 5 19:10:35 2006 for zypp by  doxygen 1.4.6