00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "zypp/CapFactory.h"
00023 #include "zypp/CapSet.h"
00024 #include "zypp/Package.h"
00025 #include "zypp/base/Logger.h"
00026 #include "zypp/base/String.h"
00027 #include "zypp/base/Gettext.h"
00028
00029 #include "zypp/base/Algorithm.h"
00030 #include "zypp/ResPool.h"
00031 #include "zypp/ResFilters.h"
00032 #include "zypp/CapFilters.h"
00033 #include "zypp/CapMatchHelper.h"
00034
00035 #include "zypp/solver/detail/QueueItemInstall.h"
00036 #include "zypp/solver/detail/QueueItemEstablish.h"
00037 #include "zypp/solver/detail/QueueItemUninstall.h"
00038 #include "zypp/solver/detail/QueueItemRequire.h"
00039 #include "zypp/solver/detail/QueueItemConflict.h"
00040 #include "zypp/solver/detail/QueueItem.h"
00041 #include "zypp/solver/detail/ResolverContext.h"
00042 #include "zypp/solver/detail/ResolverInfoConflictsWith.h"
00043 #include "zypp/solver/detail/ResolverInfoMisc.h"
00044 #include "zypp/solver/detail/ResolverInfoNeededBy.h"
00045 #include "zypp/solver/detail/Helper.h"
00046
00048 namespace zypp
00049 {
00050
00051 namespace solver
00052 {
00053
00054 namespace detail
00055 {
00056
00057 using namespace std;
00058
00059 IMPL_PTR_TYPE(QueueItemInstall);
00060
00061
00062
00063 std::ostream &
00064 QueueItemInstall::dumpOn( std::ostream & os ) const
00065 {
00066 os << "[" << (_soft?"Soft":"") << "Install: ";
00067 os << _item;
00068 if (_upgrades) {
00069 os << ", Upgrades ";
00070 os << _upgrades;
00071 }
00072 if (_dep_satisfied_by_this_install != Capability::noCap) {
00073 os << ", Satisfies [" << _dep_satisfied_by_this_install << "]";
00074 }
00075 if (_needed_by) {
00076 os << ", Needed by " << _needed_by;
00077 }
00078 if (_explicitly_requested) os << ", Explicit !";
00079 os << "]";
00080 return os;
00081 }
00082
00083
00084
00085 QueueItemInstall::QueueItemInstall (const ResPool & pool, PoolItem_Ref item, bool soft)
00086 : QueueItem (QUEUE_ITEM_TYPE_INSTALL, pool)
00087 , _item (item)
00088 , _soft (soft)
00089 , _dep_satisfied_by_this_install (Capability::noCap)
00090 , _needed_by (PoolItem_Ref())
00091 , _channel_priority (0)
00092 , _other_penalty (0)
00093 , _explicitly_requested (false)
00094 {
00095 Resolvable::constPtr res = item.resolvable();
00096
00097
00098 bool install_in_parallel = isKind<Atom>( res );
00099
00100
00101 if (!install_in_parallel) {
00102 Package::constPtr pkg = asKind<Package>( res );
00103 install_in_parallel = (pkg != NULL) && pkg->installOnly();
00104 }
00105
00106
00107
00108
00109 if (!install_in_parallel) {
00110 _upgrades = Helper::findInstalledItem (pool, item);
00111 }
00112
00113 _XDEBUG("QueueItemInstall::QueueItemInstall(" << item << (soft?", soft":"") << ") upgrades " << _upgrades);
00114 }
00115
00116
00117 QueueItemInstall::~QueueItemInstall()
00118 {
00119 }
00120
00121
00122
00123 bool
00124 QueueItemInstall::isSatisfied (ResolverContext_Ptr context) const
00125 {
00126 return context->isPresent (_item);
00127 }
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 typedef map<string, PoolItem_Ref> EstablishMap;
00138
00139 struct InstallEstablishItem
00140 {
00141 EstablishMap establishmap;
00142
00143 InstallEstablishItem ()
00144 { }
00145
00146
00147
00148
00149
00150 bool operator()( const CapAndItem & cai )
00151 {
00152 _XDEBUG("QueueItemInstall::InstallEstablishItem (" << cai.item << ", " << cai.cap << ")");
00153
00154
00155
00156 PoolItem_Ref item( cai.item );
00157
00158 EstablishMap::iterator it = establishmap.find( item->name() );
00159
00160 if (it != establishmap.end()) {
00161 int cmp = it->second->arch().compare( item->arch() );
00162 if (cmp < 0) {
00163 it->second = item;
00164 }
00165 else if (cmp == 0) {
00166 if (it->second->edition().compare( item->edition() ) < 0) {
00167 it->second = item;
00168 }
00169 }
00170 }
00171 else {
00172 establishmap[item->name()] = item;
00173 }
00174 return true;
00175 }
00176 };
00177
00178
00179
00180
00181
00182
00183
00184 struct UninstallConflicting
00185 {
00186 ResolverContext_Ptr _context;
00187 const Capability _provided_cap;
00188 PoolItem _install_item;
00189 PoolItem _upgrade_item;
00190 QueueItemList & _qil;
00191 bool ignored;
00192
00193 UninstallConflicting( ResolverContext_Ptr ctx, const Capability & provided_cap, PoolItem install_item, PoolItem upgrade_item, QueueItemList & qil )
00194 : _context( ctx )
00195 , _provided_cap( provided_cap )
00196 , _install_item( install_item )
00197 , _upgrade_item( upgrade_item )
00198 , _qil( qil )
00199 , ignored( false )
00200 { }
00201
00202
00203
00204
00205 bool operator()( const CapAndItem & cai)
00206 {
00207 PoolItem_Ref conflicting_item = cai.item;
00208
00209 _XDEBUG("UninstallConflicting(" << conflicting_item << ", cap " << cai.cap << ")");
00210
00211 if (conflicting_item == _install_item) {
00212 WAR << "Ignoring self-conflicts" << endl;
00213 return true;
00214 }
00215 if (conflicting_item == _upgrade_item) {
00216 _XDEBUG("We're upgrading the conflicting item");
00217 return true;
00218 }
00219
00220 const Capability conflicting_cap = cai.cap;
00221 ResolverInfo_Ptr log_info;
00222 QueueItemUninstall_Ptr uninstall_item;
00223
00224 IgnoreMap ignoreMap = _context->getIgnoreConflicts();
00225
00226 for (IgnoreMap::iterator it = ignoreMap.begin(); it != ignoreMap.end(); it++) {
00227 if (it->first == conflicting_item
00228 && it->second == conflicting_cap)
00229 {
00230 _XDEBUG("Found ignoring conflicts " << conflicting_cap << " for " << conflicting_item);
00231 ignored = true;
00232 return false;
00233 } else {
00234 _XDEBUG("Ignoring conflict " << it->second << " for " << it->first << " does not fit");
00235 }
00236 }
00237
00238
00239
00240
00241
00242
00243
00244 if (compareByNVR (conflicting_item.resolvable(), _install_item.resolvable()) == 0) {
00245 return true;
00246 }
00247
00248 #warning Make behaviour configurable
00249
00250
00251
00252
00253 ResStatus confl_status = _context->getStatus( conflicting_item );
00254 if (confl_status.isToBeInstalled()
00255 || confl_status.staysInstalled())
00256 {
00257 ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CONFLICT_CANT_INSTALL,
00258 _install_item, RESOLVER_INFO_PRIORITY_VERBOSE, _provided_cap);
00259 misc_info->setOtherPoolItem (conflicting_item);
00260 misc_info->setOtherCapability (conflicting_cap);
00261 _context->addInfo (misc_info);
00262 }
00263
00264 _XDEBUG("because: '" << conflicting_item << "'conflicts " << conflicting_cap);
00265
00266 QueueItemUninstall_Ptr uninstall_qitem = new QueueItemUninstall (_context->pool(), conflicting_item, QueueItemUninstall::CONFLICT);
00267 uninstall_qitem->setDueToConflict ();
00268 uninstall_qitem->setPriority(0);
00269
00270 log_info = new ResolverInfoConflictsWith (conflicting_item, _install_item,
00271 conflicting_cap);
00272 uninstall_qitem->addInfo (log_info);
00273 _qil.push_front (uninstall_qitem);
00274
00275 return true;
00276 }
00277 };
00278
00279
00280
00281 bool
00282 QueueItemInstall::process (const QueueItemList & mainQueue, ResolverContext_Ptr context, QueueItemList & qil)
00283 {
00284 ResStatus status = context->getStatus(_item);
00285
00286 _XDEBUG( "QueueItemInstall::process(" << *this << "):" << status);
00287
00288
00289
00290 if (_needed_by) {
00291
00292 ResStatus neededStatus = context->getStatus(_needed_by);
00293 if (neededStatus.isToBeUninstalled()) {
00294 _XDEBUG( _needed_by << " will be uninstalled. So the requirement is not needed anymore");
00295 return true;
00296 }
00297
00298 ResolverInfoNeededBy_Ptr info;
00299
00300 info = new ResolverInfoNeededBy (_item);
00301 info->addRelatedPoolItem (_needed_by);
00302 info->setCapability (_dep_satisfied_by_this_install, _soft?Dep::RECOMMENDS:Dep::REQUIRES);
00303 info->setInitialInstallation (true);
00304 context->addInfo (info);
00305 }
00306
00307
00308
00309
00310
00311 if (_upgrades
00312 && compareByNVRA(_item.resolvable(), _upgrades.resolvable()) == 0)
00313 {
00314 if (_item->kind() == ResTraits<Package>::kind) {
00315 ResolverInfo_Ptr info;
00316 _DEBUG("install of " << _item << " upgrades itself, skipping");
00317
00318 info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_SKIPPING, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00319 context->addInfo (info);
00320 goto finished;
00321 }
00322 else {
00323 _DEBUG("re-install " << _item);
00324 }
00325 }
00326
00327
00328
00329
00330 if (_needed_by) {
00331 _XDEBUG( "still needed ");
00332
00333 ResStatus status = _needed_by.status();
00334 _XDEBUG("by: [status: " << status << "] " << _needed_by);
00335 if ( status.isToBeUninstalled()
00336 || status.isImpossible())
00337 {
00338 goto finished;
00339 }
00340 }
00341
00342
00343
00344
00345
00346 if (context->verifying()
00347 && (status.isToBeUninstalled() || status.isImpossible())
00348 && _needed_by) {
00349
00350 QueueItemUninstall_Ptr uninstall_item;
00351 uninstall_item = new QueueItemUninstall (pool(), _needed_by, QueueItemUninstall::BACKOUT);
00352 qil.push_front (uninstall_item);
00353
00354 goto finished;
00355 }
00356
00357
00358
00359 if (status.isNeeded()) {
00360 context->setStatus (_item, _soft ? ResStatus::toBeInstalledSoft : ResStatus::toBeInstalled);
00361 }
00362
00363
00364
00365
00366
00367 if (!_upgrades) {
00368
00369 _XDEBUG("trying simple install of " << _item);
00370 if (!context->install (_item, context->verifying() || _soft, _other_penalty))
00371 goto finished;
00372
00373 }
00374 else {
00375
00376 QueueItemUninstall_Ptr uninstall_item;
00377
00378 _XDEBUG("trying upgrade install of " << _item);
00379
00380 if (!context->upgrade (_item, _upgrades, context->verifying() || _soft, _other_penalty)) {
00381
00382 ResolverInfo_Ptr info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_INVALID_SOLUTION, PoolItem_Ref(), RESOLVER_INFO_PRIORITY_VERBOSE);
00383 context->addError (info);
00384 goto finished;
00385 }
00386
00387
00388
00389 uninstall_item = new QueueItemUninstall (pool(), _upgrades, QueueItemUninstall::UPGRADE );
00390 uninstall_item->setUpgradedTo (_item);
00391
00392 if (_explicitly_requested)
00393 uninstall_item->setExplicitlyRequested ();
00394
00395 qil.push_front (uninstall_item);
00396
00397 }
00398
00399
00400
00401
00402 if (! (status.staysUninstalled()
00403 || status.isToBeUninstalledDueToUnlink()
00404 || status.isIncomplete()
00405 || status.isSatisfied()))
00406 {
00407 _XDEBUG("status " << status << " -> finished");
00408 goto finished;
00409 }
00410
00411 _XDEBUG("status " << status << " -> NOT finished");
00412 {
00413
00414 ResolverInfoMisc_Ptr misc_info;
00415
00416 if (_upgrades) {
00417
00418 misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UPDATING, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00419 misc_info->setOtherPoolItem (_upgrades);
00420
00421 } else {
00422
00423 misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_INSTALLING, _item, RESOLVER_INFO_PRIORITY_VERBOSE);
00424
00425 }
00426
00427 context->addInfo (misc_info);
00428 logInfo (context);
00429
00430
00431
00432 CapSet caps;
00433
00434 caps = _item->dep (Dep::REQUIRES);
00435
00436 for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00437
00438 const Capability cap = *iter;
00439 _XDEBUG("this requires " << cap);
00440 bool fulfilled = false;
00441
00442 fulfilled = context->requirementIsInstalledOrUnneeded (cap, _item, Dep::REQUIRES);
00443
00444 if (!fulfilled) {
00445 _XDEBUG("this requirement is still unfulfilled");
00446 QueueItemRequire_Ptr req_item = new QueueItemRequire (pool(), cap );
00447 req_item->addPoolItem (_item);
00448 qil.push_front (req_item);
00449 }
00450 }
00451
00452 caps = _item->dep (Dep::RECOMMENDS);
00453
00454 for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00455
00456 const Capability cap = *iter;
00457 _XDEBUG("this recommends " << cap);
00458
00459 if (!context->requirementIsMet (cap, _item, Dep::RECOMMENDS)) {
00460 _XDEBUG("this recommends is still unfulfilled");
00461 QueueItemRequire_Ptr req_item = new QueueItemRequire (pool(), cap, true);
00462 req_item->addPoolItem (_item);
00463 qil.push_front (req_item);
00464 }
00465
00466 }
00467
00468
00469
00470 caps = _item->dep (Dep::CONFLICTS);
00471 for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00472 const Capability cap = *iter;
00473 _XDEBUG("this conflicts with '" << cap << "'");
00474 QueueItemConflict_Ptr conflict_item = new QueueItemConflict (pool(), cap, _item );
00475
00476
00477 qil.push_back (conflict_item);
00478 }
00479
00480
00481
00482 caps = _item->dep (Dep::OBSOLETES);
00483 IgnoreMap ignoreMap = context->getIgnoreObsoletes();
00484
00485 for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00486 const Capability cap = *iter;
00487 bool found = false;
00488 for (IgnoreMap::iterator it = ignoreMap.begin();
00489 it != ignoreMap.end(); it++) {
00490 if (it->first == _item
00491 && it->second == cap) {
00492 _XDEBUG("Found ignoring obsoletes " << cap << " for " << _item);
00493 found = true;
00494 break;
00495 }
00496 }
00497 if (!found) {
00498 _XDEBUG("this obsoletes " << cap);
00499 QueueItemConflict_Ptr conflict_item = new QueueItemConflict (pool(), cap, _item );
00500 conflict_item->setActuallyAnObsolete();
00501
00502
00503
00504 qil.push_front (conflict_item);
00505 }
00506 }
00507
00508
00509
00510
00511
00512
00513 InstallEstablishItem establish;
00514
00515 caps = _item->dep (Dep::PROVIDES);
00516 bool ignored = false;
00517
00518 for (CapSet::const_iterator iter = caps.begin(); iter != caps.end(); iter++) {
00519 const Capability cap = *iter;
00520
00521
00522
00523
00524 _XDEBUG("Re-establish all freshens on " << cap);
00525
00526
00527 Dep dep( Dep::FRESHENS);
00528 invokeOnEach( pool().byCapabilityIndexBegin( cap.index(), dep ),
00529 pool().byCapabilityIndexEnd( cap.index(), dep ),
00530 resfilter::ByCapMatch( cap ),
00531 functor::functorRef<bool,CapAndItem>( establish ) );
00532
00533 dep = Dep::SUPPLEMENTS;
00534 invokeOnEach( pool().byCapabilityIndexBegin( cap.index(), dep ),
00535 pool().byCapabilityIndexEnd( cap.index(), dep ),
00536 resfilter::ByCapMatch( cap ),
00537 functor::functorRef<bool,CapAndItem>( establish ) );
00538
00539 if (!ignored) {
00540
00541
00542 UninstallConflicting info( context, cap, _item, _upgrades, qil );
00543
00544 Dep dep( Dep::CONFLICTS );
00545 invokeOnEach( pool().byCapabilityIndexBegin( cap.index(), dep ),
00546 pool().byCapabilityIndexEnd( cap.index(), dep ),
00547 resfilter::ByCapMatch( cap ),
00548 functor::functorRef<bool,CapAndItem>( info ) );
00549
00550 ignored = info.ignored;
00551 }
00552
00553 }
00554
00555
00556
00557 for (EstablishMap::iterator firstIt = establish.establishmap.begin(); firstIt != establish.establishmap.end(); ++firstIt) {
00558 bool conflictFound = false;
00559 CapSet provides = firstIt->second.resolvable()->deps()[Dep::PROVIDES];
00560
00561
00562 for (EstablishMap::iterator secondIt = firstIt; secondIt != establish.establishmap.end() && !conflictFound; ++secondIt) {
00563 CapSet conflicts = secondIt->second.resolvable()->deps()[Dep::CONFLICTS];
00564 if (hasMatches (provides,conflicts)) {
00565 conflictFound = true;
00566 _XDEBUG("Do not establish " << firstIt->second << " cause it is conflicting with " << secondIt->second );
00567 }
00568 }
00569
00570 if (!conflictFound) {
00571 QueueItemEstablish_Ptr establish_item = new QueueItemEstablish (pool(), firstIt->second, true);
00572 qil.push_front( establish_item );
00573 }
00574 }
00575
00576 }
00577
00578 finished:
00579
00580 return true;
00581 }
00582
00583
00584 QueueItem_Ptr
00585 QueueItemInstall::copy (void) const
00586 {
00587 QueueItemInstall_Ptr new_install = new QueueItemInstall (pool(), _item);
00588 new_install->QueueItem::copy(this);
00589
00590 new_install->_upgrades = _upgrades;
00591 new_install->_dep_satisfied_by_this_install = _dep_satisfied_by_this_install;
00592 new_install->_needed_by = _needed_by;
00593 new_install->_channel_priority = _channel_priority;
00594 new_install->_other_penalty = _other_penalty;
00595 new_install->_explicitly_requested = _explicitly_requested;
00596
00597 return new_install;
00598 }
00599
00600
00601 int
00602 QueueItemInstall::cmp (QueueItem_constPtr item) const
00603 {
00604 int cmp = this->compare (item);
00605 if (cmp != 0)
00606 return cmp;
00607 QueueItemInstall_constPtr install = dynamic_pointer_cast<const QueueItemInstall>(item);
00608 return compareByNVRA (_item.resolvable(), install->_item.resolvable());
00609 }
00610
00611
00613 };
00616 };
00619 };
00621