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

Generated on Mon Jun 5 19:10:35 2006 for zypp by  doxygen 1.4.6