1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/TargetImpl.cc
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/Exception.h"
19 #include "zypp/PoolItem.h"
20 #include "zypp/Resolvable.h"
21 #include "zypp/ResObject.h"
22 #include "zypp/Package.h"
24 #include "zypp/target/TargetImpl.h"
25 #include "zypp/target/TargetCallbackReceiver.h"
27 #include "zypp/solver/detail/InstallOrder.h"
30 using zypp::solver::detail::InstallOrder;
32 ///////////////////////////////////////////////////////////////////
34 { /////////////////////////////////////////////////////////////////
35 ///////////////////////////////////////////////////////////////////
37 { /////////////////////////////////////////////////////////////////
39 IMPL_PTR_TYPE(TargetImpl);
41 TargetImpl_Ptr TargetImpl::_nullimpl;
43 /** Null implementation */
44 TargetImpl_Ptr TargetImpl::nullimpl()
47 _nullimpl = new TargetImpl;
52 ///////////////////////////////////////////////////////////////////
54 // METHOD NAME : TargetImpl::TargetImpl
57 TargetImpl::TargetImpl(const Pathname & root_r)
60 _rpm.initDatabase(_root);
61 _storage_enabled = false;
62 MIL << "Initialized target on " << _root << endl;
65 ///////////////////////////////////////////////////////////////////
67 // METHOD NAME : TargetImpl::~TargetImpl
70 TargetImpl::~TargetImpl()
73 MIL << "Targets closed" << endl;
76 bool TargetImpl::isStorageEnabled() const
78 return _storage_enabled;
82 void TargetImpl::enableStorage(const Pathname &root_r)
84 _storage.init(root_r);
85 _storage_enabled = true;
88 const ResStore & TargetImpl::resolvables()
92 std::list<Package::Ptr> packages = _rpm.getPackages();
93 for (std::list<Package::Ptr>::const_iterator it = packages.begin();
100 if ( isStorageEnabled() )
102 // resolvables stored in the zypp storage database
103 std::list<ResObject::Ptr> resolvables = _storage.storedObjects();
104 for (std::list<ResObject::Ptr>::iterator it = resolvables.begin();
105 it != resolvables.end();
113 WAR << "storage target not enabled" << std::endl;
120 Pathname TargetImpl::getRpmFile(Package::constPtr package)
122 callback::SendReport<source::DownloadResolvableReport> report;
124 // FIXME: error handling
126 report->start( package, Url() );
128 Pathname file = package->getPlainRpm();
130 report->finish( package, source::DownloadResolvableReport::NO_ERROR, "" );
136 int TargetImpl::commit(ResPool pool_r, unsigned int medianr, TargetImpl::PoolItemList & errors_r, TargetImpl::PoolItemList & remaining_r, TargetImpl::PoolItemList & srcremaining_r)
138 MIL << "TargetImpl::commit(<pool>, " << medianr << ")" << endl;
142 srcremaining_r.clear();
144 TargetImpl::PoolItemList to_uninstall;
145 TargetImpl::PoolItemList to_install;
146 TargetImpl::PoolItemList to_srcinstall;
147 getResolvablesToInsDel( pool_r, to_uninstall, to_install, to_srcinstall );
150 MIL << "Restrict to media number " << medianr << endl;
153 commit (to_uninstall);
155 if (medianr == 0) { // commit all
156 remaining_r = commit( to_install );
157 srcremaining_r = commit( to_srcinstall );
161 TargetImpl::PoolItemList current_install;
162 TargetImpl::PoolItemList current_srcinstall;
164 for (TargetImpl::PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it)
166 Resolvable::constPtr res( it->resolvable() );
167 Package::constPtr pkg( asKind<Package>(res) );
168 if (pkg && medianr != pkg->mediaId()) // check medianr for packages only
170 MIL << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
171 remaining_r.push_back( *it );
175 current_install.push_back( *it );
178 TargetImpl::PoolItemList bad = commit (current_install);
179 remaining_r.insert(remaining_r.end(), bad.begin(), bad.end());
181 for (TargetImpl::PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
183 Resolvable::constPtr res( it->resolvable() );
184 Package::constPtr pkg( asKind<Package>(res) );
185 if (pkg && medianr != pkg->mediaId()) // check medianr for packages only
187 MIL << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
188 srcremaining_r.push_back( *it );
191 current_srcinstall.push_back( *it );
194 bad = commit (current_srcinstall);
195 srcremaining_r.insert(srcremaining_r.end(), bad.begin(), bad.end());
197 return to_install.size() - remaining_r.size();
201 TargetImpl::PoolItemList
202 TargetImpl::commit( const TargetImpl::PoolItemList & items_r)
204 TargetImpl::PoolItemList remaining;
206 MIL << "TargetImpl::commit(<list>)" << endl;
207 for (TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
209 if (isKind<Package>(it->resolvable()))
211 Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
212 if (it->status().isToBeInstalled())
214 Pathname localfile = getRpmFile(p);
215 #warning Exception handling
216 // create a installation progress report proxy
217 RpmInstallPackageReceiver progress(it->resolvable());
222 progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
224 rpm().installPackage(localfile,
225 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : 0);
227 catch (Exception & excpt_r) {
228 ZYPP_CAUGHT(excpt_r);
229 WAR << "Install failed, retrying with --nodeps" << endl;
231 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
232 rpm().installPackage(localfile,
233 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : rpm::RpmDb::RPMINST_NODEPS);
235 catch (Exception & excpt_r)
237 ZYPP_CAUGHT(excpt_r);
238 WAR << "Install failed again, retrying with --force --nodeps" << endl;
241 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
242 rpm().installPackage(localfile,
243 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : (rpm::RpmDb::RPMINST_NODEPS|rpm::RpmDb::RPMINST_FORCE));
245 catch (Exception & excpt_r) {
246 remaining.push_back( *it );
248 ZYPP_CAUGHT(excpt_r);
253 it->status().setStatus( ResStatus::installed );
255 progress.disconnect();
261 RpmRemovePackageReceiver progress(it->resolvable());
264 rpm().removePackage( p );
266 catch (Exception & excpt_r) {
267 ZYPP_CAUGHT(excpt_r);
268 WAR << "Remove failed, retrying with --nodeps" << endl;
270 rpm().removePackage( p, rpm::RpmDb::RPMINST_NODEPS);
272 catch (Exception & excpt_r) {
273 ZYPP_CAUGHT(excpt_r);
278 it->status().setStatus( ResStatus::uninstalled );
280 progress.disconnect();
283 else // other resolvables
285 if ( isStorageEnabled() )
287 if (it->status().isToBeInstalled())
289 bool success = false;
292 _storage.storeObject(it->resolvable());
295 catch (Exception & excpt_r)
297 ZYPP_CAUGHT(excpt_r);
298 WAR << "Install of Resolvable from storage failed" << endl;
301 it->status().setStatus( ResStatus::installed );
305 bool success = false;
308 _storage.deleteObject(it->resolvable());
311 catch (Exception & excpt_r)
313 ZYPP_CAUGHT(excpt_r);
314 WAR << "Uninstall of Resolvable from storage failed" << endl;
317 it->status().setStatus( ResStatus::uninstalled );
322 WAR << "storage target disabled" << std::endl;
329 rpm::RpmDb & TargetImpl::rpm()
332 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
333 { return _rpm.hasFile(path_str, name_str); }
335 /** Return the resolvable which provides path_str (rpm -qf)
336 return NULL if no resolvable provides this file */
337 ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
339 string name = _rpm.whoOwnsFile (path_str);
343 for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it) {
344 if ((*it)->name() == name) {
351 /** Set the log file for target */
352 bool TargetImpl::setInstallationLogfile(const Pathname & path_r)
354 return rpm::RpmDb::setInstallationLogfile(path_r);
357 //-----------------------------------------------------------------------------
358 /******************************************************************
361 ** FUNCTION NAME : strip_obsoleted_to_delete
362 ** FUNCTION TYPE : void
364 ** strip packages to_delete which get obsoleted by
365 ** to_install (i.e. delay deletion in case the
366 ** obsoleting package likes to save whatever...
370 strip_obsoleted_to_delete( TargetImpl::PoolItemList & deleteList_r,
371 const TargetImpl::PoolItemList & instlist_r )
373 if ( deleteList_r.size() == 0 || instlist_r.size() == 0 )
374 return; // ---> nothing to do
376 // build obsoletes from instlist_r
378 for ( TargetImpl::PoolItemList::const_iterator it = instlist_r.begin();
379 it != instlist_r.end(); ++it )
381 PoolItem_Ref item( *it );
382 obsoletes.insert( item->dep(Dep::OBSOLETES).begin(), item->dep(Dep::OBSOLETES).end() );
384 if ( obsoletes.size() == 0 )
385 return; // ---> nothing to do
388 TargetImpl::PoolItemList undelayed;
389 // forall applDelete Packages...
390 for ( TargetImpl::PoolItemList::iterator it = deleteList_r.begin();
391 it != deleteList_r.end(); ++it )
393 PoolItem_Ref ipkg( *it );
394 bool delayPkg = false;
395 // ...check whether an obsoletes....
396 for ( CapSet::iterator obs = obsoletes.begin();
397 ! delayPkg && obs != obsoletes.end(); ++obs )
399 // ...matches anything provided by the package?
400 for ( CapSet::const_iterator prov = ipkg->dep(Dep::PROVIDES).begin();
401 prov != ipkg->dep(Dep::PROVIDES).end(); ++prov )
403 if ( obs->matches( *prov ) == CapMatch::yes )
405 // if so, delay package deletion
406 DBG << "Ignore appl_delete (should be obsoleted): " << ipkg << endl;
413 MIL << "undelayed " << ipkg << endl;
414 undelayed.push_back( ipkg );
418 deleteList_r.swap( undelayed );
425 TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
426 TargetImpl::PoolItemList & dellist_r,
427 TargetImpl::PoolItemList & instlist_r,
428 TargetImpl::PoolItemList & srclist_r ) const
433 TargetImpl::PoolItemList nonpkglist;
435 for ( ResPool::const_iterator it = pool_r.begin(); it != pool_r.end(); ++it )
437 if (it->status().isToBeInstalled())
439 if ((*it)->kind() != ResTraits<Package>::kind) {
440 nonpkglist.push_back( *it );
442 else if (it->resolvable()->arch() == Arch_src)
443 srclist_r.push_back( *it );
445 instlist_r.push_back( *it );
447 else if (it->status().isToBeUninstalled())
449 if ( it->status().isToBeUninstalledDueToObsolete() )
451 DBG << "Ignore auto_delete (should be obsoleted): " << *it << endl;
453 else if ( it->status().isToBeUninstalledDueToUpgrade() )
455 DBG << "Ignore auto_delete (should be upgraded): " << *it << endl;
458 dellist_r.push_back( *it );
463 MIL << "ResolvablesToInsDel: delete " << dellist_r.size()
464 << ", install " << instlist_r.size()
465 << ", srcinstall " << srclist_r.size()
466 << ", nonpkg " << nonpkglist.size() << endl;
468 ///////////////////////////////////////////////////////////////////
470 // strip packages to_delete which get obsoleted by
471 // to_install (i.e. delay deletion in case the
472 // obsoleting package likes to save whatever...
474 ///////////////////////////////////////////////////////////////////
475 strip_obsoleted_to_delete( dellist_r, instlist_r );
477 if ( dellist_r.size() ) {
478 ///////////////////////////////////////////////////////////////////
480 // sort delete list...
482 ///////////////////////////////////////////////////////////////////
483 TargetImpl::PoolItemSet delset; // for delete order
484 TargetImpl::PoolItemSet dummy; // dummy, empty, should contain already installed
485 for ( TargetImpl::PoolItemList::iterator pkgIt = dellist_r.begin();
486 pkgIt != dellist_r.end(); ++pkgIt )
488 delset.insert( *pkgIt );
491 InstallOrder order( pool_r, delset, dummy ); // sort according top prereq
493 const TargetImpl::PoolItemList dsorted( order.getTopSorted() );
496 for ( TargetImpl::PoolItemList::const_reverse_iterator cit = dsorted.rbegin();
497 cit != dsorted.rend(); ++cit )
499 dellist_r.push_back( *cit );
503 ///////////////////////////////////////////////////////////////////
505 // sort installed list...
507 ///////////////////////////////////////////////////////////////////
508 if ( instlist_r.empty() ) {
509 instlist_r.splice( instlist_r.end(), nonpkglist );
513 #warning Source Rank Priority ?
515 ///////////////////////////////////////////////////////////////////
516 // Get desired order of InstSrc'es to install from.
517 ///////////////////////////////////////////////////////////////////
518 typedef map<unsigned,unsigned> RankPriority;
520 RankPriority rankPriority;
522 InstSrcManager::ISrcIdList sourcerank( Y2PM::instSrcManager().instOrderSources() );
523 // map InstSrc rank to install priority
525 for ( InstSrcManager::ISrcIdList::const_iterator it = sourcerank.begin();
526 it != sourcerank.end(); ++it, ++prio ) {
527 rankPriority[(*it)->descr()->default_rank()] = prio;
532 ///////////////////////////////////////////////////////////////////
533 // Compute install order according to packages prereq.
534 // Try to group packages with respect to the desired install order
535 ///////////////////////////////////////////////////////////////////
536 // backup list for debug purpose.
537 // You can as well build the set, clear the list and rebuild it in install order.
538 TargetImpl::PoolItemList instbackup_r;
539 instbackup_r.swap( instlist_r );
541 TargetImpl::PoolItemSet insset; // for install order
542 TargetImpl::PoolItemSet installed; // dummy, empty, should contain already installed
543 for ( TargetImpl::PoolItemList::iterator resIt = instbackup_r.begin(); resIt != instbackup_r.end(); ++resIt ) {
544 insset.insert( *resIt );
546 InstallOrder order( pool_r, insset, installed );
547 // start recursive depth-first-search
549 MIL << "order.init() done" << endl;
550 order.printAdj( DBG, false );
551 ///////////////////////////////////////////////////////////////////
552 // build install list in install order
553 ///////////////////////////////////////////////////////////////////
554 TargetImpl::PoolItemList best_list;
555 // unsigned best_prio = 0;
556 unsigned best_medianum = 0;
558 TargetImpl::PoolItemList last_list;
559 // unsigned last_prio = 0;
560 unsigned last_medianum = 0;
562 TargetImpl::PoolItemList other_list;
564 for ( TargetImpl::PoolItemList items = order.computeNextSet(); ! items.empty(); items = order.computeNextSet() )
566 MIL << "order.computeNextSet: " << items.size() << " resolvables" << endl;
567 ///////////////////////////////////////////////////////////////////
568 // items contains all packages we could install now. Pick all packages
569 // from current media, or best media if none for current.
570 ///////////////////////////////////////////////////////////////////
576 for ( TargetImpl::PoolItemList::iterator cit = items.begin(); cit != items.end(); ++cit )
578 Resolvable::constPtr res( cit->resolvable() );
580 Package::constPtr cpkg( asKind<Package>(res) );
582 MIL << "Not a package " << *cit << endl;
583 order.setInstalled( *cit );
584 other_list.push_back( *cit );
587 MIL << "Package " << *cpkg << ", media " << cpkg->mediaId() << " last_medianum " << last_medianum << " best_medianum " << best_medianum << endl;
588 if ( // rankPriority[cpkg->instSrcRank()] == last_prio &&
589 cpkg->mediaId() == last_medianum ) {
590 // prefer packages on current media.
591 last_list.push_back( *cit );
595 if ( last_list.empty() ) {
596 // check for best media as long as there are no packages for current media.
598 if ( ! best_list.empty() ) {
601 if ( rankPriority[cpkg->instSrcRank()] < best_prio ) {
602 best_list.clear(); // new best
603 } else if ( rankPriority[cpkg->instSrcRank()] == best_prio ) {
606 if ( cpkg->mediaId() < best_medianum ) {
607 best_list.clear(); // new best
608 } else if ( cpkg->mediaId() == best_medianum ) {
609 best_list.push_back( *cit ); // same as best -> add
621 if ( best_list.empty() )
623 // first package or new best
624 best_list.push_back( *cit );
625 // best_prio = rankPriority[cpkg->instSrcRank()];
626 best_medianum = cpkg->mediaId();
631 } // for all packages in current set
633 ///////////////////////////////////////////////////////////////////
634 // remove packages picked from install order and append them to
636 ///////////////////////////////////////////////////////////////////
637 TargetImpl::PoolItemList & take_list( last_list.empty() ? best_list : last_list );
638 if ( last_list.empty() )
640 MIL << "SET NEW media " << best_medianum << endl;
641 // last_prio = best_prio;
642 last_medianum = best_medianum;
646 MIL << "SET CONTINUE" << endl;
649 for ( TargetImpl::PoolItemList::iterator it = take_list.begin(); it != take_list.end(); ++it )
651 order.setInstalled( *it );
652 MIL << "SET isrc " << (*it)->name() << endl;
654 // move everthing from take_list to the end of instlist_r, clean take_list
655 instlist_r.splice( instlist_r.end(), take_list );
656 // same for other_list
657 instlist_r.splice( instlist_r.end(), other_list );
659 } // for all sets computed
662 if ( instbackup_r.size() != instlist_r.size() )
664 ERR << "***************** Lost packages in InstallOrder sort." << endl;
666 instlist_r.splice( instlist_r.end(), nonpkglist );
670 /////////////////////////////////////////////////////////////////
671 } // namespace target
672 ///////////////////////////////////////////////////////////////////
673 /////////////////////////////////////////////////////////////////
675 ///////////////////////////////////////////////////////////////////