ResolverContext.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /* ResolverContext.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 
00023 #include <values.h>
00024 
00025 #include "zypp/CapSet.h"
00026 #include "zypp/base/Logger.h"
00027 #include "zypp/base/String.h"
00028 #include "zypp/base/Gettext.h"
00029 #include "zypp/base/String.h"
00030 
00031 #include "zypp/base/Algorithm.h"
00032 #include "zypp/ResPool.h"
00033 #include "zypp/ResFilters.h"
00034 #include "zypp/CapFilters.h"
00035 #include "zypp/Package.h"
00036 #include "zypp/Resolvable.h"
00037 
00038 #include "zypp/solver/detail/Types.h"
00039 #include "zypp/solver/detail/Helper.h"
00040 #include "zypp/solver/detail/ResolverContext.h"
00041 #include "zypp/solver/detail/ResolverInfoMisc.h"
00042 #include "zypp/solver/detail/ResolverInfoConflictsWith.h"
00043 #include "zypp/solver/detail/ResolverInfoNeededBy.h"
00044 
00046 namespace zypp
00047 { 
00048 
00049   namespace solver
00050   { 
00051 
00052     namespace detail
00053     { 
00054 
00055 using namespace std;
00056 
00057 IMPL_PTR_TYPE(ResolverContext);
00058 
00059 //---------------------------------------------------------------------------
00060         
00061 class compare_items {
00062 public:
00063     int operator() (PoolItem_Ref p1,
00064                     PoolItem_Ref p2) const
00065         { return compareByN(p1.resolvable(),p2.resolvable()) < 0 ; }
00066 };
00067         
00068 
00069 //---------------------------------------------------------------------------
00070 
00071 ostream&
00072 operator<<( ostream& os, const ResolverContext & context)
00073 {
00074     if (context._parent != NULL) {
00075         os << "Parent @" << context._parent << endl;
00076         os << *(context._parent);
00077     }
00078     os << "ResolverContext with " << context._context.size() << " entries" << endl;
00079     for (ResolverContext::Context::const_iterator iter = context._context.begin(); iter != context._context.end(); ++iter) {
00080         os << iter->first << " : " << iter->second << endl;
00081     }
00082     return os;
00083 }
00084 
00085 //---------------------------------------------------------------------------
00086 
00087 ResolverContext::ResolverContext (const ResPool & pool, const Arch & arch, ResolverContext_Ptr parent)
00088     : _parent (parent)
00089     , _establish_context (NULL)
00090     , _pool (pool)
00091     , _download_size (0)
00092     , _install_size (0)
00093     , _total_priority (0)
00094     , _min_priority (0)
00095     , _max_priority (0)
00096     , _other_penalties (0)
00097     , _verifying (false)
00098     , _establishing (false)
00099     , _invalid (false)
00100     , _askUser(false)
00101     , _architecture(arch)
00102     , _forceResolve(false)
00103     , _upgradeMode(false)
00104     , _preferHighestVersion(true)
00105     , _tryAllPossibilities(false)
00106     , _skippedPossibilities(false)
00107       
00108 {
00109 _XDEBUG( "new ResolverContext()" );
00110     if (parent != NULL) {
00111         _pool                = parent->_pool;
00112         _download_size       = parent->_download_size;
00113         _install_size        = parent->_install_size;
00114         _total_priority      = parent->_total_priority;
00115         _max_priority        = parent->_max_priority;
00116         _min_priority        = parent->_min_priority;
00117         _other_penalties     = parent->_other_penalties;
00118         _verifying           = parent->_verifying;
00119         _establishing        = parent->_establishing;
00120         _ignoreConflicts     = parent->_ignoreConflicts;
00121         _ignoreRequires      = parent->_ignoreRequires;
00122         _ignoreObsoletes     = parent->_ignoreObsoletes;
00123         _ignoreInstalledItem = parent->_ignoreInstalledItem;
00124         _ignoreArchitectureItem = parent->_ignoreArchitectureItem;
00125         _ignoreVendorItem    = parent->_ignoreVendorItem;
00126         _forceResolve        = parent->_forceResolve;
00127         _upgradeMode         = parent->_upgradeMode;
00128         _preferHighestVersion = parent->_preferHighestVersion;
00129         _tryAllPossibilities = parent->_tryAllPossibilities;
00130         _skippedPossibilities = parent->_skippedPossibilities;
00131         _establish_context = parent->_establish_context;
00132         
00133     } else {
00134         _min_priority = MAXINT;
00135     }
00136 }
00137 
00138 
00139 ResolverContext::~ResolverContext()
00140 {
00141 }
00142 
00143 //---------------------------------------------------------------------------
00144 // status retrieve
00145 
00146 ResStatus
00147 ResolverContext::getStatus (PoolItem_Ref item)
00148 {
00149 //_XDEBUG( "[" << this << "]getStatus(" << item << ")" );
00150 
00151     if (item == _last_checked_item) return _last_checked_status;
00152 
00153     _last_checked_item = item;
00154 
00155     Context::const_iterator it;
00156     ResolverContext_constPtr context = this;
00157 
00158     while (context) {                                   // go through the _parent chain
00159 
00160         it = context->_context.find(item);              // part of local context ?
00161         if (it != context->_context.end()) {
00162 //_XDEBUG( "[" << context << "]:" << it->second );
00163             _last_checked_status = it->second;
00164            if (_last_checked_status.isUndetermined()
00165                && _establish_context != NULL) {
00166                // take status from the last resolver establish run
00167                // in order to get the correct establishing status of the system
00168                // without any transactions. Bug 191810         
00169                ResStatus status = _establish_context->getStatus(item);
00170                _last_checked_status.setEstablishValue (status.getEstablishValue());
00171            }
00172            return _last_checked_status;                // Y: return
00173         }
00174         context = context->_parent;                     // N: go up the chain
00175     }
00176 
00177     ResStatus status( item.status() );                  // make a copy of the status
00178     status.resetTransact( ResStatus::USER );            //   without transaction
00179 #if 0
00180     if (item.status().isInstalled())
00181         status = ResStatus::installed;                  // return _is_ state, not _to be_ state
00182     else
00183         status = ResStatus::uninstalled;                // return _is_ state, not _to be_ state
00184 #endif
00185     _last_checked_status = status;
00186 //_XDEBUG( "[NULL]:" << status );    
00187     if (_establish_context != NULL) {
00188         // take status from the last resolver establish run
00189         // in order to get the correct establishing status of the system
00190         // without any transactions. Bug 191810
00191         ResStatus status = _establish_context->getStatus(item);
00192         _last_checked_status.setEstablishValue (status.getEstablishValue());
00193     }
00194 
00195     return _last_checked_status;                                // Not part of context, return Pool status
00196 }
00197 
00198 
00199 //---------------------------------------------------------------------------
00200 // status change
00201 
00202 void
00203 ResolverContext::setStatus (PoolItem_Ref item, const ResStatus & status)
00204 {
00205     if (_invalid) return;
00206 
00207     _XDEBUG( "[" << this << "]setStatus(" << item << ", " << status << ")" );
00208     ResStatus old_status = getStatus (item);
00209 
00210     if (old_status != status) {         // new status ?
00211         _XDEBUG( "MARK" );
00212         _context[item] = status;                // set it !
00213     }
00214 
00215     _last_checked_item = item;
00216     _last_checked_status = status;
00217 
00218     return;
00219 }
00220 
00221 
00222 // change state to TO_BE_INSTALLED (does not upgrade)
00223 
00224 bool
00225 ResolverContext::install (PoolItem_Ref item, bool is_soft, int other_penalty)
00226 {
00227     ResStatus status, new_status;
00228     std::string msg;
00229 
00230     status = getStatus(item);
00231     _XDEBUG( "ResolverContext[" << this << "]::install(<" << status  << "> " << item << ")" );
00232 
00233     if (status.isToBeUninstalled()
00234         && !status.isToBeUninstalledDueToUnlink()) {
00235         ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_INSTALL_TO_BE_UNINSTALLED, item, RESOLVER_INFO_PRIORITY_VERBOSE);
00236         addError (misc_info);
00237         return false;
00238     }
00239 
00240     if (status.isImpossible()) {
00241         ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALLABLE, item, RESOLVER_INFO_PRIORITY_VERBOSE);
00242         // it is only an error, if the user wants to install explicity.
00243         if (is_soft) {
00244             addInfo (misc_info);
00245         } else {
00246             addError (misc_info);
00247         }
00248         return false;
00249     }
00250 
00251     if (status.isUnneeded()
00252         && ( item->kind() == ResTraits<Patch>::kind     
00253              || item->kind() == ResTraits<Atom>::kind)) {
00254         ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_INSTALL_UNNEEDED, item, RESOLVER_INFO_PRIORITY_VERBOSE);
00255         addInfo (misc_info);
00256         return false;
00257     }
00258 
00259     if (status.isToBeInstalled()) {
00260         return true;
00261     }
00262 
00263     if (isParallelInstall( item )) {
00264         ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc( RESOLVER_INFO_TYPE_INSTALL_PARALLEL,
00265                                                                item, RESOLVER_INFO_PRIORITY_VERBOSE );
00266         PoolItem_Ref otherItem = getParallelInstall ( item );
00267         ResStatus statusOtherItem = getStatus (otherItem);
00268         misc_info->setOtherPoolItem (otherItem);
00269         if (NVRA(item.resolvable()) == NVRA(otherItem.resolvable())
00270             && status.isBySolver() && statusOtherItem.isBySolver()) {
00271             // If there has already been selected another item by the solver (e.g. from another repo)
00272             // we will take that.
00273             // Bug 224698
00274             addInfo( misc_info );
00275             return true;
00276         }
00277         else {
00278             addError( misc_info );
00279             return false;
00280         }
00281     }
00282 
00283     if (is_soft)
00284         setStatus (item, ResStatus::toBeInstalledSoft);
00285     else if (status.isToBeUninstalledDueToUnlink())
00286         setStatus (item, ResStatus(true));
00287     else
00288         setStatus (item, ResStatus::toBeInstalled);
00289 
00290     if (status.wasUninstalled()) {
00291         Resolvable::constPtr res = item.resolvable();
00292         Package::constPtr pkg = asKind<Package>(res);                   // try to access it as a package
00293         if (pkg) {                                                      // if its !=NULL, get size information
00294 
00295             _download_size += pkg->downloadSize();
00296             _install_size += pkg->size();
00297 
00298         }
00299 
00300         int priority;
00301 #if 0
00302         if (item->local())
00303             priority = 0;
00304         else {
00305 #endif
00306             priority = getRepoPriority (item->repository());
00307 //      }
00308 
00309         if (priority < _min_priority) _min_priority = priority;
00310         if (priority > _max_priority) _max_priority = priority;
00311 
00312         _other_penalties += other_penalty;
00313 
00314     }
00315 
00316     return true;
00317 }
00318 
00319 
00320 // change state to TO_BE_INSTALLED (does upgrade)
00321 
00322 bool
00323 ResolverContext::upgrade (PoolItem_Ref item, PoolItem_Ref old_item, bool is_soft, int other_penalty)
00324 {
00325     ResStatus status;
00326 
00327     _XDEBUG( "ResolverContext[" << this << "]::upgrade(" << item << " upgrades " << old_item << ")" );
00328 
00329     status = getStatus(item);
00330     
00331     if (status.isToBeUninstalled()) {
00332         ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_INSTALL_TO_BE_UNINSTALLED,
00333                                                            item, RESOLVER_INFO_PRIORITY_VERBOSE);
00334         addError (misc_info);
00335         return false;
00336     }
00337     if (status.isImpossible()) {
00338         ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALLABLE,
00339                                                            item, RESOLVER_INFO_PRIORITY_VERBOSE);
00340         addError (misc_info);
00341         return false;
00342     }
00343 
00344     if (status.isToBeInstalled())
00345         return true;
00346 
00347     if (isParallelInstall( item )) {
00348         ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc( RESOLVER_INFO_TYPE_INSTALL_PARALLEL, item, RESOLVER_INFO_PRIORITY_VERBOSE );
00349         PoolItem_Ref otherItem = getParallelInstall ( item );
00350         ResStatus statusOtherItem = getStatus (otherItem);
00351         misc_info->setOtherPoolItem (otherItem);
00352         if (NVRA(item.resolvable()) == NVRA(otherItem.resolvable())
00353             && status.isBySolver() && statusOtherItem.isBySolver()) {
00354             // If there has already been selected another item by the solver (e.g. from another repo)
00355             // we will take that.
00356             // Bug 224698           
00357             addInfo( misc_info );
00358             return true;
00359         }
00360         else {
00361             addError( misc_info );
00362             return false;
00363         }
00364     }
00365 
00366     ResStatus::TransactByValue by = ResStatus::SOLVER;
00367     if (item.status().isToBeInstalled()
00368         && item.status().getTransactByValue() > ResStatus::SOLVER) {
00369         // if the item has already has been set for installation by 
00370         // user, or other applications with higher priority
00371         // We will use this priority
00372         by = item.status().getTransactByValue();
00373     }
00374         
00375     if (is_soft) {
00376         ResStatus newStatus = ResStatus::toBeInstalledSoft; // This can only be done by the solver
00377         setStatus (item, newStatus);
00378     }
00379     else {
00380         ResStatus newStatus;
00381         newStatus.setToBeInstalled (by);
00382         setStatus (item, newStatus);
00383     }
00384 
00385     Resolvable::constPtr res = old_item.resolvable();
00386     Package::constPtr pkg = asKind<Package>(res);                       // try to access it as a package
00387     if (pkg) {                                                  // if its !=NULL, get size information
00388 
00389         _install_size -= pkg->size();
00390     }
00391 
00392     if (status == ResStatus::uninstalled) {
00393         res = item.resolvable();
00394         pkg = asKind<Package>(res);                                     // try to access it as a package
00395         if (pkg) {                                                      // if its !=NULL, get size information
00396 
00397             _download_size += pkg->downloadSize();
00398             _install_size += pkg->size();
00399 
00400         }
00401 
00402         int priority;
00403 #if 0
00404         if (item->local())
00405             priority = 0;
00406         else {
00407 #endif
00408             priority = getRepoPriority (item->repository());
00409 //      }
00410 
00411         if (priority < _min_priority) _min_priority = priority;
00412         if (priority > _max_priority) _max_priority = priority;
00413 
00414         _other_penalties += other_penalty;
00415     }
00416     return true;
00417 }
00418 
00419 
00420 // change state to 'TO_BE_UNINSTALLED{, DUE_TO_OBSOLETE, DUE_TO_UNLINK}'
00421 
00422 bool
00423 ResolverContext::uninstall (PoolItem_Ref item, bool part_of_upgrade, bool due_to_obsolete, bool due_to_unlink, bool explicitly_requested)
00424 {
00425     ResStatus status, new_status;
00426     std::string msg;
00427 
00428     status = getStatus(item);
00429     
00430     _XDEBUG( "ResolverContext[" << this << "]::uninstall("
00431                     << item << " " << (part_of_upgrade ? "part_of_upgrade" : "") << " "
00432                     << (due_to_obsolete ? "due_to_obsolete": "") << " "
00433              << (due_to_unlink ? "due_to_unlink" : "")
00434              << ( explicitly_requested ? "explicitly_requested" : "")
00435              << ")" << "context-status:" << status);
00436 
00437     assert (! (due_to_obsolete && due_to_unlink));
00438 
00439     if ( ( forceResolve() // This is the behaviour of ZMD
00440            && (status.isToBeInstalledNotSoft()             // \ The resolvable will be installed
00441                || item.status().isToBeInstalledNotSoft())) // / explicit. (And not by WEAK dependencies like supplements)
00442          
00443          || ( !forceResolve() // This is the bahaviour of YaST
00444               && ((status.staysInstalled() || status.isToBeInstalledNotSoft())                   //   \ We will have the resolvable
00445                   && (item.status().staysInstalled() || item.status().isToBeInstalledNotSoft())  //   / available.
00446                   || status.isToBeInstalledNotSoft())                                            //   is to be installed e.g. due solver requirement
00447                                                                                                  //   (And not by WEAK dependencies like supplements)
00448               && !part_of_upgrade
00449               && !due_to_obsolete
00450               && !due_to_unlink
00451               && !explicitly_requested)) {
00452         // We have a resolvable which should be kept on the system or is set to be installed explicit.
00453         // So we are not allowed deleting it. The reason WHY this resolvable has to be deleted here
00454         // is not show. We go back to the ResolverInfo to evaluate the reason. This reason (marked as an info)
00455         // will be stored at the end of ResolverInfo and will be marked as an error which is shown 
00456         // to the UI (solution included)
00457         // Canditates of searched ResolverInfo are RESOLVER_INFO_TYPE_CONFLICT_CANT_INSTALL
00458         //                                         RESOLVER_INFO_TYPE_NO_PROVIDER
00459         //                                         RESOLVER_INFO_TYPE_NO_OTHER_PROVIDER
00460         //                                         RESOLVER_INFO_TYPE_CANT_SATISFY
00461         //                                         RESOLVER_INFO_TYPE_CONFLICTS_WITH
00462         //
00463         // Testcases are:
00464         // conflict2-test.xml  conflict-test.xml              remove-still-needed2-test.xml  require-test.xml
00465         // conflict3-test.xml  remove-still-needed1-test.xml  remove-still-needed3-test.xml  unfulfilled-2-test.xml
00466         //
00467         bool found = false;
00468 
00469         ResolverInfoList addList;
00470         for (ResolverInfoList::const_iterator iter = _log.begin(); iter != _log.end(); iter++) {
00471             ResolverInfo_Ptr info = *iter;
00472 
00473             if (info->type() == RESOLVER_INFO_TYPE_CONFLICT_CANT_INSTALL
00474                 || info->type() == RESOLVER_INFO_TYPE_CONFLICTS_WITH) {
00475 
00476                 // There is a conflict like "a conflicts with b"
00477                 // Searching if there is already an error like "b conflicts with a"
00478                 PoolItem_Ref other_item = PoolItem_Ref();
00479                 if (info->type() == RESOLVER_INFO_TYPE_CONFLICT_CANT_INSTALL) {
00480                     ResolverInfoMisc_constPtr misc_info = dynamic_pointer_cast<const ResolverInfoMisc>(info);
00481                     other_item = misc_info->other();
00482                 } else {
00483                     ResolverInfoConflictsWith_constPtr conflicts_with = dynamic_pointer_cast<const ResolverInfoConflictsWith>(info);
00484                     if (conflicts_with->items().size() == 1) {
00485                         // It is only useful if there is ONE other item
00486                         other_item = *(conflicts_with->items().begin());
00487                     }
00488                 }
00489 
00490                 bool other_found = false;
00491 
00492                 if (other_item != PoolItem_Ref()) {
00493                     // searching for other solutions which have the same problem/solution
00494                     for (ResolverInfoList::const_iterator iter_other = addList.begin();
00495                          iter_other != addList.end(); iter_other++) {
00496                         
00497                         if ((*iter_other)->type() == RESOLVER_INFO_TYPE_CONFLICT_CANT_INSTALL) {
00498                                 ResolverInfoMisc_constPtr misc_info = dynamic_pointer_cast<const ResolverInfoMisc>(*iter_other);
00499                                 if (   (other_item == misc_info->other()
00500                                         && item == misc_info->affected())
00501                                     || (other_item == misc_info->affected()
00502                                         && item == misc_info->other())) 
00503                                     other_found = true;
00504                         }
00505                         else if ((*iter_other)->type() == RESOLVER_INFO_TYPE_CONFLICTS_WITH) {
00506                             ResolverInfoConflictsWith_constPtr conflicts_with = dynamic_pointer_cast<const ResolverInfoConflictsWith>(*iter_other);
00507                             if (conflicts_with->items().size() == 1) {
00508                                 // It is only useful if there is ONE other item
00509                                 if (   (other_item == *(conflicts_with->items().begin())
00510                                         && item == conflicts_with->affected())
00511                                     || (other_item == conflicts_with->affected()
00512                                         && item == *(conflicts_with->items().begin())))
00513                                     other_found = true;                                 
00514                             }
00515                         }
00516                     }
00517                 }
00518 
00519                 if ( !other_found
00520                      && (info->affected() == item
00521                          || other_item == item)) {
00522                     if (!getStatus(info->affected()).isImpossible() // Check, if the both items are still "installable"
00523                         && !getStatus(other_item).isImpossible()) { // If not this is not an error anymore
00524                         // put the info on the end as an error
00525                         addList.push_back (info);
00526                         found = true;
00527                     }
00528                 }
00529             } else if ( (info->type() == RESOLVER_INFO_TYPE_NO_PROVIDER
00530                          || info->type() == RESOLVER_INFO_TYPE_NO_OTHER_PROVIDER
00531                          || info->type() == RESOLVER_INFO_TYPE_CANT_SATISFY)
00532                         && info->affected() == item)
00533             {
00534                 // put the info on the end as error
00535                 found = true;
00536                 // dont duplicate known errors (#167309)
00537                 if (!info->error())
00538                     addList.push_back (info);
00539             } else if (info->type() == RESOLVER_INFO_TYPE_CONFLICTS_WITH
00540                        && info->affected() == item) {
00541                 // put the info on the end as error
00542                 found = true;
00543                 // dont duplicate known errors (#167309)
00544                 if (!info->error())
00545                     addList.push_back (info);           
00546             }
00547         }
00548         if (!found) {
00549             // generating a default problem
00550             ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_REJECT_INSTALL, item, RESOLVER_INFO_PRIORITY_VERBOSE);
00551             addError (misc_info, true); // true = asking the user
00552         } else {
00553             // Put the info at the end of the list, flagged as error
00554             for (ResolverInfoList::const_iterator iter = addList.begin(); iter != addList.end(); iter++) {
00555                 ResolverInfo_Ptr info = *iter;
00556                 addError (info, true);  // true = asking the user
00557             }
00558         }
00559         
00560 //      return false;
00561     }
00562 
00563     if (status.isToBeUninstalled()
00564         && !status.isToBeUninstalledDueToUnlink())
00565     {
00566         return true;
00567     }
00568 
00569     if (status.wasUninstalled()
00570         || status.isImpossible()
00571         || status.isToBeUninstalledDueToUnlink())
00572     {
00573         ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALLABLE, item, RESOLVER_INFO_PRIORITY_VERBOSE);
00574         addInfo (misc_info);
00575     }
00576 
00577     if (due_to_obsolete) {
00578         setStatus (item, ResStatus::toBeUninstalledDueToObsolete);
00579     }
00580     else if (due_to_unlink) {
00581         setStatus (item, ResStatus::toBeUninstalledDueToUnlink);
00582     }
00583     else if (status.wasUninstalled() ||
00584              (status.isToBeInstalled() && status.isBySolver())) {
00585         setStatus (item, ResStatus::impossible);
00586     }
00587     else if (part_of_upgrade) {
00588         setStatus (item, ResStatus::toBeUninstalledDueToUpgrade);
00589     }
00590     else {
00591         setStatus (item, ResStatus::toBeUninstalled);
00592     }
00593 
00594     if (status.wasInstalled()) {
00595         Resolvable::constPtr res = item.resolvable();
00596         Package::constPtr pkg = asKind<Package>(res);                   // try to access it as a package
00597         if (pkg) {                                                      // if its !=NULL, get size information
00598             _install_size -= pkg->size();
00599         }
00600     }
00601 
00602     return true;
00603 }
00604 
00605 
00606 // change state to UNNEEDED
00607 
00608 bool
00609 ResolverContext::unneeded (PoolItem_Ref item, int other_penalty)
00610 {
00611     ResStatus status;
00612 
00613     _XDEBUG( "ResolverContext[" << this << "]::unneeded(" << item << ")" );
00614 
00615     status = getStatus(item);
00616 
00617     if (status.wasInstalled()) {
00618         if (item->kind() != ResTraits<Patch>::kind
00619             && item->kind() != ResTraits<Atom>::kind
00620             && item->kind() != ResTraits<Script>::kind
00621             && item->kind() != ResTraits<Message>::kind) {
00622             setStatus (item, ResStatus::satisfied);
00623         } else {
00624             // Patch concerning resolvables have to be set to
00625             // "unneeded" although they are installed. In order
00626             // to get the state "no longer applicable" (Bug 171590)
00627             setStatus (item, ResStatus::unneeded);          
00628         }
00629     }
00630     else if (status.wasUninstalled()) {
00631         setStatus (item, ResStatus::unneeded);
00632     }
00633     return true;
00634 }
00635 
00636 
00637 // change state to SATISFIED
00638 
00639 bool
00640 ResolverContext::satisfy (PoolItem_Ref item, int other_penalty)
00641 {
00642     ResStatus status;
00643 
00644     status = getStatus(item);
00645 
00646     _XDEBUG( "ResolverContext[" << this << "]::satisfy(" << item << ":" << status << ")" );
00647 
00648     if (status.wasInstalled()) {
00649         setStatus (item, ResStatus::complete);
00650     }
00651     else if (status.wasUninstalled()) {
00652         setStatus (item, ResStatus::satisfied);
00653     }
00654 
00655     return true;
00656 }
00657 
00658 
00659 // change state to INCOMPLETE
00660 
00661 bool
00662 ResolverContext::incomplete (PoolItem_Ref item, int other_penalty)
00663 {
00664     ResStatus status = getStatus (item);
00665 
00666     _XDEBUG( "ResolverContext[" << this << "]::incomplete(" << item << "):" << status );
00667 
00668     if (_establishing) {
00669         if (status.wasInstalled()) {
00670             setStatus (item, ResStatus::incomplete);
00671         }
00672         else {
00673             setStatus (item, ResStatus::needed);
00674         }
00675     }
00676 
00677     return true;
00678 }
00679 
00680 //---------------------------------------------------------------------------
00681 
00682 // is it installed (after transaction), is unneeded or satisfied
00683 // if yes, install/requires requests are considered done
00684 
00685 bool
00686 ResolverContext::isPresent (PoolItem_Ref item, bool *unneeded, bool *installed)
00687 {
00688     ResStatus status = getStatus(item);
00689 
00690     bool res = ((status.staysInstalled() && !status.isIncomplete())
00691                 || (status.isToBeInstalled() && !status.isNeeded())
00692                 || status.isUnneeded()
00693                 || status.isSatisfied()
00694                 );
00695 
00696    if (unneeded) *unneeded = status.isUnneeded();
00697    if (installed) *installed = status.staysInstalled() || status.isToBeInstalled();
00698 
00699 _XDEBUG("ResolverContext::itemIsPresent(<" << status << ">" << item << ") " << (res?"Y":"N"));
00700 
00701     return res;
00702 }
00703 
00704 
00705 // is it uninstalled (after transaction) ?
00706 // if yes, uninstall requests are considered done
00707 
00708 bool
00709 ResolverContext::isAbsent (PoolItem_Ref item)
00710 {
00711     ResStatus status = getStatus(item);
00712 
00713     // DONT add incomplete here, uninstall requests for incompletes must be handled
00714 
00715     bool res = (status.staysUninstalled()
00716                 || status.isToBeUninstalled()
00717                 || status.isImpossible());
00718 
00719 _XDEBUG("ResolverContext::itemIsAbsent(<" << status << ">" << item << ") " << (res?"Y":"N"));
00720 
00721     return res;
00722 }
00723 
00724 
00725 //---------------------------------------------------------------------------
00726 // marked
00727 
00728 void
00729 ResolverContext::foreachMarked (MarkedPoolItemFn fn, void *data) const
00730 {
00731     ResolverContext_constPtr context = this;
00732     while (context) {
00733         for (Context::const_iterator iter = context->_context.begin(); iter != context->_context.end(); ++iter) {
00734             fn (iter->first, iter->second, data);
00735         }
00736         context = context->_parent;
00737     }
00738 }
00739 
00740 
00741 //---------------------------------------------------------------------------
00742 // collect
00743 
00744 typedef struct {
00745     PoolItemList *rl;
00746     int status;                         // <0: uninstalls, ==0: all, >0: installs
00747 } MarkedResolvableInfo;
00748 
00749 
00750 static void
00751 marked_item_collector (PoolItem_Ref item, const ResStatus & status, void *data)
00752 {
00753     MarkedResolvableInfo *info = (MarkedResolvableInfo *)data;
00754     if (info->status == 0
00755        || (info->status > 0 && status.isToBeInstalled())
00756        || (info->status < 0 && status.isToBeUninstalled()))
00757     {
00758         info->rl->push_back (item);
00759     }
00760 }
00761 
00762 
00763 PoolItemList
00764 ResolverContext::getMarked (int which) // <0: uninstalls, ==0: all, >0: installs
00765 {
00766     if ( _last_getMarked_which == which
00767          && _last_getMarked.size() > 0 )
00768         return _last_getMarked; // use the last run
00769 
00770     MarkedResolvableInfo info = { &_last_getMarked, which };
00771 
00772     foreachMarked (marked_item_collector, &info);
00773 
00774     _last_getMarked.sort(compare_items());
00775     _last_getMarked_which = which;
00776 
00777     return _last_getMarked;
00778 }
00779 
00780 //---------------------------------------------------------------------------
00781 // install
00782 
00783 typedef struct {
00784     ResPool pool;
00785     MarkedPoolItemFn fn;
00786     PoolItemList *rl;
00787     int count;
00788 } InstallInfo;
00789 
00790 static void
00791 install_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
00792 {
00793     InstallInfo *info = (InstallInfo *)data;
00794 
00795     if (status.isToBeInstalled()
00796         && !item.status().isInstalled()
00797         && !Helper::findInstalledItem( info->pool, item))
00798     {
00799         if (info->fn) info->fn (item, status, info->rl);
00800         ++info->count;
00801     }
00802 }
00803 
00804 
00805 int
00806 ResolverContext::foreachInstall (MarkedPoolItemFn fn, void *data) const
00807 {
00808     PoolItemList *rl = (PoolItemList *)data;
00809     InstallInfo info = { _pool, fn, rl, 0 };
00810 
00811     foreachMarked (install_item_cb, (void *)&info);
00812 
00813     return info.count;
00814 }
00815 
00816 
00817 static void
00818 context_item_collector (PoolItem_Ref item, const ResStatus & status, void *data)
00819 {
00820     PoolItemList *rl = (PoolItemList *)data;
00821     if (status.isToBeInstalled()
00822         || status.isToBeUninstalled())
00823     {
00824         rl->push_front (item);
00825     }
00826 }
00827 
00828 
00829 PoolItemList
00830 ResolverContext::getInstalls (void) const
00831 {
00832     PoolItemList rl;
00833 
00834     foreachInstall (context_item_collector, (void *)&rl);
00835 
00836     return rl;
00837 }
00838 
00839 
00840 //---------------------------------------------------------------------------
00841 // satisfy
00842 
00843 typedef struct {
00844     ResPool pool;
00845     MarkedPoolItemFn fn;
00846     PoolItemList *rl;
00847     int count;
00848 } SatisfyInfo;
00849 
00850 static void
00851 satisfy_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
00852 {
00853     SatisfyInfo *info = (SatisfyInfo *)data;
00854     if (status.isSatisfied()
00855        && ! status.staysInstalled ()
00856        && !Helper::findInstalledItem (info->pool, item))
00857     {
00858        if (info->fn) info->fn (item, status, info->rl);
00859        ++info->count;
00860     }
00861 }
00862 
00863 
00864 int
00865 ResolverContext::foreachSatisfy (MarkedPoolItemFn fn, void *data) const
00866 {
00867     PoolItemList *rl = (PoolItemList *)data;
00868     SatisfyInfo info = { _pool, fn, rl, 0 };
00869 
00870     foreachMarked (satisfy_item_cb, (void *)&info);
00871 
00872     return info.count;
00873 }
00874 
00875 
00876 static void
00877 context_item_collector_satisfy (PoolItem_Ref item, const ResStatus & status, void *data)
00878 {
00879     PoolItemList *rl = (PoolItemList *)data;
00880     if (status.isSatisfied ())
00881     {
00882        rl->push_front (item);
00883     }
00884 }
00885 
00886 
00887 PoolItemList
00888 ResolverContext::getSatisfies (void) const
00889 {
00890     PoolItemList rl;
00891 
00892     foreachSatisfy (context_item_collector_satisfy, (void *)&rl);
00893 
00894     return rl;
00895 }
00896 
00897 
00898 //---------------------------------------------------------------------------
00899 // incomplete
00900 
00901 typedef struct {
00902     ResPool pool;
00903     MarkedPoolItemFn fn;
00904     PoolItemList *rl;
00905     int count;
00906 } IncompleteInfo;
00907 
00908 static void
00909 incomplete_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
00910 {
00911     IncompleteInfo *info = (IncompleteInfo *)data;
00912 
00913     if (status.isIncomplete ()) {
00914        if (info->fn) info->fn (item, status, info->rl);
00915        ++info->count;
00916     }
00917 }
00918 
00919 
00920 int
00921 ResolverContext::foreachIncomplete (MarkedPoolItemFn fn, void *data) const
00922 {
00923     PoolItemList *rl = (PoolItemList *)data;
00924     IncompleteInfo info = { _pool, fn, rl, 0 };
00925 
00926     foreachMarked (incomplete_item_cb, (void *)&info);
00927 
00928     return info.count;
00929 }
00930 
00931 
00932 static void
00933 context_item_collector_incomplete (PoolItem_Ref item, const ResStatus & status, void *data)
00934 {
00935     PoolItemList *rl = (PoolItemList *)data;
00936     if (status.isIncomplete ())
00937     {
00938        rl->push_front (item);
00939     }
00940 }
00941 
00942 
00943 PoolItemList
00944 ResolverContext::getIncompletes (void) const
00945 {
00946     PoolItemList rl;
00947 
00948     foreachIncomplete (context_item_collector_incomplete, (void *)&rl);
00949 
00950     return rl;
00951 }
00952 
00953 
00954 //---------------------------------------------------------------------------
00955 // upgrade
00956 
00957 typedef struct {
00958     ResPool pool;
00959     MarkedPoolItemPairFn fn;
00960     void *data;
00961     ResolverContext_Ptr context;
00962     int count;
00963 } UpgradeInfo;
00964 
00965 static void
00966 upgrade_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
00967 {
00968     UpgradeInfo *info = (UpgradeInfo *)data;
00969 
00970     PoolItem_Ref installed_item;
00971 
00972     if (status.isToBeInstalled()
00973         && ! item.status().isInstalled ())
00974     {
00975         // check if there is already an installed item with same name and kind
00976         installed_item = Helper::findInstalledItem( info->pool, item );
00977         if (installed_item) {
00978 
00979             // there is an installed item, check its status
00980             ResStatus installed_status( info->context->getStatus( installed_item ) );
00981 
00982             // if it does not transact, it does not get updated (we have an allowed parallel install)
00983             if (!installed_status.transacts())
00984                 return;
00985 
00986             if (info->fn) {
00987                 info->fn (item, status, installed_item, installed_status, info->data);
00988             }
00989             ++info->count;
00990         }
00991     }
00992 }
00993 
00994 
00995 int
00996 ResolverContext::foreachUpgrade (MarkedPoolItemPairFn fn, void *data)
00997 {
00998     UpgradeInfo info = { _pool, fn, data, this, 0 };
00999 
01000     foreachMarked (upgrade_item_cb, (void *)&info);
01001 
01002     return info.count;
01003 }
01004 
01005 
01006 static void
01007 pair_item_collector (PoolItem_Ref item, const ResStatus & status, PoolItem_Ref old_item, const ResStatus & old_status, void *data)
01008 {
01009     PoolItemList *rl = (PoolItemList *)data;
01010     rl->push_back (item);
01011 }
01012 
01013 
01014 PoolItemList
01015 ResolverContext::getUpgrades (void)
01016 {
01017     PoolItemList rl;
01018 
01019     foreachUpgrade (pair_item_collector, (void *)&rl);
01020 
01021     return rl;
01022 }
01023 
01024 
01025 //---------------------------------------------------------------------------
01026 // uninstall
01027 
01028 typedef std::map<std::string,PoolItem_Ref> UpgradeTable;
01029 
01030 typedef struct {
01031     MarkedPoolItemFn fn;
01032     PoolItemList *rl;
01033     UpgradeTable upgrade_hash;
01034     int count;
01035 } UninstallInfo;
01036 
01037 static void
01038 uninstall_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01039 {
01040     UninstallInfo *info = (UninstallInfo *)data;
01041 
01042     UpgradeTable::const_iterator pos = info->upgrade_hash.find(item->name());
01043 
01044     if (status.isToBeUninstalled ()
01045         && pos == info->upgrade_hash.end())             // dont count upgrades
01046     {
01047         if (info->fn)
01048             info->fn (item, status, info->rl);
01049         ++info->count;
01050     }
01051 }
01052 
01053 
01054 static void
01055 build_upgrade_hash_cb (PoolItem_Ref item_add, const ResStatus & add_status, PoolItem_Ref item_del, const ResStatus & del_status, void *data)
01056 {
01057     UpgradeTable *upgrade_hash = (UpgradeTable *)data;
01058     (*upgrade_hash)[item_del->name()] = item_del;
01059 }
01060 
01061 
01062 int
01063 ResolverContext::foreachUninstall (MarkedPoolItemFn fn, void *data)
01064 {
01065     UninstallInfo info;         // inits upgrade_hash
01066 
01067     info.fn = fn;
01068     info.rl = (PoolItemList *)data;
01069     info.count = 0;
01070 
01071     foreachUpgrade (build_upgrade_hash_cb, (void *)&(info.upgrade_hash));
01072     foreachMarked (uninstall_item_cb, (void *)&info);
01073 
01074     return info.count;
01075 }
01076 
01077 
01078 PoolItemList
01079 ResolverContext::getUninstalls (void)
01080 {
01081     PoolItemList rl;
01082 
01083     foreachUninstall (context_item_collector, (void *)&rl);
01084 
01085     return rl;
01086 }
01087 
01088 
01089 //---------------------------------------------------------------------------
01090 // impossible
01091 
01092 typedef struct {
01093     ResPool pool;
01094     MarkedPoolItemFn fn;
01095     int count;
01096     void *data;
01097 } ImpossibleInfo;
01098 
01099 static void
01100 impossible_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01101 {
01102     ImpossibleInfo *info = (ImpossibleInfo *)data;
01103 
01104     if (status.isImpossible ()) {
01105        if (info->fn) info->fn (item, status, info->data);
01106        ++info->count;
01107     }
01108 }
01109 
01110 
01111 int
01112 ResolverContext::foreachImpossible (MarkedPoolItemFn fn, void *data)
01113 {
01114     ImpossibleInfo info = { _pool, fn, 0, data };
01115 
01116     foreachMarked (impossible_item_cb, (void *)&info);
01117 
01118     return info.count;
01119 }
01120 
01121 
01122 //---------------------------------------------------------------------------
01123 
01124 static void
01125 install_count_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01126 {
01127     int *count = (int *)data;
01128     if (!item.status().isInstalled ()) {
01129         ++*count;
01130     }
01131 }
01132 
01133 int
01134 ResolverContext::installCount (void) const
01135 {
01136     int count = 0;
01137 
01138     foreachInstall (install_count_cb, (void *)&count);
01139 
01140     return count;
01141 }
01142 
01143 
01144 static void
01145 uninstall_count_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01146 {
01147     int *count = (int *)data;
01148     if (item.status().isInstalled ()) {
01149         ++*count;
01150     }
01151 }
01152 
01153 
01154 int
01155 ResolverContext::uninstallCount (void)
01156 {
01157     int count = 0;
01158 
01159     foreachUninstall (uninstall_count_cb, (void *)&count);
01160 
01161     return count;
01162 }
01163 
01164 
01165 int
01166 ResolverContext::upgradeCount (void)
01167 {
01168     return foreachUpgrade ((MarkedPoolItemPairFn)NULL, (void *)NULL);
01169 }
01170 
01171 
01172 static void
01173 satisfy_count_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01174 {
01175     int *count = (int *)data;
01176     if (!item.status().isInstalled ()) {
01177         ++*count;
01178     }
01179 }
01180 
01181 int
01182 ResolverContext::satisfyCount (void) const
01183 {
01184     int count = 0;
01185 
01186     foreachSatisfy (satisfy_count_cb, (void *)&count);
01187 
01188     return count;
01189 }
01190 
01191 
01192 int
01193 ResolverContext::incompleteCount (void) const
01194 {
01195     return foreachIncomplete ((MarkedPoolItemFn)NULL, (void *)NULL);
01196 }
01197 
01198 
01199 
01200 //---------------------------------------------------------------------------
01201 // info
01202 
01203 void
01204 ResolverContext::addInfo (ResolverInfo_Ptr info, bool askUser)
01205 {
01206     _XDEBUG( "ResolverContext[" << this << "]::addInfo(" << *info << ")" );
01207     _log.push_back (info);
01208 
01209     // _propagated_importance = false;
01210 
01211     if (info->error ()
01212         && !askUser) { // Go forward in order to evaluate more problems
01213 
01214         if (! _invalid) {
01215             ResolverInfo_Ptr info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_INVALID_SOLUTION, PoolItem_Ref(), RESOLVER_INFO_PRIORITY_VERBOSE);
01216             info->flagAsError ();
01217             _log.push_back (info);
01218         }
01219 
01220         _invalid = true;
01221     }
01222     if (askUser)
01223         _askUser = true;
01224 }
01225 
01226 
01227 void
01228 ResolverContext::addError (ResolverInfo_Ptr info, bool askUser)
01229 {
01230     bool is_error = true;
01231 
01232     if (info->type() == RESOLVER_INFO_TYPE_UNINSTALL_LOCKED) {
01233         for (PoolItemList::const_iterator iter = _ignoreInstalledItem.begin(); iter != _ignoreInstalledItem.end(); iter++) {
01234             if (info->affected() == *iter) {
01235                 XXX << "ignore keep installed: " << info->affected() << endl;
01236                 is_error = false;
01237                 break;
01238             }
01239         }
01240     }
01241 
01242     if (is_error)
01243         info->flagAsError ();
01244 
01245     WAR << "******** Error: " << *info << endl;
01246     addInfo (info, askUser);
01247 }
01248 
01249 
01250 //---------------------------------------------------------------------------
01251 // foreach info
01252 
01253 //  We call a item mentioned by an error info an "error-item".
01254 //  We call a item mentioned by an important info an "important-item".
01255 //
01256 //  The rules:
01257 //  (1) An info item that mentions an error-item is important.
01258 //  (2) An info item is about an important-item is important.
01259 
01260 static void
01261 mark_important_info (const ResolverInfoList & il)
01262 {
01263     // set of all items mentioned in the ResolverInfoList
01264     PoolItemSet error_set;
01265 
01266     bool did_something;
01267     int pass_num = 1;
01268 
01269     /* First of all, store all error-items in a set. */
01270 
01271     for (ResolverInfoList::const_iterator info_iter = il.begin(); info_iter != il.end(); ++info_iter) {
01272         ResolverInfo_Ptr info = (*info_iter);
01273         if (info != NULL                                                // list items might be NULL
01274             && info->error ())                                          // only look at error infos
01275         {
01276             PoolItem_Ref item = info->affected();               // get item from ResolverInfoList
01277             if (item) {
01278                 error_set.insert (item);
01279             }
01280 
01281             // the info might be a container, check it by doing a dynamic cast
01282 
01283             PoolItemList containerItems;
01284             ResolverInfoContainer_constPtr c = dynamic_pointer_cast<const ResolverInfoContainer>(*info_iter);
01285             if (c != NULL) containerItems = c->items();
01286 
01287             // containerItems is non-empty if info is really a ResolverInfoContainer
01288 
01289             for (PoolItemList::iterator res_iter = containerItems.begin(); res_iter != containerItems.end(); res_iter++) {
01290                 PoolItem_Ref item = (*res_iter);
01291                 if (item) {
01292                     error_set.insert (item);
01293                 }
01294             }
01295         }
01296     }
01297 
01298     // now collect all important ones
01299 
01300     PoolItemSet important_set;
01301 
01302     do {
01303         ++pass_num;
01304         assert (pass_num < 10000);
01305 
01306         did_something = false;
01307 
01308         for (ResolverInfoList::const_iterator info_iter = il.begin(); info_iter != il.end(); ++info_iter) {
01309 
01310             ResolverInfo_Ptr info = (*info_iter);
01311 
01312             if (info != NULL                                            // list items might be set to NULL
01313                 && !info->important ())                                 // only look at ones we didn't consider yet
01314             {
01315                 bool should_be_important = false;
01316 
01317                 for (PoolItemSet::const_iterator res_iter = error_set.begin(); res_iter != error_set.end() && ! should_be_important; ++res_iter) {
01318                     ResolverInfoContainer_constPtr c = dynamic_pointer_cast<const ResolverInfoContainer>(*info_iter);
01319                     if (c != NULL                                       // check if it really is a container
01320                         && c->mentions (*res_iter))
01321                     {
01322                         should_be_important = true;
01323                     }
01324                 }
01325 
01326                 for (PoolItemSet::const_iterator res_iter = important_set.begin(); res_iter != important_set.end() && ! should_be_important; ++res_iter) {
01327                     if (info->isAbout (*res_iter)) {
01328                         should_be_important = true;
01329                         break;
01330                     }
01331                 }
01332 
01333                 if (should_be_important) {
01334                     did_something = true;
01335                     info->flagAsImportant ();
01336                     PoolItemList items;
01337                     ResolverInfoContainer_constPtr c = dynamic_pointer_cast<const ResolverInfoContainer>(*info_iter);           // check if it really is a container
01338                     if (c != NULL) items = c->items();
01339                     for (PoolItemList::iterator res_iter = items.begin(); res_iter != items.end(); res_iter++) {
01340                         important_set.insert (*res_iter);
01341                     }
01342                 }
01343             }
01344         }
01345 
01346     } while (did_something);
01347 
01348 }
01349 
01350 void
01351 ResolverContext::foreachInfo (PoolItem_Ref item, int priority, ResolverInfoFn fn, void *data,
01352                               const bool merge, const bool findImportant) const
01353 {
01354     ResolverInfoList info_list;
01355 
01356     ResolverContext_constPtr context = this;
01357      // Assemble a list of copies of all of the info objects
01358     while (context != NULL) {
01359 
01360         for (ResolverInfoList::const_iterator iter = context->_log.begin(); iter != context->_log.end(); ++iter) {
01361 
01362             ResolverInfo_Ptr info = *iter;
01363 
01364             if ((item == PoolItem_Ref()
01365                  || info->affected() == item)
01366                 && info->priority() >= priority)
01367             {
01368                 info_list.push_back( info );
01369 
01370                 if (!merge
01371                     && !findImportant) {
01372                     // invoke our callback in order to avoid an additional run over the complete list
01373                     fn( info, data );               
01374                 }
01375             }
01376         }
01377         context = context->_parent;
01378     }
01379     if (merge) {
01380         // Merge info objects
01381         for (ResolverInfoList::iterator iter = info_list.begin(); iter != info_list.end(); ++iter) {
01382 
01383             ResolverInfo_Ptr info1 = (*iter);
01384             ResolverInfoList::iterator subiter = iter;
01385 
01386             if (info1 != NULL) {
01387                 for (subiter++; subiter != info_list.end();) {
01388                     ResolverInfo_Ptr info2 = *subiter;
01389                     ResolverInfoList::iterator next = subiter; ++next;
01390                     if (info2 && info1->merge (info2)) {
01391                         info_list.erase( subiter );
01392                     }
01393                     subiter = next;
01394                 }
01395             }
01396         }
01397     }
01398 
01399     if (findImportant) mark_important_info( info_list );
01400 
01401     if (merge
01402         || findImportant) {    
01403         // Walk across the list of info objects and invoke our callback
01404 
01405         for (ResolverInfoList::iterator iter = info_list.begin(); iter != info_list.end(); ++iter) {
01406             if (*iter != NULL) {
01407                 fn( *iter, data );
01408             }
01409         }
01410     }
01411 }
01412 
01413 
01414 
01415 static void
01416 get_info_foreach_cb (ResolverInfo_Ptr info, void *data)
01417 {
01418     ResolverInfoList *il = (ResolverInfoList *)data;
01419 
01420     if (info->important ()) {
01421         il->push_back (info);
01422     }
01423 }
01424 
01425 
01426 
01427 ResolverInfoList
01428 ResolverContext::getInfo (void) const
01429 {
01430     ResolverInfoList il;
01431     foreachInfo (PoolItem_Ref(), -1, get_info_foreach_cb, (void *)&il);
01432     return il;
01433 }
01434 
01435 
01436 //---------------------------------------------------------------------------
01437 // spew
01438 
01439 static void
01440 spew_item_cb (PoolItem_Ref item, const ResStatus & status, void *unused)
01441 {
01442     MIL << "  " << item << " (" << status << ")" << endl;
01443 }
01444 
01445 
01446 void
01447 spew_item_pair_cb (PoolItem_Ref item1, const ResStatus & status1, PoolItem_Ref item2, const ResStatus & status2, void *unused)
01448 {
01449     MIL << "  " << item2 << " (" << status2 << ") => (" << item1 << " (" << status2 << ")" << endl;
01450 }
01451 
01452 
01453 void
01454 ResolverContext::spew (void)
01455 {
01456     MIL << "TO INSTALL:" << endl;
01457     foreachInstall (spew_item_cb, NULL);
01458     MIL << endl;
01459 
01460     MIL << "TO REMOVE:" << endl;
01461     foreachUninstall (spew_item_cb, NULL);
01462     MIL << endl;
01463 
01464     MIL << "TO UPGRADE:" << endl;
01465     foreachUpgrade (spew_item_pair_cb, NULL);
01466     MIL << endl;
01467 }
01468 
01469 
01470 static void
01471 spew_info_cb (ResolverInfo_Ptr info, void *unused)
01472 {
01473     if (info == NULL) return;
01474 
01475     if (info->error ()) MIL << "[ERROR] " << *info << endl;
01476     else if (info->important()) MIL << "[>>>>>] " << *info << endl;
01477     else MIL << *info << endl;
01478 }
01479 
01480 
01481 void
01482 ResolverContext::spewInfo (void) const
01483 {
01484     _XDEBUG( "ResolverContext[" << this << "]::spewInfo" );
01485     foreachInfo (PoolItem_Ref(), -1, spew_info_cb, NULL, false, false);
01486 }
01487 
01488 //---------------------------------------------------------------------------
01489 // requirements
01490 
01491 struct RequirementMet
01492 {
01493     ResolverContext_Ptr context;
01494     bool flag;
01495     bool unneeded;
01496     bool *installed;
01497     const PoolItem_Ref whoNeeds;
01498     const Dep cap;
01499     const bool installInfoFlag;
01500     bool allAtomsSatisfied;
01501 
01502     RequirementMet (ResolverContext_Ptr ctx, bool *inst, const PoolItem_Ref who, const Dep & capKind, const bool instFlag)
01503         : context (ctx)
01504         , flag (false)
01505         , unneeded( false )
01506         , installed( inst )
01507         , whoNeeds( who )
01508         , cap( capKind )
01509         , installInfoFlag( instFlag )
01510         , allAtomsSatisfied(true)
01511     { }
01512 
01513 
01514     bool operator()( const CapAndItem & cai )
01515     {
01516         Capability match( cai.cap );
01517         PoolItem provider( cai.item );
01518         // capability is set for item set children. If it is set, query the
01519         //   exact version only.
01520         bool my_unneeded = false;
01521         if (context->isPresent( provider, &my_unneeded, installed ))
01522         {
01523             unneeded = my_unneeded;
01524             flag = true;
01525             ResolverInfoNeededBy_Ptr info;
01526 
01527             if (cap == Dep::PREREQUIRES
01528                 || cap == Dep::REQUIRES
01529                 || cap == Dep::RECOMMENDS
01530                 || cap == Dep::SUGGESTS) {
01531                 info = new ResolverInfoNeededBy (provider);
01532                 info->addRelatedPoolItem (whoNeeds);
01533             } else {
01534                 // FRESHENS, ENHANCES, SUPPLEMENTS
01535                 // are reverse dependencies
01536                 info = new ResolverInfoNeededBy (whoNeeds);
01537                 info->addRelatedPoolItem (provider);
01538                 if (installInfoFlag)
01539                     info->setInitialInstallation (true);
01540             }
01541             info->setCapability (match, cap);
01542             context->addInfo (info);        
01543         } else {
01544             if (isKind<Atom>(provider.resolvable()) ) {
01545                 allAtomsSatisfied = false;
01546             }
01547         }
01548 
01549 //      ERR << "RequirementMet(" <<  provider << ", " << match << ") [capability " <<
01550 //        capability << "] -> " <<  (flag ? "true" : "false") << endl;
01551         
01552         if ( (installed // Checking as long as we have found an installed item
01553               && !*installed)
01554              || isKind<Atom>(provider.resolvable())) // checking all Atoms
01555             return true;
01556         
01557         return ! flag;
01558     }
01559 };
01560 
01561 
01562 bool
01563 ResolverContext::requirementIsMet (const Capability & capability,
01564                                    const PoolItem_Ref who,
01565                                    const Dep & capKind,
01566                                    bool *unneeded, bool *installed,
01567                                    const bool installInfoFlag)
01568 {
01569     RequirementMet info (this, installed, who, capKind, installInfoFlag);
01570 
01571     //    world()->foreachProviding (capability, requirement_met_cb, (void *)&info);
01572 
01573     Dep dep( Dep::PROVIDES );
01574 
01575     // world->foreachProvidingResItem (capability, require_process_cb, &info);
01576 
01577     invokeOnEach( pool().byCapabilityIndexBegin( capability.index(), dep ),
01578                   pool().byCapabilityIndexEnd( capability.index(), dep ),
01579                   resfilter::ByCapMatch( capability ),
01580                   functor::functorRef<bool,CapAndItem>(info) );
01581 _XDEBUG( "ResolverContext::requirementIsMet(" << capability << ") " << (info.flag?"Y":"N") );
01582     if (unneeded) *unneeded = info.unneeded;
01583 
01584     return info.flag && info.allAtomsSatisfied;
01585 }
01586 
01587 //---------------------------------------------------------------------------
01594 bool
01595 ResolverContext::requirementIsInstalledOrUnneeded (const Capability & capability,
01596                                                    const PoolItem_Ref who,
01597                                                    const Dep & capKind)
01598 {
01599     ResObject::Kind kind = who->kind();
01600     bool fulfilled = false;
01601            
01602     if (kind != ResTraits<Package>::kind
01603         || kind != ResTraits<Script>::kind
01604         || kind != ResTraits<Message>::kind)
01605     {
01606        bool unneeded, installed;
01607        fulfilled = requirementIsMet (capability, who, capKind, &unneeded, &installed);
01608        if (!fulfilled
01609            || (!unneeded
01610                && !installed)) {
01611            fulfilled = false;
01612            _XDEBUG("Requirement is not unneeded and not installed.");
01613            // "low" level resolvables will be installed if they are not unneeded
01614            // Bug 192535/204913
01615        }
01616     }else {
01617        fulfilled = requirementIsMet (capability, who, capKind);
01618     }
01619 
01620     return fulfilled;
01621 }
01622 
01623 
01624 
01625 //---------------------------------------------------------------------------
01626 
01627 struct RequirementPossible
01628 {
01629     ResolverContext_Ptr context;
01630     bool flag;
01631 
01632     RequirementPossible( ResolverContext_Ptr ctx )
01633         : context (ctx)
01634         , flag (false)
01635     { }
01636 
01637     bool operator()( const CapAndItem & cai )
01638     {
01639         PoolItem provider( cai.item );
01640         ResStatus status = context->getStatus( provider );
01641         if (! (status.isToBeUninstalled () || status.isImpossible())
01642             || status.isToBeUninstalledDueToUnlink())
01643         {
01644             flag = true;
01645         }
01646 
01647         // Checking, if it has already been selected for removing by the user
01648         // Bug 155368; Testcase data.deptestomatic/yast-tests/bug155368-test.xml
01649         if (flag
01650             && !context->forceResolve()) {
01651             PoolItem installedItem = Helper::findInstalledByNameAndKind (context->pool(), provider->name(), provider->kind() );
01652             if (installedItem) {
01653                 ResStatus statusInstalled = context->getStatus (installedItem);
01654                 if (installedItem.status().isToBeUninstalled()
01655                     && installedItem.status().isByUser()){
01656                     XXX << provider << " would satify the requirement but it has been selected for removing by the user." << endl;
01657                     flag = false;
01658                 }
01659             }
01660         }
01661         
01662         return ! flag;
01663     }
01664 };
01665 
01666 
01667 bool
01668 ResolverContext::requirementIsPossible (const Capability & capability)
01669 {
01670     RequirementPossible info( this );
01671 
01672     // world()->foreachProviding (dep, requirement_possible_cb, (void *)&info);
01673 
01674     Dep dep( Dep::PROVIDES );
01675 
01676     invokeOnEach( pool().byCapabilityIndexBegin( capability.index(), dep ),
01677                   pool().byCapabilityIndexEnd( capability.index(), dep ),
01678                   resfilter::ByCapMatch( capability ),
01679                   functor::functorRef<bool,CapAndItem>(info) );
01680     _XDEBUG("requirementIsPossible( " << capability << ") = " << (info.flag ? "Y" : "N"));
01681     return info.flag;
01682 }
01683 
01684 
01685 bool
01686 ResolverContext::itemIsPossible( PoolItem_Ref item, Capability & failed )
01687 {
01688     CapSet requires = item->dep (Dep::REQUIRES);
01689     for (CapSet::iterator iter = requires.begin(); iter !=  requires.end(); iter++) {
01690         if (! requirementIsPossible (*iter)) {
01691             failed = *iter;
01692             return false;
01693         }
01694     }
01695 
01696     return true;
01697 }
01698 
01699 //---------------------------------------------------------------------------
01700 
01701 typedef struct {
01702     PoolItem_Ref other;
01703     bool flag;
01704     PoolItem_Ref foundItem;
01705 } DupNameCheckInfo;
01706 
01707 static void
01708 dup_name_check_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01709 {
01710     DupNameCheckInfo *info = (DupNameCheckInfo *)data;
01711     if (! info->flag
01712         && status.isToBeInstalled ()
01713         && info->other->kind() == item->kind()
01714         && info->other->name() == item->name()
01715 #if 0
01716         && item->edition().compare(info->other->edition()) == 0
01717         && item->arch() == info->other->arch()
01718 #endif
01719         && item != info->other) // if it's exactly the same package, ignore it silently.
01720     {
01721         Package::constPtr p1 = asKind<Package>(item.resolvable());
01722         Package::constPtr p2 = asKind<Package>(info->other.resolvable());
01723         if (p1 && p2 && p1->installOnly() && p2->installOnly())         // both are parallel installable
01724             return;
01725 
01726         info->flag = true;
01727         info->foundItem = item;
01728     }
01729 }
01730 
01731 
01732 bool
01733 ResolverContext::isParallelInstall (PoolItem_Ref item) const
01734 {
01735     if (item->kind() == ResTraits<Atom>::kind) {
01736         return false;                                   // Atoms are paralell installable (#170098)
01737     }
01738 
01739     for (PoolItemList::const_iterator iter = _ignoreInstalledItem.begin();
01740          iter != _ignoreInstalledItem.end(); iter++) {
01741         if (item == *iter) {
01742             XXX << "ignore parallel install: " << item << endl;
01743             return false;
01744         }
01745     }
01746     
01747     DupNameCheckInfo info;
01748 
01749     info.other = item;
01750     info.flag = false;
01751     foreachMarked (dup_name_check_cb, (void *)&info);
01752     if (info.flag) {
01753         XXX << "isParallelInstall!!(" << item << ", " << info.foundItem << ")" << endl;
01754     }
01755     return info.flag;
01756 }
01757 
01758 
01759 PoolItem_Ref
01760 ResolverContext::getParallelInstall (PoolItem_Ref item) const
01761 {
01762     DupNameCheckInfo info;
01763 
01764     info.other = item;
01765     info.flag = false;
01766     foreachMarked( dup_name_check_cb, (void *)&info );
01767     return info.foundItem;
01768 }
01769 
01770 
01771 int
01772 ResolverContext::getRepoPriority (Repository repo) const
01773 {
01774 #warning fix repo priority
01775   return 0;
01776 //     if (repo.subscribed())
01777 //      return repo.priority();
01778 //     return repository.priorityUnsubscribed();
01779 }
01780 
01781 //---------------------------------------------------------------------------
01782 
01783 static int
01784 num_cmp (double a, double b)
01785 {
01786     return (b < a) - (a < b);
01787 }
01788 
01789 static int
01790 rev_num_cmp (double a, double b)
01791 {
01792     return (a < b) - (b < a);
01793 }
01794 
01795 static double
01796 churn_factor (ResolverContext_Ptr a)
01797 {
01798     return a->upgradeCount() + (2.0 * a->installCount ()) + (4.0 * a->uninstallCount ());
01799 }
01800 
01801 void
01802 ResolverContext::collectCompareInfo (int & cmpVersion,    // Version compare of ACCUMULATED items
01803                                      int & cmpRepo,    // compare of Repositories
01804                                      ResolverContext_Ptr compareContext)
01805 {
01806     Repository userRepo;         // Repo Id of items which have been selected by the user for installation
01807                                    // It is empty, if there are different repos
01808     bool differentUserRepos = false;
01809     Repository userRepoCompare;  // Repo Id of items which have been selected by the user for installation
01810                                    // It is empty, if there are different repos
01811     bool differentUserCompareRepos = false;    
01812     RepositoryCounter thisMap;         // Map of to be installed repositorys with an item counter
01813     RepositoryCounter compareMap;      // Map of to be installed repositorys with an item counter
01814     
01815     PoolItemList installList = getMarked(1);
01816     PoolItemList compareList = compareContext->getMarked(1);; // List of comparing items which has to be installed
01817     PoolItemList::const_iterator itCompare = compareList.begin();
01818     _XDEBUG ("Starting comparing two solutions--------");
01819     for ( PoolItemList::const_iterator thisIt = installList.begin();
01820           thisIt != installList.end(); thisIt++ )
01821     {
01822         // evaluate, if the user selected packages (items) has the same repository
01823         ResStatus status = getStatus (*thisIt);
01824         if (status.isByUser()
01825             || thisIt->status().isByUser())
01826         {
01827             if (userRepo == Repository::noRepository
01828                 && !differentUserRepos)
01829             {
01830                 userRepo = thisIt->resolvable()->repository();
01831             }
01832             else if (userRepo != thisIt->resolvable()->repository())
01833             {
01834                 differentUserRepos = true; // there are other items of other repositorys which have been set by the user
01835             }
01836         }
01837 
01838         // collecting relationship between channels and installed items
01839         if (thisMap.find (thisIt->resolvable()->repository()) == thisMap.end()) {
01840             thisMap[thisIt->resolvable()->repository()] = 1;
01841         }
01842         else {
01843             thisMap[thisIt->resolvable()->repository()] += 1;
01844         }
01845         _XDEBUG ("Count of left " << thisIt->resolvable()->repository() << ": " << thisMap[thisIt->resolvable()->repository()] << " : " << *(thisIt->resolvable()));    
01846 
01847         // Comparing versions
01848         while (itCompare != compareList.end() )
01849         {
01850             int cmp = compareByN ( thisIt->resolvable(), itCompare->resolvable());
01851             if ( cmp == 0) {
01852                 // comparing the version of both items and "adding" the result
01853                 // to accumulated compare result.
01854                 // Testcase: freshen-tests/exercise-7f-test
01855                 // Testcase: freshen-tests/exercise-7-test
01856                 cmpVersion += thisIt->resolvable()->edition().compare( itCompare->resolvable()->edition());
01857                 _XDEBUG ("Version: " << *(thisIt->resolvable()) << "[" << thisIt->resolvable()->repository() << "]" << endl
01858                          << " <--> " << endl 
01859                          << "Version: " << *(itCompare->resolvable()) << "[" << itCompare->resolvable()->repository() << "]"
01860                          << " --> cmpVersion : " << cmpVersion);                
01861 
01862                 // evaluate if the user selected packages (items) has the same repository
01863                 ResObject::constPtr repositoryItem = itCompare->resolvable();
01864                 ResStatus compStatus = compareContext->getStatus(*itCompare);
01865                 if (compStatus.isByUser()
01866                     || itCompare->status().isByUser())
01867                 {
01868                     if (userRepoCompare == Repository::noRepository
01869                         && !differentUserCompareRepos)
01870                         userRepoCompare = repositoryItem->repository();
01871                     else if (userRepoCompare != repositoryItem->repository())
01872                         differentUserCompareRepos = true; // there are other items of other repositorys which have been set by the user
01873                 }
01874                 // collecting relationship between channels and installed items
01875                 if (compareMap.find (repositoryItem->repository()) == compareMap.end()) 
01876                     compareMap[repositoryItem->repository()] = 1;
01877                 else
01878                     compareMap[repositoryItem->repository()] += 1;
01879                 _XDEBUG ("Count of right " << repositoryItem->repository() << ": " << compareMap[repositoryItem->repository()] << " : " << *(itCompare->resolvable()));
01880                 itCompare++;
01881             } else if (cmp > 0 )
01882                 itCompare++;
01883             else break;
01884         }
01885     }
01886 
01887     // comparing the rest of the other install list
01888     while (itCompare != compareList.end() )
01889     {
01890         // evaluate if the user selected packages (items) has the same repository
01891         ResObject::constPtr repositoryItem = itCompare->resolvable();
01892         ResStatus compStatus = compareContext->getStatus(*itCompare);
01893         if (compStatus.isByUser()
01894             || itCompare->status().isByUser()) 
01895         {
01896             if (userRepoCompare == Repository::noRepository
01897                 && !differentUserCompareRepos)
01898                     userRepoCompare = repositoryItem->repository();             
01899             else if (userRepoCompare != repositoryItem->repository())
01900                 differentUserCompareRepos = true; // there are other items of other repositorys which have been set by the user         
01901         }
01902 
01903         // collecting relationship between channels and installed items
01904         if (compareMap.find (repositoryItem->repository()) == compareMap.end()) 
01905             compareMap[repositoryItem->repository()] = 1;
01906         else
01907             compareMap[repositoryItem->repository()] += 1;
01908         _XDEBUG ("Count of right" << repositoryItem->repository() << ": " << compareMap[repositoryItem->repository()] << " : "
01909                  << *(itCompare->resolvable()));        
01910         itCompare++;    
01911     }
01912 
01913     // evaluate cmpRepo
01914     cmpRepo = 0;
01915     int cmpCompare = 0;
01916 
01917     if (!differentUserRepos)
01918     {
01919         // user selected items which has to be installed has only one channel;
01920         // cmpRepo = number of items of that channel
01921         cmpRepo = thisMap[userRepo];
01922     }
01923         
01924     if (!differentUserCompareRepos) {
01925         // user selected items which has to be installed has only one channel;  
01926         // cmpCompare = number of items of that channel
01927         cmpCompare = compareMap[userRepoCompare];
01928     }
01929     _XDEBUG ("cmpRepo = " << cmpRepo << " ; cmpCompare = " << cmpCompare << " ; sizeof compareMap:" <<  compareMap.size());
01930     if (compareMap.size() == 1
01931         && thisMap.size() == 1
01932         && userRepo == userRepoCompare) {
01933         // We have only one repository from which all items will be instaled.
01934         // So we will regards the complete amount of installed/updated packages
01935         // Testcase basic-exercises/exercise-14-test
01936         cmpRepo = 0;
01937     } else {
01938         // The solutions has different channels with user selected items.
01939         // Take the solution with the greater account of items in this channel
01940         // Testcase basic-exercises/exercise-solution-order-test
01941         cmpRepo = cmpRepo - cmpCompare;     
01942     }
01943 
01944     if (cmpRepo == 0)
01945     {
01946         // less amount of channels are better
01947         cmpRepo = compareMap.size() - thisMap.size();
01948     }
01949     _XDEBUG ("End comparing two solutions-------- Version compare: " << cmpVersion << " Repo compare: "<< cmpRepo);    
01950 }
01951 
01952 int
01953 ResolverContext::partialCompare (ResolverContext_Ptr context)
01954 {
01955     int cmp = 0;
01956     if (this != context) {
01957 
01958         // collecting all data for comparing both resultion results
01959         int  cmpVersion = 0; // Version compare of ACCUMULATED items
01960         int  cmpRepo = 0;  // compare of Repos
01961 
01962         collectCompareInfo (cmpVersion, cmpRepo, context);
01963         if (_preferHighestVersion) {
01964             // comparing versions
01965             cmp = cmpVersion;
01966             XXX << "Comparing versions returned :" << cmp << endl;
01967             if (cmp == 0) { 
01968                 // High numbers are good... we don't want solutions containing low-priority channels.
01969                 // Repo priority which has been set externally
01970                 cmp = num_cmp (_min_priority, context->_min_priority);
01971                 XXX << "Comparing priority returned :" << cmp << endl;
01972                 if (cmp == 0) {
01973                     // High numbers are bad.  Less churn is better.
01974                     cmp = rev_num_cmp (churn_factor (this), churn_factor (context));
01975                     XXX << "Comparing churn_factor returned :" << cmp << endl;
01976                     if (cmp == 0) {             
01977                         // Comparing repositorys regarding the items which has to be installed
01978                         cmp = cmpRepo;
01979                         XXX << "Comparing repositorys returned :" << cmp << endl;               
01980                         if (cmp == 0) {
01981                             // High numbers are bad.  Bigger #s means more penalties.
01982                             cmp = rev_num_cmp (_other_penalties, context->_other_penalties);
01983                             XXX << "Comparing other penalties returned :" << cmp << endl;                       
01984                         }
01985                     }
01986                 }
01987             }
01988         } else {
01989             // less transaction will be prefered
01990             // High numbers are bad.  Less churn is better.
01991             cmp = rev_num_cmp (churn_factor (this), churn_factor (context));
01992             XXX << "Comparing churn_factor returned :" << cmp << endl;      
01993             if (cmp == 0) { 
01994                 // High numbers are good... we don't want solutions containing low-priority channels.
01995                 // Repo priority which has been set externally
01996                 cmp = num_cmp (_min_priority, context->_min_priority);
01997                 XXX << "Comparing priority returned :" << cmp << endl;
01998                 if (cmp == 0) {
01999                     cmp = cmpVersion;
02000                     XXX << "Comparing versions returned :" << cmp << endl;
02001                     if (cmp == 0) {             
02002                         // Comparing repositorys regarding the items which has to be installed
02003                         cmp = cmpRepo;
02004                         XXX << "Comparing repositorys returned :" << cmp << endl;               
02005                         if (cmp == 0) {
02006                             // High numbers are bad.  Bigger #s means more penalties.
02007                             cmp = rev_num_cmp (_other_penalties, context->_other_penalties);
02008                             XXX << "Comparing other penalties returned :" << cmp << endl;                       
02009                         }
02010                     }
02011                 }
02012             }       
02013         }
02014     }
02015 
02016     return cmp;
02017 }
02018 
02019 int
02020 ResolverContext::compare (ResolverContext_Ptr context)
02021 {
02022     int cmp;
02023     
02024     if (this == context)
02025         return 0;
02026     
02027     cmp = partialCompare (context);
02028     if (cmp)
02029         return cmp;
02030     
02031     /* High numbers are bad.  Smaller downloads are best. */
02032     cmp = rev_num_cmp (_download_size, context->_download_size);
02033     if (cmp)
02034         return cmp;
02035     
02036     /* High numbers are bad.  Less disk space consumed is good. */
02037     cmp = rev_num_cmp (_install_size, context->_install_size);
02038     if (cmp)
02039         return cmp;
02040     
02041     return 0;
02042 }
02043 
02045     };// namespace detail
02048   };// namespace solver
02051 };// namespace zypp
02053 

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