1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/TargetImpl.cc
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/Exception.h"
19 #include "zypp/base/Gettext.h"
20 #include "zypp/PoolItem.h"
21 #include "zypp/Resolvable.h"
22 #include "zypp/ResObject.h"
23 #include "zypp/Package.h"
25 #include "zypp/target/TargetImpl.h"
26 #include "zypp/target/TargetCallbackReceiver.h"
28 #include "zypp/solver/detail/InstallOrder.h"
31 using zypp::solver::detail::InstallOrder;
33 ///////////////////////////////////////////////////////////////////
35 { /////////////////////////////////////////////////////////////////
36 ///////////////////////////////////////////////////////////////////
38 { /////////////////////////////////////////////////////////////////
40 IMPL_PTR_TYPE(TargetImpl);
42 TargetImpl_Ptr TargetImpl::_nullimpl;
44 /** Null implementation */
45 TargetImpl_Ptr TargetImpl::nullimpl()
48 _nullimpl = new TargetImpl;
53 ///////////////////////////////////////////////////////////////////
55 // METHOD NAME : TargetImpl::TargetImpl
58 TargetImpl::TargetImpl(const Pathname & root_r)
61 _rpm.initDatabase(_root);
62 _storage_enabled = false;
63 MIL << "Initialized target on " << _root << endl;
66 ///////////////////////////////////////////////////////////////////
68 // METHOD NAME : TargetImpl::~TargetImpl
71 TargetImpl::~TargetImpl()
74 MIL << "Targets closed" << endl;
77 bool TargetImpl::isStorageEnabled() const
79 return _storage_enabled;
83 void TargetImpl::enableStorage(const Pathname &root_r)
85 _storage.init(root_r);
86 _storage_enabled = true;
89 Pathname TargetImpl::root() const
94 const ResStore & TargetImpl::resolvables()
98 std::list<Package::Ptr> packages = _rpm.getPackages();
99 for (std::list<Package::Ptr>::const_iterator it = packages.begin();
100 it != packages.end();
106 if ( isStorageEnabled() )
108 // resolvables stored in the zypp storage database
109 std::list<ResObject::Ptr> resolvables = _storage.storedObjects();
110 for (std::list<ResObject::Ptr>::iterator it = resolvables.begin();
111 it != resolvables.end();
119 WAR << "storage target not enabled" << std::endl;
126 Pathname TargetImpl::getRpmFile(Package::constPtr package)
128 callback::SendReport<source::DownloadResolvableReport> report;
130 #warning FIXME: error handling
132 report->start( package, Url() );
134 Pathname file = package->getPlainRpm();
136 report->finish( package, source::DownloadResolvableReport::NO_ERROR, "" );
142 int TargetImpl::commit(ResPool pool_r, unsigned int medianr, TargetImpl::PoolItemList & errors_r, TargetImpl::PoolItemList & remaining_r, TargetImpl::PoolItemList & srcremaining_r)
144 MIL << "TargetImpl::commit(<pool>, " << medianr << ")" << endl;
148 srcremaining_r.clear();
150 TargetImpl::PoolItemList to_uninstall;
151 TargetImpl::PoolItemList to_install;
152 TargetImpl::PoolItemList to_srcinstall;
153 getResolvablesToInsDel( pool_r, to_uninstall, to_install, to_srcinstall );
156 MIL << "Restrict to media number " << medianr << endl;
159 commit (to_uninstall);
161 if (medianr == 0) { // commit all
162 remaining_r = commit( to_install );
163 srcremaining_r = commit( to_srcinstall );
167 TargetImpl::PoolItemList current_install;
168 TargetImpl::PoolItemList current_srcinstall;
170 for (TargetImpl::PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it)
172 Resolvable::constPtr res( it->resolvable() );
173 Package::constPtr pkg( asKind<Package>(res) );
174 if (pkg && medianr != pkg->mediaId()) // check medianr for packages only
176 XXX << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
177 remaining_r.push_back( *it );
181 current_install.push_back( *it );
184 TargetImpl::PoolItemList bad = commit (current_install);
185 remaining_r.insert(remaining_r.end(), bad.begin(), bad.end());
187 for (TargetImpl::PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
189 Resolvable::constPtr res( it->resolvable() );
190 Package::constPtr pkg( asKind<Package>(res) );
191 if (pkg && medianr != pkg->mediaId()) // check medianr for packages only
193 XXX << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
194 srcremaining_r.push_back( *it );
197 current_srcinstall.push_back( *it );
200 bad = commit (current_srcinstall);
201 srcremaining_r.insert(srcremaining_r.end(), bad.begin(), bad.end());
203 return to_install.size() - remaining_r.size();
207 TargetImpl::PoolItemList
208 TargetImpl::commit( const TargetImpl::PoolItemList & items_r)
210 TargetImpl::PoolItemList remaining;
212 MIL << "TargetImpl::commit(<list>)" << endl;
216 // remember the last used source (if any)
217 Source_Ref lastUsedSource;
219 for (TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
221 if (isKind<Package>(it->resolvable()))
223 Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
224 if (it->status().isToBeInstalled())
226 Pathname localfile = getRpmFile( p );
227 lastUsedSource = p->source(); // remember the package source
229 #warning Exception handling
230 // create a installation progress report proxy
231 RpmInstallPackageReceiver progress( it->resolvable() );
236 progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
238 rpm().installPackage(localfile,
239 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : 0);
241 if( progress.aborted() )
243 WAR << "commit aborted by the user" << endl;
244 progress.disconnect();
250 catch (Exception & excpt_r) {
251 ZYPP_CAUGHT(excpt_r);
252 WAR << "Install failed, retrying with --nodeps" << endl;
254 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
255 rpm().installPackage(localfile,
256 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : rpm::RpmDb::RPMINST_NODEPS);
258 if( progress.aborted() )
260 WAR << "commit aborted by the user" << endl;
262 progress.disconnect();
266 catch (Exception & excpt_r)
268 ZYPP_CAUGHT(excpt_r);
269 WAR << "Install failed again, retrying with --force --nodeps" << endl;
272 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
273 rpm().installPackage(localfile,
274 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : (rpm::RpmDb::RPMINST_NODEPS|rpm::RpmDb::RPMINST_FORCE));
276 catch (Exception & excpt_r) {
277 remaining.push_back( *it );
279 ZYPP_CAUGHT(excpt_r);
282 if( progress.aborted() )
284 WAR << "commit aborted by the user" << endl;
286 progress.disconnect();
292 it->status().setTransact( false, ResStatus::USER );
294 progress.disconnect();
300 RpmRemovePackageReceiver progress(it->resolvable());
303 rpm().removePackage( p, rpm::RpmDb::RPMINST_NODEPS );
305 catch (Exception & excpt_r) {
306 WAR << "removal of " << p << " failed";
308 ZYPP_CAUGHT( excpt_r );
311 it->status().setTransact( false, ResStatus::USER );
313 progress.disconnect();
316 else // other resolvables
318 if ( isStorageEnabled() )
320 if (it->status().isToBeInstalled())
322 bool success = false;
325 _storage.storeObject(it->resolvable());
328 catch (Exception & excpt_r)
330 ZYPP_CAUGHT(excpt_r);
331 WAR << "Install of Resolvable from storage failed" << endl;
334 it->status().setTransact( false, ResStatus::USER );
338 bool success = false;
341 _storage.deleteObject(it->resolvable());
344 catch (Exception & excpt_r)
346 ZYPP_CAUGHT(excpt_r);
347 WAR << "Uninstall of Resolvable from storage failed" << endl;
350 it->status().setTransact( false, ResStatus::USER );
355 WAR << "storage target disabled" << std::endl;
358 } // other resolvables
362 // we're done with the commit, release the source media
363 // In the case of a single media, end of commit means we don't need _this_
365 // In the case of 'commit any media', end of commit means we're completely
366 // done and don't need the source's media anyways.
368 if (lastUsedSource) { // if a source was used
369 lastUsedSource.release(); // release their medias
373 ZYPP_THROW( Exception( N_("Target commit aborted by user.") ) );
378 rpm::RpmDb & TargetImpl::rpm()
381 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
382 { return _rpm.hasFile(path_str, name_str); }
384 /** Return the resolvable which provides path_str (rpm -qf)
385 return NULL if no resolvable provides this file */
386 ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
388 string name = _rpm.whoOwnsFile (path_str);
392 for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it) {
393 if ((*it)->name() == name) {
400 /** Set the log file for target */
401 bool TargetImpl::setInstallationLogfile(const Pathname & path_r)
403 return rpm::RpmDb::setInstallationLogfile(path_r);
406 //-----------------------------------------------------------------------------
407 /******************************************************************
410 ** FUNCTION NAME : strip_obsoleted_to_delete
411 ** FUNCTION TYPE : void
413 ** strip packages to_delete which get obsoleted by
414 ** to_install (i.e. delay deletion in case the
415 ** obsoleting package likes to save whatever...
419 strip_obsoleted_to_delete( TargetImpl::PoolItemList & deleteList_r,
420 const TargetImpl::PoolItemList & instlist_r )
422 if ( deleteList_r.size() == 0 || instlist_r.size() == 0 )
423 return; // ---> nothing to do
425 // build obsoletes from instlist_r
427 for ( TargetImpl::PoolItemList::const_iterator it = instlist_r.begin();
428 it != instlist_r.end(); ++it )
430 PoolItem_Ref item( *it );
431 obsoletes.insert( item->dep(Dep::OBSOLETES).begin(), item->dep(Dep::OBSOLETES).end() );
433 if ( obsoletes.size() == 0 )
434 return; // ---> nothing to do
437 TargetImpl::PoolItemList undelayed;
438 // forall applDelete Packages...
439 for ( TargetImpl::PoolItemList::iterator it = deleteList_r.begin();
440 it != deleteList_r.end(); ++it )
442 PoolItem_Ref ipkg( *it );
443 bool delayPkg = false;
444 // ...check whether an obsoletes....
445 for ( CapSet::iterator obs = obsoletes.begin();
446 ! delayPkg && obs != obsoletes.end(); ++obs )
448 // ...matches anything provided by the package?
449 for ( CapSet::const_iterator prov = ipkg->dep(Dep::PROVIDES).begin();
450 prov != ipkg->dep(Dep::PROVIDES).end(); ++prov )
452 if ( obs->matches( *prov ) == CapMatch::yes )
454 // if so, delay package deletion
455 DBG << "Ignore appl_delete (should be obsoleted): " << ipkg << endl;
457 ipkg.status().setTransact( false, ResStatus::USER );
463 DBG << "undelayed " << ipkg << endl;
464 undelayed.push_back( ipkg );
468 deleteList_r.swap( undelayed );
475 TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
476 TargetImpl::PoolItemList & dellist_r,
477 TargetImpl::PoolItemList & instlist_r,
478 TargetImpl::PoolItemList & srclist_r ) const
483 TargetImpl::PoolItemList nonpkglist;
485 for ( ResPool::const_iterator it = pool_r.begin(); it != pool_r.end(); ++it )
487 if (it->status().isToBeInstalled())
489 if ((*it)->kind() == ResTraits<SrcPackage>::kind) {
490 srclist_r.push_back( *it );
492 else if ((*it)->kind() != ResTraits<Package>::kind) {
493 nonpkglist.push_back( *it );
496 instlist_r.push_back( *it );
498 else if (it->status().isToBeUninstalled())
500 if ( it->status().isToBeUninstalledDueToObsolete() )
502 DBG << "Ignore auto_delete (should be obsoleted): " << *it << endl;
504 else if ( it->status().isToBeUninstalledDueToUpgrade() )
506 DBG << "Ignore auto_delete (should be upgraded): " << *it << endl;
509 dellist_r.push_back( *it );
514 MIL << "ResolvablesToInsDel: delete " << dellist_r.size()
515 << ", install " << instlist_r.size()
516 << ", srcinstall " << srclist_r.size()
517 << ", nonpkg " << nonpkglist.size() << endl;
519 ///////////////////////////////////////////////////////////////////
521 // strip packages to_delete which get obsoleted by
522 // to_install (i.e. delay deletion in case the
523 // obsoleting package likes to save whatever...
525 ///////////////////////////////////////////////////////////////////
526 strip_obsoleted_to_delete( dellist_r, instlist_r );
528 if ( dellist_r.size() ) {
529 ///////////////////////////////////////////////////////////////////
531 // sort delete list...
533 ///////////////////////////////////////////////////////////////////
534 TargetImpl::PoolItemSet delset; // for delete order
535 TargetImpl::PoolItemSet dummy; // dummy, empty, should contain already installed
536 for ( TargetImpl::PoolItemList::iterator pkgIt = dellist_r.begin();
537 pkgIt != dellist_r.end(); ++pkgIt )
539 delset.insert( *pkgIt );
542 InstallOrder order( pool_r, delset, dummy ); // sort according top prereq
544 const TargetImpl::PoolItemList dsorted( order.getTopSorted() );
547 for ( TargetImpl::PoolItemList::const_reverse_iterator cit = dsorted.rbegin();
548 cit != dsorted.rend(); ++cit )
550 dellist_r.push_back( *cit );
554 ///////////////////////////////////////////////////////////////////
556 // sort installed list...
558 ///////////////////////////////////////////////////////////////////
559 if ( instlist_r.empty() ) {
560 instlist_r.splice( instlist_r.end(), nonpkglist );
564 #warning Source Rank Priority ?
566 ///////////////////////////////////////////////////////////////////
567 // Get desired order of InstSrc'es to install from.
568 ///////////////////////////////////////////////////////////////////
569 typedef map<unsigned,unsigned> RankPriority;
571 RankPriority rankPriority;
573 InstSrcManager::ISrcIdList sourcerank( Y2PM::instSrcManager().instOrderSources() );
574 // map InstSrc rank to install priority
576 for ( InstSrcManager::ISrcIdList::const_iterator it = sourcerank.begin();
577 it != sourcerank.end(); ++it, ++prio ) {
578 rankPriority[(*it)->descr()->default_rank()] = prio;
583 ///////////////////////////////////////////////////////////////////
584 // Compute install order according to packages prereq.
585 // Try to group packages with respect to the desired install order
586 ///////////////////////////////////////////////////////////////////
587 // backup list for debug purpose.
588 // You can as well build the set, clear the list and rebuild it in install order.
589 TargetImpl::PoolItemList instbackup_r;
590 instbackup_r.swap( instlist_r );
592 TargetImpl::PoolItemSet insset; // for install order
593 TargetImpl::PoolItemSet installed; // dummy, empty, should contain already installed
594 for ( TargetImpl::PoolItemList::iterator resIt = instbackup_r.begin(); resIt != instbackup_r.end(); ++resIt ) {
595 insset.insert( *resIt );
597 InstallOrder order( pool_r, insset, installed );
598 // start recursive depth-first-search
600 MIL << "order.init() done" << endl;
601 order.printAdj( XXX, false );
602 ///////////////////////////////////////////////////////////////////
603 // build install list in install order
604 ///////////////////////////////////////////////////////////////////
605 TargetImpl::PoolItemList best_list;
606 // unsigned best_prio = 0;
607 unsigned best_medianum = 0;
609 TargetImpl::PoolItemList last_list;
610 // unsigned last_prio = 0;
611 unsigned last_medianum = 0;
613 TargetImpl::PoolItemList other_list;
615 for ( TargetImpl::PoolItemList items = order.computeNextSet(); ! items.empty(); items = order.computeNextSet() )
617 MIL << "order.computeNextSet: " << items.size() << " resolvables" << endl;
618 ///////////////////////////////////////////////////////////////////
619 // items contains all packages we could install now. Pick all packages
620 // from current media, or best media if none for current.
621 ///////////////////////////////////////////////////////////////////
627 for ( TargetImpl::PoolItemList::iterator cit = items.begin(); cit != items.end(); ++cit )
629 Resolvable::constPtr res( cit->resolvable() );
631 Package::constPtr cpkg( asKind<Package>(res) );
633 XXX << "Not a package " << *cit << endl;
634 order.setInstalled( *cit );
635 other_list.push_back( *cit );
638 XXX << "Package " << *cpkg << ", media " << cpkg->mediaId() << " last_medianum " << last_medianum << " best_medianum " << best_medianum << endl;
639 if ( // rankPriority[cpkg->instSrcRank()] == last_prio &&
640 cpkg->mediaId() == last_medianum ) {
641 // prefer packages on current media.
642 last_list.push_back( *cit );
646 if ( last_list.empty() ) {
647 // check for best media as long as there are no packages for current media.
649 if ( ! best_list.empty() ) {
652 if ( rankPriority[cpkg->instSrcRank()] < best_prio ) {
653 best_list.clear(); // new best
654 } else if ( rankPriority[cpkg->instSrcRank()] == best_prio ) {
657 if ( cpkg->mediaId() < best_medianum ) {
658 best_list.clear(); // new best
659 } else if ( cpkg->mediaId() == best_medianum ) {
660 best_list.push_back( *cit ); // same as best -> add
672 if ( best_list.empty() )
674 // first package or new best
675 best_list.push_back( *cit );
676 // best_prio = rankPriority[cpkg->instSrcRank()];
677 best_medianum = cpkg->mediaId();
682 } // for all packages in current set
684 ///////////////////////////////////////////////////////////////////
685 // remove packages picked from install order and append them to
687 ///////////////////////////////////////////////////////////////////
688 TargetImpl::PoolItemList & take_list( last_list.empty() ? best_list : last_list );
689 if ( last_list.empty() )
691 MIL << "SET NEW media " << best_medianum << endl;
692 // last_prio = best_prio;
693 last_medianum = best_medianum;
697 MIL << "SET CONTINUE" << endl;
700 for ( TargetImpl::PoolItemList::iterator it = take_list.begin(); it != take_list.end(); ++it )
702 order.setInstalled( *it );
703 XXX << "SET isrc " << (*it)->name() << endl;
705 // move everthing from take_list to the end of instlist_r, clean take_list
706 instlist_r.splice( instlist_r.end(), take_list );
707 // same for other_list
708 instlist_r.splice( instlist_r.end(), other_list );
710 } // for all sets computed
713 if ( instbackup_r.size() != instlist_r.size() )
715 ERR << "***************** Lost packages in InstallOrder sort." << endl;
717 instlist_r.splice( instlist_r.end(), nonpkglist );
721 /////////////////////////////////////////////////////////////////
722 } // namespace target
723 ///////////////////////////////////////////////////////////////////
724 /////////////////////////////////////////////////////////////////
726 ///////////////////////////////////////////////////////////////////