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

Generated on Tue Nov 28 16:49:31 2006 for zypp by  doxygen 1.5.0