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