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 
00671     return true;
00672 }
00673 
00674 //---------------------------------------------------------------------------
00675 
00676 // is it installed (after transaction), is unneeded or satisfied
00677 // if yes, install/requires requests are considered done
00678 
00679 bool
00680 ResolverContext::isPresent (PoolItem_Ref item, bool *unneeded, bool *installed)
00681 {
00682     ResStatus status = getStatus(item);
00683 
00684     bool res = false;
00685     if (item->kind() == ResTraits<Atom>::kind
00686         || item->kind() == ResTraits<Patch>::kind
00687         || item->kind() == ResTraits<Script>::kind
00688         || item->kind() == ResTraits<Message>::kind) {    
00689         res = ((status.staysInstalled() && !status.isIncomplete())
00690                 || (status.isToBeInstalled() && !status.isNeeded())
00691                 || status.isUnneeded()
00692                 || status.isSatisfied()
00693                 );
00694     } else {
00695         // packages, patterns are present although they are incomplete or unneeded (Bug289577)
00696         res = (status.staysInstalled() || status.isToBeInstalled());
00697     }
00698 
00699    if (unneeded) *unneeded = status.isUnneeded();
00700    if (installed) *installed = status.staysInstalled() || status.isToBeInstalled();
00701 
00702 _XDEBUG("ResolverContext::itemIsPresent(<" << status << ">" << item << ") " << (res?"Y":"N"));
00703 
00704     return res;
00705 }
00706 
00707 
00708 // is it uninstalled (after transaction) ?
00709 // if yes, uninstall requests are considered done
00710 
00711 bool
00712 ResolverContext::isAbsent (PoolItem_Ref item)
00713 {
00714     ResStatus status = getStatus(item);
00715 
00716     // DONT add incomplete here, uninstall requests for incompletes must be handled
00717 
00718     bool res = (status.staysUninstalled()
00719                 || status.isToBeUninstalled()
00720                 || status.isImpossible());
00721 
00722 _XDEBUG("ResolverContext::itemIsAbsent(<" << status << ">" << item << ") " << (res?"Y":"N"));
00723 
00724     return res;
00725 }
00726 
00727 
00728 //---------------------------------------------------------------------------
00729 // marked
00730 
00731 void
00732 ResolverContext::foreachMarked (MarkedPoolItemFn fn, void *data) const
00733 {
00734     ResolverContext_constPtr context = this;
00735     while (context) {
00736         for (Context::const_iterator iter = context->_context.begin(); iter != context->_context.end(); ++iter) {
00737             fn (iter->first, iter->second, data);
00738         }
00739         context = context->_parent;
00740     }
00741 }
00742 
00743 
00744 //---------------------------------------------------------------------------
00745 // collect
00746 
00747 typedef struct {
00748     PoolItemList *rl;
00749     int status;                         // <0: uninstalls, ==0: all, >0: installs
00750 } MarkedResolvableInfo;
00751 
00752 
00753 static void
00754 marked_item_collector (PoolItem_Ref item, const ResStatus & status, void *data)
00755 {
00756     MarkedResolvableInfo *info = (MarkedResolvableInfo *)data;
00757     if (info->status == 0
00758        || (info->status > 0 && status.isToBeInstalled())
00759        || (info->status < 0 && status.isToBeUninstalled()))
00760     {
00761         info->rl->push_back (item);
00762     }
00763 }
00764 
00765 
00766 PoolItemList
00767 ResolverContext::getMarked (int which) // <0: uninstalls, ==0: all, >0: installs
00768 {
00769     if ( _last_getMarked_which == which
00770          && _last_getMarked.size() > 0 )
00771         return _last_getMarked; // use the last run
00772 
00773     MarkedResolvableInfo info = { &_last_getMarked, which };
00774 
00775     foreachMarked (marked_item_collector, &info);
00776 
00777     _last_getMarked.sort(compare_items());
00778     _last_getMarked_which = which;
00779 
00780     return _last_getMarked;
00781 }
00782 
00783 //---------------------------------------------------------------------------
00784 // install
00785 
00786 typedef struct {
00787     ResPool pool;
00788     MarkedPoolItemFn fn;
00789     PoolItemList *rl;
00790     int count;
00791 } InstallInfo;
00792 
00793 static void
00794 install_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
00795 {
00796     InstallInfo *info = (InstallInfo *)data;
00797 
00798     Package::constPtr p = asKind<Package>(item.resolvable());
00799 
00800     if (status.isToBeInstalled()
00801         && !item.status().isInstalled()
00802         && ( !Helper::findInstalledItem( info->pool, item)) || ( p && p->installOnly()) )
00803     {
00804         if (info->fn) info->fn (item, status, info->rl);
00805         ++info->count;
00806     }
00807 }
00808 
00809 
00810 int
00811 ResolverContext::foreachInstall (MarkedPoolItemFn fn, void *data) const
00812 {
00813     PoolItemList *rl = (PoolItemList *)data;
00814     InstallInfo info = { _pool, fn, rl, 0 };
00815 
00816     foreachMarked (install_item_cb, (void *)&info);
00817 
00818     return info.count;
00819 }
00820 
00821 
00822 static void
00823 context_item_collector (PoolItem_Ref item, const ResStatus & status, void *data)
00824 {
00825     PoolItemList *rl = (PoolItemList *)data;
00826     if (status.isToBeInstalled()
00827         || status.isToBeUninstalled())
00828     {
00829         rl->push_front (item);
00830     }
00831 }
00832 
00833 
00834 PoolItemList
00835 ResolverContext::getInstalls (void) const
00836 {
00837     PoolItemList rl;
00838 
00839     foreachInstall (context_item_collector, (void *)&rl);
00840 
00841     return rl;
00842 }
00843 
00844 
00845 //---------------------------------------------------------------------------
00846 // satisfy
00847 
00848 typedef struct {
00849     ResPool pool;
00850     MarkedPoolItemFn fn;
00851     PoolItemList *rl;
00852     int count;
00853 } SatisfyInfo;
00854 
00855 static void
00856 satisfy_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
00857 {
00858     SatisfyInfo *info = (SatisfyInfo *)data;
00859     if (status.isSatisfied()
00860        && ! status.staysInstalled ()
00861        && !Helper::findInstalledItem (info->pool, item))
00862     {
00863        if (info->fn) info->fn (item, status, info->rl);
00864        ++info->count;
00865     }
00866 }
00867 
00868 
00869 int
00870 ResolverContext::foreachSatisfy (MarkedPoolItemFn fn, void *data) const
00871 {
00872     PoolItemList *rl = (PoolItemList *)data;
00873     SatisfyInfo info = { _pool, fn, rl, 0 };
00874 
00875     foreachMarked (satisfy_item_cb, (void *)&info);
00876 
00877     return info.count;
00878 }
00879 
00880 
00881 static void
00882 context_item_collector_satisfy (PoolItem_Ref item, const ResStatus & status, void *data)
00883 {
00884     PoolItemList *rl = (PoolItemList *)data;
00885     if (status.isSatisfied ())
00886     {
00887        rl->push_front (item);
00888     }
00889 }
00890 
00891 
00892 PoolItemList
00893 ResolverContext::getSatisfies (void) const
00894 {
00895     PoolItemList rl;
00896 
00897     foreachSatisfy (context_item_collector_satisfy, (void *)&rl);
00898 
00899     return rl;
00900 }
00901 
00902 
00903 //---------------------------------------------------------------------------
00904 // incomplete
00905 
00906 typedef struct {
00907     ResPool pool;
00908     MarkedPoolItemFn fn;
00909     PoolItemList *rl;
00910     int count;
00911 } IncompleteInfo;
00912 
00913 static void
00914 incomplete_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
00915 {
00916     IncompleteInfo *info = (IncompleteInfo *)data;
00917 
00918     if (status.isIncomplete ()) {
00919        if (info->fn) info->fn (item, status, info->rl);
00920        ++info->count;
00921     }
00922 }
00923 
00924 
00925 int
00926 ResolverContext::foreachIncomplete (MarkedPoolItemFn fn, void *data) const
00927 {
00928     PoolItemList *rl = (PoolItemList *)data;
00929     IncompleteInfo info = { _pool, fn, rl, 0 };
00930 
00931     foreachMarked (incomplete_item_cb, (void *)&info);
00932 
00933     return info.count;
00934 }
00935 
00936 
00937 static void
00938 context_item_collector_incomplete (PoolItem_Ref item, const ResStatus & status, void *data)
00939 {
00940     PoolItemList *rl = (PoolItemList *)data;
00941     if (status.isIncomplete ())
00942     {
00943        rl->push_front (item);
00944     }
00945 }
00946 
00947 
00948 PoolItemList
00949 ResolverContext::getIncompletes (void) const
00950 {
00951     PoolItemList rl;
00952 
00953     foreachIncomplete (context_item_collector_incomplete, (void *)&rl);
00954 
00955     return rl;
00956 }
00957 
00958 
00959 //---------------------------------------------------------------------------
00960 // upgrade
00961 
00962 typedef struct {
00963     ResPool pool;
00964     MarkedPoolItemPairFn fn;
00965     void *data;
00966     ResolverContext_Ptr context;
00967     int count;
00968 } UpgradeInfo;
00969 
00970 static void
00971 upgrade_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
00972 {
00973     UpgradeInfo *info = (UpgradeInfo *)data;
00974 
00975     PoolItem_Ref installed_item;
00976 
00977     if (status.isToBeInstalled()
00978         && ! item.status().isInstalled ())
00979     {
00980         // check if there is already an installed item with same name and kind
00981         installed_item = Helper::findInstalledItem( info->pool, item );
00982         if (installed_item) {
00983 
00984             // there is an installed item, check its status
00985             ResStatus installed_status( info->context->getStatus( installed_item ) );
00986 
00987             // if it does not transact, it does not get updated (we have an allowed parallel install)
00988             if (!installed_status.transacts())
00989                 return;
00990 
00991             if (info->fn) {
00992                 info->fn (item, status, installed_item, installed_status, info->data);
00993             }
00994             ++info->count;
00995         }
00996     }
00997 }
00998 
00999 
01000 int
01001 ResolverContext::foreachUpgrade (MarkedPoolItemPairFn fn, void *data)
01002 {
01003     UpgradeInfo info = { _pool, fn, data, this, 0 };
01004 
01005     foreachMarked (upgrade_item_cb, (void *)&info);
01006 
01007     return info.count;
01008 }
01009 
01010 
01011 static void
01012 pair_item_collector (PoolItem_Ref item, const ResStatus & status, PoolItem_Ref old_item, const ResStatus & old_status, void *data)
01013 {
01014     PoolItemList *rl = (PoolItemList *)data;
01015     rl->push_back (item);
01016 }
01017 
01018 
01019 PoolItemList
01020 ResolverContext::getUpgrades (void)
01021 {
01022     PoolItemList rl;
01023 
01024     foreachUpgrade (pair_item_collector, (void *)&rl);
01025 
01026     return rl;
01027 }
01028 
01029 
01030 //---------------------------------------------------------------------------
01031 // uninstall
01032 
01033 typedef std::map<std::string,PoolItem_Ref> UpgradeTable;
01034 
01035 typedef struct {
01036     MarkedPoolItemFn fn;
01037     PoolItemList *rl;
01038     UpgradeTable upgrade_hash;
01039     int count;
01040 } UninstallInfo;
01041 
01042 static void
01043 uninstall_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01044 {
01045     UninstallInfo *info = (UninstallInfo *)data;
01046 
01047     UpgradeTable::const_iterator pos = info->upgrade_hash.find(item->name());
01048 
01049     if (status.isToBeUninstalled ()
01050         && pos == info->upgrade_hash.end())             // dont count upgrades
01051     {
01052         if (info->fn)
01053             info->fn (item, status, info->rl);
01054         ++info->count;
01055     }
01056 }
01057 
01058 
01059 static void
01060 build_upgrade_hash_cb (PoolItem_Ref item_add, const ResStatus & add_status, PoolItem_Ref item_del, const ResStatus & del_status, void *data)
01061 {
01062     UpgradeTable *upgrade_hash = (UpgradeTable *)data;
01063     (*upgrade_hash)[item_del->name()] = item_del;
01064 }
01065 
01066 
01067 int
01068 ResolverContext::foreachUninstall (MarkedPoolItemFn fn, void *data)
01069 {
01070     UninstallInfo info;         // inits upgrade_hash
01071 
01072     info.fn = fn;
01073     info.rl = (PoolItemList *)data;
01074     info.count = 0;
01075 
01076     foreachUpgrade (build_upgrade_hash_cb, (void *)&(info.upgrade_hash));
01077     foreachMarked (uninstall_item_cb, (void *)&info);
01078 
01079     return info.count;
01080 }
01081 
01082 
01083 PoolItemList
01084 ResolverContext::getUninstalls (void)
01085 {
01086     PoolItemList rl;
01087 
01088     foreachUninstall (context_item_collector, (void *)&rl);
01089 
01090     return rl;
01091 }
01092 
01093 
01094 //---------------------------------------------------------------------------
01095 // impossible
01096 
01097 typedef struct {
01098     ResPool pool;
01099     MarkedPoolItemFn fn;
01100     int count;
01101     void *data;
01102 } ImpossibleInfo;
01103 
01104 static void
01105 impossible_item_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01106 {
01107     ImpossibleInfo *info = (ImpossibleInfo *)data;
01108 
01109     if (status.isImpossible ()) {
01110        if (info->fn) info->fn (item, status, info->data);
01111        ++info->count;
01112     }
01113 }
01114 
01115 
01116 int
01117 ResolverContext::foreachImpossible (MarkedPoolItemFn fn, void *data)
01118 {
01119     ImpossibleInfo info = { _pool, fn, 0, data };
01120 
01121     foreachMarked (impossible_item_cb, (void *)&info);
01122 
01123     return info.count;
01124 }
01125 
01126 
01127 //---------------------------------------------------------------------------
01128 
01129 static void
01130 install_count_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01131 {
01132     int *count = (int *)data;
01133     if (!item.status().isInstalled ()) {
01134         ++*count;
01135     }
01136 }
01137 
01138 int
01139 ResolverContext::installCount (void) const
01140 {
01141     int count = 0;
01142 
01143     foreachInstall (install_count_cb, (void *)&count);
01144 
01145     return count;
01146 }
01147 
01148 
01149 static void
01150 uninstall_count_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01151 {
01152     int *count = (int *)data;
01153     if (item.status().isInstalled ()) {
01154         ++*count;
01155     }
01156 }
01157 
01158 
01159 int
01160 ResolverContext::uninstallCount (void)
01161 {
01162     int count = 0;
01163 
01164     foreachUninstall (uninstall_count_cb, (void *)&count);
01165 
01166     return count;
01167 }
01168 
01169 
01170 int
01171 ResolverContext::upgradeCount (void)
01172 {
01173     return foreachUpgrade ((MarkedPoolItemPairFn)NULL, (void *)NULL);
01174 }
01175 
01176 
01177 static void
01178 satisfy_count_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01179 {
01180     int *count = (int *)data;
01181     if (!item.status().isInstalled ()) {
01182         ++*count;
01183     }
01184 }
01185 
01186 int
01187 ResolverContext::satisfyCount (void) const
01188 {
01189     int count = 0;
01190 
01191     foreachSatisfy (satisfy_count_cb, (void *)&count);
01192 
01193     return count;
01194 }
01195 
01196 
01197 int
01198 ResolverContext::incompleteCount (void) const
01199 {
01200     return foreachIncomplete ((MarkedPoolItemFn)NULL, (void *)NULL);
01201 }
01202 
01203 
01204 
01205 //---------------------------------------------------------------------------
01206 // info
01207 
01208 void
01209 ResolverContext::addInfo (ResolverInfo_Ptr info, bool askUser)
01210 {
01211     _XDEBUG( "ResolverContext[" << this << "]::addInfo(" << *info << ")" );
01212     _log.push_back (info);
01213 
01214     // _propagated_importance = false;
01215 
01216     if (info->error ()
01217         && !askUser) { // Go forward in order to evaluate more problems
01218 
01219         if (! _invalid) {
01220             ResolverInfo_Ptr info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_INVALID_SOLUTION, PoolItem_Ref(), RESOLVER_INFO_PRIORITY_VERBOSE);
01221             info->flagAsError ();
01222             _log.push_back (info);
01223         }
01224 
01225         _invalid = true;
01226     }
01227     if (askUser)
01228         _askUser = true;
01229 }
01230 
01231 
01232 void
01233 ResolverContext::addError (ResolverInfo_Ptr info, bool askUser)
01234 {
01235     bool is_error = true;
01236 
01237     if (info->type() == RESOLVER_INFO_TYPE_UNINSTALL_LOCKED) {
01238         for (PoolItemList::const_iterator iter = _ignoreInstalledItem.begin(); iter != _ignoreInstalledItem.end(); iter++) {
01239             if (info->affected() == *iter) {
01240                 DBG << "ignore keep installed: " << info->affected() << endl;
01241                 is_error = false;
01242                 break;
01243             }
01244         }
01245     }
01246 
01247     if (is_error)
01248         info->flagAsError ();
01249 
01250     WAR << "******** Error: " << *info << endl;
01251     addInfo (info, askUser);
01252 }
01253 
01254 
01255 //---------------------------------------------------------------------------
01256 // foreach info
01257 
01258 //  We call a item mentioned by an error info an "error-item".
01259 //  We call a item mentioned by an important info an "important-item".
01260 //
01261 //  The rules:
01262 //  (1) An info item that mentions an error-item is important.
01263 //  (2) An info item is about an important-item is important.
01264 
01265 static void
01266 mark_important_info (const ResolverInfoList & il)
01267 {
01268     // set of all items mentioned in the ResolverInfoList
01269     PoolItemSet error_set;
01270 
01271     bool did_something;
01272     int pass_num = 1;
01273 
01274     /* First of all, store all error-items in a set. */
01275 
01276     for (ResolverInfoList::const_iterator info_iter = il.begin(); info_iter != il.end(); ++info_iter) {
01277         ResolverInfo_Ptr info = (*info_iter);
01278         if (info != NULL                                                // list items might be NULL
01279             && info->error ())                                          // only look at error infos
01280         {
01281             PoolItem_Ref item = info->affected();               // get item from ResolverInfoList
01282             if (item) {
01283                 error_set.insert (item);
01284             }
01285 
01286             // the info might be a container, check it by doing a dynamic cast
01287 
01288             PoolItemList containerItems;
01289             ResolverInfoContainer_constPtr c = dynamic_pointer_cast<const ResolverInfoContainer>(*info_iter);
01290             if (c != NULL) containerItems = c->items();
01291 
01292             // containerItems is non-empty if info is really a ResolverInfoContainer
01293 
01294             for (PoolItemList::iterator res_iter = containerItems.begin(); res_iter != containerItems.end(); res_iter++) {
01295                 PoolItem_Ref item = (*res_iter);
01296                 if (item) {
01297                     error_set.insert (item);
01298                 }
01299             }
01300         }
01301     }
01302 
01303     // now collect all important ones
01304 
01305     PoolItemSet important_set;
01306 
01307     do {
01308         ++pass_num;
01309         assert (pass_num < 10000);
01310 
01311         did_something = false;
01312 
01313         for (ResolverInfoList::const_iterator info_iter = il.begin(); info_iter != il.end(); ++info_iter) {
01314 
01315             ResolverInfo_Ptr info = (*info_iter);
01316 
01317             if (info != NULL                                            // list items might be set to NULL
01318                 && !info->important ())                                 // only look at ones we didn't consider yet
01319             {
01320                 bool should_be_important = false;
01321 
01322                 for (PoolItemSet::const_iterator res_iter = error_set.begin(); res_iter != error_set.end() && ! should_be_important; ++res_iter) {
01323                     ResolverInfoContainer_constPtr c = dynamic_pointer_cast<const ResolverInfoContainer>(*info_iter);
01324                     if (c != NULL                                       // check if it really is a container
01325                         && c->mentions (*res_iter))
01326                     {
01327                         should_be_important = true;
01328                     }
01329                 }
01330 
01331                 for (PoolItemSet::const_iterator res_iter = important_set.begin(); res_iter != important_set.end() && ! should_be_important; ++res_iter) {
01332                     if (info->isAbout (*res_iter)) {
01333                         should_be_important = true;
01334                         break;
01335                     }
01336                 }
01337 
01338                 if (should_be_important) {
01339                     did_something = true;
01340                     info->flagAsImportant ();
01341                     PoolItemList items;
01342                     ResolverInfoContainer_constPtr c = dynamic_pointer_cast<const ResolverInfoContainer>(*info_iter);           // check if it really is a container
01343                     if (c != NULL) items = c->items();
01344                     for (PoolItemList::iterator res_iter = items.begin(); res_iter != items.end(); res_iter++) {
01345                         important_set.insert (*res_iter);
01346                     }
01347                 }
01348             }
01349         }
01350 
01351     } while (did_something);
01352 
01353 }
01354 
01355 void
01356 ResolverContext::foreachInfo (PoolItem_Ref item, int priority, ResolverInfoFn fn, void *data) const
01357 {
01358     ResolverInfoList info_list;
01359 
01360     ResolverContext_constPtr context = this;
01361      // Assemble a list of copies of all of the info objects
01362     while (context != NULL) {
01363 
01364         for (ResolverInfoList::const_iterator iter = context->_log.begin(); iter != context->_log.end(); ++iter) {
01365 
01366             ResolverInfo_Ptr info = *iter;
01367 
01368             if ((item == PoolItem_Ref()
01369                  || info->affected() == item)
01370                 && info->priority() >= priority)
01371             {
01372                 info_list.push_back( info );
01373             }
01374         }
01375         context = context->_parent;
01376     }
01377 #if 1
01378     // Merge info objects
01379     for (ResolverInfoList::iterator iter = info_list.begin(); iter != info_list.end(); ++iter) {
01380 
01381         ResolverInfo_Ptr info1 = (*iter);
01382         ResolverInfoList::iterator subiter = iter;
01383 
01384         if (info1 != NULL) {
01385             for (subiter++; subiter != info_list.end();) {
01386                 ResolverInfo_Ptr info2 = *subiter;
01387                 ResolverInfoList::iterator next = subiter; ++next;
01388                 if (info2 && info1->merge (info2)) {
01389                     info_list.erase( subiter );
01390                 }
01391                 subiter = next;
01392             }
01393         }
01394     }
01395 #endif
01396     mark_important_info( info_list );
01397 
01398     // Walk across the list of info objects and invoke our callback
01399 
01400     for (ResolverInfoList::iterator iter = info_list.begin(); iter != info_list.end(); ++iter) {
01401         if (*iter != NULL) {
01402             fn( *iter, data );
01403         }
01404     }
01405 }
01406 
01407 
01408 
01409 static void
01410 get_info_foreach_cb (ResolverInfo_Ptr info, void *data)
01411 {
01412     ResolverInfoList *il = (ResolverInfoList *)data;
01413 
01414     if (info->important ()) {
01415         il->push_back (info);
01416     }
01417 }
01418 
01419 
01420 
01421 ResolverInfoList
01422 ResolverContext::getInfo (void) const
01423 {
01424     ResolverInfoList il;
01425     foreachInfo (PoolItem_Ref(), -1, get_info_foreach_cb, (void *)&il);
01426     return il;
01427 }
01428 
01429 
01430 //---------------------------------------------------------------------------
01431 // spew
01432 
01433 static void
01434 spew_item_cb (PoolItem_Ref item, const ResStatus & status, void *unused)
01435 {
01436     MIL << "  " << item << " (" << status << ")" << endl;
01437 }
01438 
01439 
01440 void
01441 spew_item_pair_cb (PoolItem_Ref item1, const ResStatus & status1, PoolItem_Ref item2, const ResStatus & status2, void *unused)
01442 {
01443     MIL << "  " << item2 << " (" << status2 << ") => (" << item1 << " (" << status2 << ")" << endl;
01444 }
01445 
01446 
01447 void
01448 ResolverContext::spew (void)
01449 {
01450     MIL << "TO INSTALL:" << endl;
01451     foreachInstall (spew_item_cb, NULL);
01452     MIL << endl;
01453 
01454     MIL << "TO REMOVE:" << endl;
01455     foreachUninstall (spew_item_cb, NULL);
01456     MIL << endl;
01457 
01458     MIL << "TO UPGRADE:" << endl;
01459     foreachUpgrade (spew_item_pair_cb, NULL);
01460     MIL << endl;
01461 }
01462 
01463 
01464 static void
01465 spew_info_cb (ResolverInfo_Ptr info, void *unused)
01466 {
01467     if (info == NULL) return;
01468 
01469     if (info->error ()) MIL << "[ERROR] " << *info << endl;
01470     else if (info->important()) MIL << "[>>>>>] " << *info << endl;
01471     else MIL << *info << endl;
01472 }
01473 
01474 
01475 void
01476 ResolverContext::spewInfo (void) const
01477 {
01478     _XDEBUG( "ResolverContext[" << this << "]::spewInfo" );
01479     foreachInfo (PoolItem_Ref(), -1, spew_info_cb, NULL);
01480 }
01481 
01482 //---------------------------------------------------------------------------
01483 // requirements
01484 
01485 struct RequirementMet
01486 {
01487     ResolverContext_Ptr context;
01488     bool flag;
01489     bool unneeded;
01490     bool *installed;
01491 
01492     RequirementMet (ResolverContext_Ptr ctx, bool *inst)
01493         : context (ctx)
01494         , flag (false)
01495         , unneeded( false )
01496         , installed( inst )
01497     { }
01498 
01499 
01500     bool operator()( const CapAndItem & cai )
01501     {
01502         Capability match( cai.cap );
01503         PoolItem provider( cai.item );
01504         // capability is set for item set children. If it is set, query the
01505         //   exact version only.
01506         bool my_unneeded = false;
01507         if (context->isPresent( provider, &my_unneeded, installed ))
01508         {
01509             unneeded = my_unneeded;
01510             flag = true;
01511         }
01512 
01513 //      ERR << "RequirementMet(" <<  provider << ", " << match << ") [capability " <<
01514 //        capability << "] -> " <<  (flag ? "true" : "false") << endl;
01515         
01516         if ( installed // Checking as long as we have found an installed item
01517              && !*installed )
01518             return true;
01519         
01520         return ! flag;
01521     }
01522 };
01523 
01524 
01525 bool
01526 ResolverContext::requirementIsMet (const Capability & capability, bool *unneeded, bool *installed)
01527 {
01528     RequirementMet info (this, installed);
01529 
01530     //    world()->foreachProviding (capability, requirement_met_cb, (void *)&info);
01531 
01532     Dep dep( Dep::PROVIDES );
01533 
01534     // world->foreachProvidingResItem (capability, require_process_cb, &info);
01535 
01536     invokeOnEach( pool().byCapabilityIndexBegin( capability.index(), dep ),
01537                   pool().byCapabilityIndexEnd( capability.index(), dep ),
01538                   resfilter::ByCapMatch( capability ),
01539                   functor::functorRef<bool,CapAndItem>(info) );
01540 _XDEBUG( "ResolverContext::requirementIsMet(" << capability << ") " << (info.flag?"Y":"N") );
01541     if (unneeded) *unneeded = info.unneeded;
01542 
01543     return info.flag;
01544 }
01545 
01546 //---------------------------------------------------------------------------
01553 bool
01554 ResolverContext::requirementIsInstalledOrUnneeded (const ResObject::Kind & kind,
01555                                                    const Capability & capability)
01556 {
01557     bool fulfilled = false;
01558            
01559     if (kind != ResTraits<Package>::kind
01560         || kind != ResTraits<Script>::kind
01561         || kind != ResTraits<Message>::kind)
01562     {
01563        bool unneeded, installed;
01564        fulfilled = requirementIsMet (capability, &unneeded, &installed);
01565        if (!fulfilled
01566            || (!unneeded
01567                && !installed)) {
01568            fulfilled = false;
01569            _XDEBUG("Requirement is not unneeded and not installed.");
01570            // "low" level resolvables will be installed if they are not unneeded
01571            // Bug 192535/204913
01572        }
01573     }else {
01574        fulfilled = requirementIsMet (capability);
01575     }
01576 
01577     return fulfilled;
01578 }
01579 
01580 
01581 
01582 //---------------------------------------------------------------------------
01583 
01584 struct RequirementPossible
01585 {
01586     ResolverContext_Ptr context;
01587     bool flag;
01588 
01589     RequirementPossible( ResolverContext_Ptr ctx )
01590         : context (ctx)
01591         , flag (false)
01592     { }
01593 
01594     bool operator()( const CapAndItem & cai )
01595     {
01596         PoolItem provider( cai.item );
01597         ResStatus status = context->getStatus( provider );
01598         if (! (status.isToBeUninstalled () || status.isImpossible())
01599             || status.isToBeUninstalledDueToUnlink())
01600         {
01601             flag = true;
01602         }
01603 
01604         // Checking, if it has already been selected for removing by the user
01605         // Bug 155368; Testcase data.deptestomatic/yast-tests/bug155368-test.xml
01606         if (flag
01607             && !context->forceResolve()) {
01608             PoolItem installedItem = Helper::findInstalledByNameAndKind (context->pool(), provider->name(), provider->kind() );
01609             if (installedItem) {
01610                 ResStatus statusInstalled = context->getStatus (installedItem);
01611                 if (installedItem.status().isToBeUninstalled()
01612                     && installedItem.status().isByUser()){
01613                     DBG << provider << " would satify the requirement but it has been selected for removing by the user." << endl;
01614                     flag = false;
01615                 }
01616             }
01617         }
01618         
01619         return ! flag;
01620     }
01621 };
01622 
01623 
01624 bool
01625 ResolverContext::requirementIsPossible (const Capability & capability)
01626 {
01627     RequirementPossible info( this );
01628 
01629     // world()->foreachProviding (dep, requirement_possible_cb, (void *)&info);
01630 
01631     Dep dep( Dep::PROVIDES );
01632 
01633     invokeOnEach( pool().byCapabilityIndexBegin( capability.index(), dep ),
01634                   pool().byCapabilityIndexEnd( capability.index(), dep ),
01635                   resfilter::ByCapMatch( capability ),
01636                   functor::functorRef<bool,CapAndItem>(info) );
01637     _XDEBUG("requirementIsPossible( " << capability << ") = " << (info.flag ? "Y" : "N"));
01638     return info.flag;
01639 }
01640 
01641 
01642 bool
01643 ResolverContext::itemIsPossible (PoolItem_Ref item)
01644 {
01645     CapSet requires = item->dep (Dep::REQUIRES);
01646     for (CapSet::iterator iter = requires.begin(); iter !=  requires.end(); iter++) {
01647         if (! requirementIsPossible (*iter)) {
01648             return false;
01649         }
01650     }
01651 
01652     return true;
01653 }
01654 
01655 //---------------------------------------------------------------------------
01656 
01657 typedef struct {
01658     PoolItem_Ref other;
01659     bool flag;
01660     PoolItem_Ref foundItem;
01661 } DupNameCheckInfo;
01662 
01663 static void
01664 dup_name_check_cb (PoolItem_Ref item, const ResStatus & status, void *data)
01665 {
01666     DupNameCheckInfo *info = (DupNameCheckInfo *)data;
01667     if (! info->flag
01668         && status.isToBeInstalled ()
01669         && info->other->kind() == item->kind()
01670         && info->other->name() == item->name()
01671 #if 0
01672         && item->edition().compare(info->other->edition()) == 0
01673         && item->arch() == info->other->arch()
01674 #endif
01675         && item != info->other) // if it's exactly the same package, ignore it silently.
01676     {
01677         Package::constPtr p1 = asKind<Package>(item.resolvable());
01678         Package::constPtr p2 = asKind<Package>(info->other.resolvable());
01679         if (p1 && p2 && p1->installOnly() && p2->installOnly())         // both are parallel installable
01680             return;
01681 
01682         info->flag = true;
01683         info->foundItem = item;
01684     }
01685 }
01686 
01687 
01688 bool
01689 ResolverContext::isParallelInstall (PoolItem_Ref item) const
01690 {
01691     if (item->kind() == ResTraits<Atom>::kind) {
01692         return false;                                   // Atoms are paralell installable (#170098)
01693     }
01694 
01695     for (PoolItemList::const_iterator iter = _ignoreInstalledItem.begin();
01696          iter != _ignoreInstalledItem.end(); iter++) {
01697         if (item == *iter) {
01698             DBG << "ignore parallel install: " << item << endl;
01699             return false;
01700         }
01701     }
01702     
01703     DupNameCheckInfo info;
01704 
01705     info.other = item;
01706     info.flag = false;
01707     foreachMarked (dup_name_check_cb, (void *)&info);
01708     if (info.flag) {
01709         DBG << "isParallelInstall!!(" << item << ", " << info.foundItem << ")" << endl;
01710     }
01711     return info.flag;
01712 }
01713 
01714 
01715 PoolItem_Ref
01716 ResolverContext::getParallelInstall (PoolItem_Ref item) const
01717 {
01718     DupNameCheckInfo info;
01719 
01720     info.other = item;
01721     info.flag = false;
01722     foreachMarked( dup_name_check_cb, (void *)&info );
01723     return info.foundItem;
01724 }
01725 
01726 
01727 int
01728 ResolverContext::getSourcePriority (Source_Ref source) const
01729 {
01730     if (source.subscribed())
01731         return source.priority();
01732     return source.priorityUnsubscribed();
01733 }
01734 
01735 //---------------------------------------------------------------------------
01736 
01737 static int
01738 num_cmp (double a, double b)
01739 {
01740     return (b < a) - (a < b);
01741 }
01742 
01743 static int
01744 rev_num_cmp (double a, double b)
01745 {
01746     return (a < b) - (b < a);
01747 }
01748 
01749 static double
01750 churn_factor (ResolverContext_Ptr a)
01751 {
01752     return a->upgradeCount() + (2.0 * a->installCount ()) + (4.0 * a->uninstallCount ());
01753 }
01754 
01755 void
01756 ResolverContext::collectCompareInfo (int & cmpVersion,    // Version compare of ACCUMULATED items
01757                                      int & cmpSource,    // compare of Sources
01758                                      ResolverContext_Ptr compareContext)
01759 {
01760     Source_Ref userSource;         // Source Id of items which have been selected by the user for installation
01761                                    // It is empty, if there are different sources
01762     bool differentUserSources = false;
01763     Source_Ref userSourceCompare;  // Source Id of items which have been selected by the user for installation
01764                                    // It is empty, if there are different sources
01765     bool differentUserCompareSources = false;    
01766     SourceCounter thisMap;         // Map of to be installed sources with an item counter
01767     SourceCounter compareMap;      // Map of to be installed sources with an item counter
01768     
01769     PoolItemList installList = getMarked(1);
01770     PoolItemList compareList = compareContext->getMarked(1);; // List of comparing items which has to be installed
01771     PoolItemList::const_iterator itCompare = compareList.begin();
01772     _XDEBUG ("Starting comparing two solutions--------");
01773     for ( PoolItemList::const_iterator thisIt = installList.begin();
01774           thisIt != installList.end(); thisIt++ )
01775     {
01776         // evaluate, if the user selected packages (items) has the same source
01777         ResStatus status = getStatus (*thisIt);
01778         if (status.isByUser()
01779             || thisIt->status().isByUser())
01780         {
01781             if (userSource == Source_Ref::noSource
01782                 && !differentUserSources)
01783             {
01784                 userSource = thisIt->resolvable()->source();
01785             }
01786             else if (userSource != thisIt->resolvable()->source())
01787             {
01788                 differentUserSources = true; // there are other items of other sources which have been set by the user
01789             }
01790         }
01791 
01792         // collecting relationship between channels and installed items
01793         if (thisMap.find (thisIt->resolvable()->source()) == thisMap.end()) {
01794             thisMap[thisIt->resolvable()->source()] = 1;
01795         }
01796         else {
01797             thisMap[thisIt->resolvable()->source()] += 1;
01798         }
01799         _XDEBUG ("Count of left " << thisIt->resolvable()->source() << ": " << thisMap[thisIt->resolvable()->source()] << " : " << *(thisIt->resolvable()));    
01800 
01801         // Comparing versions
01802         while (itCompare != compareList.end() )
01803         {
01804             int cmp = compareByN ( thisIt->resolvable(), itCompare->resolvable());
01805             if ( cmp == 0) {
01806                 // comparing the version of both items and "adding" the result
01807                 // to accumulated compare result.
01808                 // Testcase: freshen-tests/exercise-7f-test
01809                 // Testcase: freshen-tests/exercise-7-test
01810                 cmpVersion += thisIt->resolvable()->edition().compare( itCompare->resolvable()->edition());
01811                 _XDEBUG ("Version: " << *(thisIt->resolvable()) << "[" << thisIt->resolvable()->source() << "]" << endl
01812                          << " <--> " << endl 
01813                          << "Version: " << *(itCompare->resolvable()) << "[" << itCompare->resolvable()->source() << "]"
01814                          << " --> cmpVersion : " << cmpVersion);                
01815 
01816                 // evaluate if the user selected packages (items) has the same source
01817                 ResObject::constPtr sourceItem = itCompare->resolvable();
01818                 ResStatus compStatus = compareContext->getStatus(*itCompare);
01819                 if (compStatus.isByUser()
01820                     || itCompare->status().isByUser())
01821                 {
01822                     if (userSourceCompare == Source_Ref::noSource
01823                         && !differentUserCompareSources)
01824                         userSourceCompare = sourceItem->source();
01825                     else if (userSourceCompare != sourceItem->source())
01826                         differentUserCompareSources = true; // there are other items of other sources which have been set by the user
01827                 }
01828                 // collecting relationship between channels and installed items
01829                 if (compareMap.find (sourceItem->source()) == compareMap.end()) 
01830                     compareMap[sourceItem->source()] = 1;
01831                 else
01832                     compareMap[sourceItem->source()] += 1;
01833                 _XDEBUG ("Count of right " << sourceItem->source() << ": " << compareMap[sourceItem->source()] << " : " << *(itCompare->resolvable()));
01834                 itCompare++;
01835             } else if (cmp > 0 )
01836                 itCompare++;
01837             else break;
01838         }
01839     }
01840 
01841     // comparing the rest of the other install list
01842     while (itCompare != compareList.end() )
01843     {
01844         // evaluate if the user selected packages (items) has the same source
01845         ResObject::constPtr sourceItem = itCompare->resolvable();
01846         ResStatus compStatus = compareContext->getStatus(*itCompare);
01847         if (compStatus.isByUser()
01848             || itCompare->status().isByUser()) 
01849         {
01850             if (userSourceCompare == Source_Ref::noSource
01851                 && !differentUserCompareSources)
01852                     userSourceCompare = sourceItem->source();           
01853             else if (userSourceCompare != sourceItem->source())
01854                 differentUserCompareSources = true; // there are other items of other sources which have been set by the user           
01855         }
01856 
01857         // collecting relationship between channels and installed items
01858         if (compareMap.find (sourceItem->source()) == compareMap.end()) 
01859             compareMap[sourceItem->source()] = 1;
01860         else
01861             compareMap[sourceItem->source()] += 1;
01862         _XDEBUG ("Count of right" << sourceItem->source() << ": " << compareMap[sourceItem->source()] << " : "
01863                  << *(itCompare->resolvable()));        
01864         itCompare++;    
01865     }
01866 
01867     // evaluate cmpSource
01868     cmpSource = 0;
01869     int cmpCompare = 0;
01870 
01871     if (!differentUserSources)
01872     {
01873         // user selected items which has to be installed has only one channel;
01874         // cmpSource = number of items of that channel
01875         cmpSource = thisMap[userSource];
01876     }
01877         
01878     if (!differentUserCompareSources) {
01879         // user selected items which has to be installed has only one channel;  
01880         // cmpCompare = number of items of that channel
01881         cmpCompare = compareMap[userSourceCompare];
01882     }
01883     _XDEBUG ("cmpSource = " << cmpSource << " ; cmpCompare = " << cmpCompare << " ; sizeof compareMap:" <<  compareMap.size());
01884     if (compareMap.size() == 1
01885         && thisMap.size() == 1
01886         && userSource == userSourceCompare) {
01887         // We have only one source from which all items will be instaled.
01888         // So we will regards the complete amount of installed/updated packages
01889         // Testcase basic-exercises/exercise-14-test
01890         cmpSource = 0;
01891     } else {
01892         // The solutions has different channels with user selected items.
01893         // Take the solution with the greater account of items in this channel
01894         // Testcase basic-exercises/exercise-solution-order-test
01895         cmpSource = cmpSource - cmpCompare;         
01896     }
01897 
01898     if (cmpSource == 0)
01899     {
01900         // less amount of channels are better
01901         cmpSource = compareMap.size() - thisMap.size();
01902     }
01903     _XDEBUG ("End comparing two solutions-------- Version compare: " << cmpVersion << " Source compare: "<< cmpSource);    
01904 }
01905 
01906 int
01907 ResolverContext::partialCompare (ResolverContext_Ptr context)
01908 {
01909     int cmp = 0;
01910     if (this != context) {
01911 
01912         // collecting all data for comparing both resultion results
01913         int  cmpVersion = 0; // Version compare of ACCUMULATED items
01914         int  cmpSource = 0;  // compare of Sources
01915 
01916         collectCompareInfo (cmpVersion, cmpSource, context);
01917         if (_preferHighestVersion) {
01918             // comparing versions
01919             cmp = cmpVersion;
01920             DBG << "Comparing versions returned :" << cmp << endl;
01921             if (cmp == 0) { 
01922                 // High numbers are good... we don't want solutions containing low-priority channels.
01923                 // Source priority which has been set externally
01924                 cmp = num_cmp (_min_priority, context->_min_priority);
01925                 DBG << "Comparing priority returned :" << cmp << endl;
01926                 if (cmp == 0) {
01927                     // High numbers are bad.  Less churn is better.
01928                     cmp = rev_num_cmp (churn_factor (this), churn_factor (context));
01929                     DBG << "Comparing churn_factor returned :" << cmp << endl;
01930                     if (cmp == 0) {             
01931                         // Comparing sources regarding the items which has to be installed
01932                         cmp = cmpSource;
01933                         DBG << "Comparing sources returned :" << cmp << endl;           
01934                         if (cmp == 0) {
01935                             // High numbers are bad.  Bigger #s means more penalties.
01936                             cmp = rev_num_cmp (_other_penalties, context->_other_penalties);
01937                             DBG << "Comparing other penalties returned :" << cmp << endl;                       
01938                         }
01939                     }
01940                 }
01941             }
01942         } else {
01943             // less transaction will be prefered
01944             // High numbers are bad.  Less churn is better.
01945             cmp = rev_num_cmp (churn_factor (this), churn_factor (context));
01946             DBG << "Comparing churn_factor returned :" << cmp << endl;      
01947             if (cmp == 0) { 
01948                 // High numbers are good... we don't want solutions containing low-priority channels.
01949                 // Source priority which has been set externally
01950                 cmp = num_cmp (_min_priority, context->_min_priority);
01951                 DBG << "Comparing priority returned :" << cmp << endl;
01952                 if (cmp == 0) {
01953                     cmp = cmpVersion;
01954                     DBG << "Comparing versions returned :" << cmp << endl;
01955                     if (cmp == 0) {             
01956                         // Comparing sources regarding the items which has to be installed
01957                         cmp = cmpSource;
01958                         DBG << "Comparing sources returned :" << cmp << endl;           
01959                         if (cmp == 0) {
01960                             // High numbers are bad.  Bigger #s means more penalties.
01961                             cmp = rev_num_cmp (_other_penalties, context->_other_penalties);
01962                             DBG << "Comparing other penalties returned :" << cmp << endl;                       
01963                         }
01964                     }
01965                 }
01966             }       
01967         }
01968     }
01969 
01970     return cmp;
01971 }
01972 
01973 int
01974 ResolverContext::compare (ResolverContext_Ptr context)
01975 {
01976     int cmp;
01977     
01978     if (this == context)
01979         return 0;
01980     
01981     cmp = partialCompare (context);
01982     if (cmp)
01983         return cmp;
01984     
01985     /* High numbers are bad.  Smaller downloads are best. */
01986     cmp = rev_num_cmp (_download_size, context->_download_size);
01987     if (cmp)
01988         return cmp;
01989     
01990     /* High numbers are bad.  Less disk space consumed is good. */
01991     cmp = rev_num_cmp (_install_size, context->_install_size);
01992     if (cmp)
01993         return cmp;
01994     
01995     return 0;
01996 }
01997 
01999     };// namespace detail
02002   };// namespace solver
02005 };// namespace zypp
02007 

Generated on Thu Apr 24 02:24:53 2008 for zypp by  doxygen 1.4.6