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

Generated on Wed Sep 27 01:16:40 2006 for zypp by  doxygen 1.4.6