QueueItemEstablish.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* QueueItemEstablish.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/solver/detail/Types.h"
00023 
00024 #include "zypp/solver/detail/QueueItemEstablish.h"
00025 #include "zypp/solver/detail/QueueItemInstall.h"
00026 #include "zypp/solver/detail/QueueItemRequire.h"
00027 #include "zypp/solver/detail/QueueItemConflict.h"
00028 #include "zypp/solver/detail/QueueItem.h"
00029 #include "zypp/solver/detail/Helper.h"
00030 #include "zypp/solver/detail/ResolverContext.h"
00031 #include "zypp/solver/detail/ResolverInfoConflictsWith.h"
00032 #include "zypp/solver/detail/ResolverInfoNeededBy.h"
00033 #include "zypp/solver/detail/ResolverInfoMisc.h"
00034 
00035 #include "zypp/CapSet.h"
00036 #include "zypp/base/Logger.h"
00037 #include "zypp/base/String.h"
00038 #include "zypp/base/Gettext.h"
00039 
00041 namespace zypp
00042 { 
00043 
00044   namespace solver
00045   { 
00046 
00047     namespace detail
00048     { 
00049 
00050 using namespace std;
00051 
00052 IMPL_PTR_TYPE(QueueItemEstablish);
00053 
00054 //---------------------------------------------------------------------------
00055 
00056 std::ostream &
00057 QueueItemEstablish::dumpOn( std::ostream & os ) const
00058 {
00059     os <<"[Establish: ";
00060     os << _item;
00061     if (_explicitly_requested) os << ", Explicit !";
00062     os << "]";
00063     return os;
00064 }
00065 
00066 //---------------------------------------------------------------------------
00067 
00068 QueueItemEstablish::QueueItemEstablish (const ResPool & pool, PoolItem_Ref item, bool soft)
00069     : QueueItem (QUEUE_ITEM_TYPE_ESTABLISH, pool)
00070     , _item(item)
00071     , _soft(soft)
00072     , _channel_priority (0)
00073     , _other_penalty (0)
00074     , _explicitly_requested (false)
00075 {
00076     _XDEBUG("QueueItemEstablish::QueueItemEstablish (" << item << ")");
00077 
00078 }
00079 
00080 
00081 QueueItemEstablish::~QueueItemEstablish()
00082 {
00083 }
00084 
00085 //---------------------------------------------------------------------------
00086 
00087 bool
00088 QueueItemEstablish::isSatisfied (ResolverContext_Ptr context) const
00089 {
00090     return context->isPresent (_item);
00091 }
00092 
00093 
00094 //---------------------------------------------------------------------------
00095 
00096 
00097 bool
00098 QueueItemEstablish::process (ResolverContext_Ptr context, QueueItemList & qil)
00099 {
00100     _XDEBUG("QueueItemEstablish::process(" << *this << ")");
00101 
00102     ResStatus status = context->getStatus(_item);
00103     
00104     if (_item.status().isLocked()
00105         || status.isLocked()) {
00106         _XDEBUG("Item " << _item << " is locked. --> NO establish");
00107         return true;
00108     }
00109     if ( ! _item->arch().compatibleWith( context->architecture() ) ) {
00110         context->unneeded (_item, _other_penalty);
00111         _XDEBUG( _item << " has incompatible architecture, unneeded" );
00112         return true;
00113     }
00114 
00115     _item.status().setUndetermined();           // reset any previous establish state
00116 
00117     CapSet freshens = _item->dep(Dep::FRESHENS);
00118 
00119     _XDEBUG("simple establish of " << _item << " with " << freshens.size() << " freshens");
00120 
00121     ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_ESTABLISHING, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00122     context->addInfo (misc_info);
00123     logInfo (context);
00124 
00125     /* Loop through all freshen dependencies. If one is satisfied, queue the _item for installation.  */
00126 
00127     CapSet::const_iterator iter;
00128     for (iter = freshens.begin(); iter != freshens.end(); iter++) {
00129         const Capability cap = *iter;
00130         if (context->requirementIsMet (cap)) {
00131             _XDEBUG("this freshens " << cap);
00132             break;
00133         }
00134     }
00135 
00136     // if we have freshens but none of the freshen deps were met, mark the _item as unneeded
00137     // else we look at its supplements as an additional condition
00138     // (freshens AND supplements must be true. true means either empty or at least one match)
00139     //
00140     // else we look at its requires to set it to satisfied or incomplete
00141 
00142     if (freshens.size() > 0                             // have freshens !
00143         && iter == freshens.end())                      // but none matched
00144     {
00145         _XDEBUG(_item << " freshens nothing -> unneeded");
00146         if (_item->kind() != ResTraits<Package>::kind)
00147             context->unneeded (_item, _other_penalty);
00148     }
00149     else {                                                      // installed or no freshens or triggered freshens
00150 
00151         CapSet supplements = _item->dep(Dep::SUPPLEMENTS);
00152         if (supplements.size() != 0) {                                  // if we have supplements, they must _also_ trigger
00153             CapSet::const_iterator iter;
00154             for (iter = supplements.begin(); iter != supplements.end(); iter++) {
00155                 const Capability cap = *iter;
00156                 if (context->requirementIsMet (cap)) {
00157                     _XDEBUG("this supplements " << cap);
00158                     break;
00159                 }
00160             }
00161             if (iter == supplements.end()) {
00162                 _XDEBUG(_item << " none of the supplements match -> unneeded");
00163                 if (_item->kind() != ResTraits<Package>::kind)
00164                     context->unneeded (_item, _other_penalty);
00165                 return true;
00166             }
00167 
00168             PoolItem_Ref installed = Helper::findInstalledItem( pool(), _item );
00169             if (!installed) {                                                           // not installed -> install
00170                 // have supplements and at least one triggers -> install
00171                 _DEBUG("Uninstalled " << _item << " supplements " << *iter << " -> install");
00172                 QueueItemInstall_Ptr install_item = new QueueItemInstall( pool(), _item, true );
00173                 qil.push_front( install_item );
00174                 return true;
00175             }
00176         }
00177 
00178         // the conditions (freshens, supplements) are true (either empty or at least one match)
00179         // for a package, these are sufficient to trigger its installation. (packages only get
00180         //  'established' if they have freshens or supplements).
00181         //  While this is fine for e.g. fonts etc. its problematic for kernel driver packages.
00182         //  We must not install kernel driver packages which (via their dependencies) will install
00183         //  additional kernels. So for kernel driver packages, checking their requires is indeed
00184         //  the right thing. (see #178721)
00185 
00186         // So the current code checks all requirements and only triggers an install if
00187         //  - all requirements are already fulfilled
00188         //  - the package is not already installed (so we do only fresh installs, no upgrades here)
00189 
00190         // for other kind of resolvables, we now look at their requirements and set their
00191         //  'state modifier' accordingly.
00192 
00193 
00194         CapSet requires = _item->dep(Dep::REQUIRES);                    // check requirements
00195         Capability missing;
00196         bool all_unneeded = true;                                       // check if all are met because of unneeded
00197         for (iter = requires.begin(); iter != requires.end(); iter++) {
00198             missing = *iter;
00199             bool unneeded;
00200             if (!context->requirementIsMet (missing, false, &unneeded)) {
00201                 all_unneeded = false;
00202                 break;
00203             }
00204             if (!unneeded) all_unneeded = false;
00205         }
00206         if (iter == requires.end()) {                                   // all are met
00207             if (all_unneeded
00208                 && _item->kind() == ResTraits<Patch>::kind)             // unneeded is transitive only for patches (#171590)
00209             {
00210                 _XDEBUG("all requirements of " << _item << " unneeded -> unneeded");
00211                 context->unneeded( _item, _other_penalty );
00212             }
00213             else if (_item->kind() == ResTraits<Package>::kind)         // install package if not installed yet.
00214             {
00215                 PoolItem_Ref installed = Helper::findInstalledItem( pool(), _item );
00216                 if (!installed) {
00217                     // freshens and at least one triggers -> install
00218                     _DEBUG("Uninstalled " << _item << " freshens -> install");
00219                     QueueItemInstall_Ptr install_item = new QueueItemInstall( pool(), _item, true );
00220                     qil.push_front( install_item );
00221                     return true;
00222                 }
00223             }
00224             else
00225             {
00226                 _XDEBUG("all requirements of " << _item << " met -> satisfied");
00227                 context->satisfy( _item, _other_penalty );
00228             }
00229         }
00230         else {                                                          // some requirements are unfulfilled
00231             // If the item stays installed, blame the user
00232             if ((_item->kind() != ResTraits<Package>::kind
00233                  && _item->kind() != ResTraits<Atom>::kind)
00234                 || status.staysInstalled()
00235                 || context->establishing())
00236             {
00237                 _XDEBUG("Non-Package/Installed/Establishing " << _item << " has unfulfilled requirement " << *iter << " -> incomplete");
00238                 context->incomplete( _item, _other_penalty );
00239             }
00240             else if (status.staysUninstalled())                 // not installed -> schedule for installation
00241             {
00242                 if (_item->kind() == ResTraits<Atom>::kind) {   // Bug 190272
00243                     _XDEBUG("Atom " << _item << " has unfulfilled requirement " << *iter << " -> incomplete");
00244                     context->incomplete( _item, _other_penalty );
00245                 }
00246                 else {  // bug #184714
00247                 // This is probably plain wrong.
00248                 // It installs a resolvable if its freshens/supplements triggers and
00249                 // some of its requirements are unfulfilled.
00250                 // What if a resolvable of the same name is already installed ?
00251                 // What if a 'better' resolvable is already scheduled for installation ?
00252 
00253                 _DEBUG("Uninstalled " << _item << " has unfulfilled requirement " << *iter << " -> install");
00254                 QueueItemInstall_Ptr install_item = new QueueItemInstall( pool(), _item );
00255                 qil.push_front( install_item );
00256                 }
00257             }
00258             else {
00259                 _XDEBUG("Transacted " << _item << " has unfulfilled requirement " << *iter << " -> leave");
00260                 // do nothing, because its either toBeInstalled or toBeUninstalled
00261             }
00262         }
00263     }
00264 
00265     return true;
00266 }
00267 
00268 
00269 QueueItem_Ptr
00270 QueueItemEstablish::copy (void) const
00271 {
00272     QueueItemEstablish_Ptr new_install = new QueueItemEstablish (pool(), _item, _soft);
00273     new_install->QueueItem::copy(this);
00274 
00275     new_install->_channel_priority = _channel_priority;
00276     new_install->_other_penalty = _other_penalty;
00277     new_install->_explicitly_requested = _explicitly_requested;
00278 
00279     return new_install;
00280 }
00281 
00282 
00283 int
00284 QueueItemEstablish::cmp (QueueItem_constPtr item) const
00285 {
00286     int cmp = this->compare (item);
00287     if (cmp != 0)
00288         return cmp;
00289     QueueItemEstablish_constPtr establish = dynamic_pointer_cast<const QueueItemEstablish>(item);
00290     return compareByNVR(_item.resolvable(), establish->_item.resolvable());
00291 }
00292 
00294     };// namespace detail
00297   };// namespace solver
00300 };// namespace zypp

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