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

Generated on Fri Jul 4 16:57:59 2008 for zypp by  doxygen 1.5.0