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

Generated on Mon Jul 17 21:27:34 2006 for zypp by  doxygen 1.4.6