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

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