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/Types.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 MIL << "Initialized target on " << _root << endl;
65 ///////////////////////////////////////////////////////////////////
67 // METHOD NAME : TargetImpl::~TargetImpl
70 TargetImpl::~TargetImpl()
73 MIL << "Targets closed" << endl;
76 #ifndef STORAGE_DISABLED
77 bool TargetImpl::isStorageEnabled() const
79 return _storage.isInitialized();
83 void TargetImpl::enableStorage(const Pathname &root_r)
86 _storage.init(root_r);
90 const ResStore & TargetImpl::resolvables()
94 std::list<Package::Ptr> packages = _rpm.getPackages();
95 for (std::list<Package::Ptr>::const_iterator it = packages.begin();
102 #ifndef STORAGE_DISABLED
103 if ( isStorageEnabled() )
105 // resolvables stored in the zypp storage database
106 std::list<ResObject::Ptr> resolvables = _storage.storedObjects();
107 for (std::list<ResObject::Ptr>::iterator it = resolvables.begin();
108 it != resolvables.end();
116 WAR << "storage target not enabled" << std::endl;
124 Pathname TargetImpl::getRpmFile(Package::constPtr package)
126 callback::SendReport<source::DownloadResolvableReport> report;
128 // FIXME: error handling
130 report->start( package, Url() );
132 Pathname file = package->getPlainRpm();
134 report->finish( package, source::DownloadResolvableReport::NO_ERROR, "" );
140 void TargetImpl::commit(ResPool pool_r, unsigned int medianr, PoolItemList & errors_r, PoolItemList & remaining_r, PoolItemList & srcremaining_r)
142 MIL << "TargetImpl::commit(<pool>, " << medianr << ")" << endl;
146 srcremaining_r.clear();
148 PoolItemList to_uninstall;
149 PoolItemList to_install;
150 PoolItemList to_srcinstall;
151 getResolvablesToInsDel( pool_r, to_uninstall, to_install, to_srcinstall );
154 MIL << "Restrict to media number " << medianr << endl;
157 commit (to_uninstall);
159 if (medianr == 0) { // commit all
160 remaining_r = commit( to_install );
161 srcremaining_r = commit( to_srcinstall );
165 PoolItemList current_install;
166 PoolItemList current_srcinstall;
168 for (PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it)
170 Resolvable::constPtr res( it->resolvable() );
171 Package::constPtr pkg( asKind<Package>(res) );
172 if (pkg && medianr != pkg->mediaId()) // check medianr for packages only
174 MIL << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
175 remaining_r.push_back( *it );
179 current_install.push_back( *it );
182 PoolItemList bad = commit (current_install);
183 remaining_r.insert(remaining_r.end(), bad.begin(), bad.end());
185 for (PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
187 Resolvable::constPtr res( it->resolvable() );
188 Package::constPtr pkg( asKind<Package>(res) );
189 if (pkg && medianr != pkg->mediaId()) // check medianr for packages only
191 MIL << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
192 srcremaining_r.push_back( *it );
195 current_srcinstall.push_back( *it );
198 bad = commit (current_srcinstall);
199 srcremaining_r.insert(remaining_r.end(), bad.begin(), bad.end());
206 TargetImpl::commit( const PoolItemList & items_r)
208 PoolItemList remaining;
210 MIL << "TargetImpl::commit(<list>)" << endl;
211 for (PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
213 if (isKind<Package>(it->resolvable()))
215 Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
216 if (it->status().isToBeInstalled())
218 Pathname localfile = getRpmFile(p);
219 #warning Exception handling
220 // create a installation progress report proxy
221 RpmInstallPackageReceiver progress(it->resolvable());
226 progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
228 rpm().installPackage(localfile,
229 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : 0);
231 catch (Exception & excpt_r) {
232 ZYPP_CAUGHT(excpt_r);
233 WAR << "Install failed, retrying with --nodeps" << endl;
235 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
236 rpm().installPackage(localfile,
237 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : rpm::RpmDb::RPMINST_NODEPS);
239 catch (Exception & excpt_r)
241 ZYPP_CAUGHT(excpt_r);
242 WAR << "Install failed again, retrying with --force --nodeps" << endl;
245 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
246 rpm().installPackage(localfile,
247 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : (rpm::RpmDb::RPMINST_NODEPS|rpm::RpmDb::RPMINST_FORCE));
249 catch (Exception & excpt_r) {
250 remaining.push_back( *it );
252 ZYPP_CAUGHT(excpt_r);
257 it->status().setStatus( ResStatus::installed );
259 progress.disconnect();
263 RpmRemovePackageReceiver progress(it->resolvable());
266 rpm().removePackage(p);
268 catch (Exception & excpt_r) {
269 ZYPP_CAUGHT(excpt_r);
270 WAR << "Remove failed, retrying with --nodeps" << endl;
271 rpm().removePackage(p, rpm::RpmDb::RPMINST_NODEPS);
273 progress.disconnect();
274 it->status().setStatus( ResStatus::uninstalled );
277 #ifndef STORAGE_DISABLED
278 else // other resolvables
280 if ( isStorageEnabled() )
282 if (it->status().isToBeInstalled())
284 bool success = false;
287 _storage.storeObject(it->resolvable());
290 catch (Exception & excpt_r)
292 ZYPP_CAUGHT(excpt_r);
293 WAR << "Install of Resolvable from storage failed" << endl;
296 it->status().setStatus( ResStatus::installed );
300 bool success = false;
303 _storage.deleteObject(it->resolvable());
306 catch (Exception & excpt_r)
308 ZYPP_CAUGHT(excpt_r);
309 WAR << "Uninstall of Resolvable from storage failed" << endl;
312 it->status().setStatus( ResStatus::uninstalled );
317 WAR << "storage target disabled" << std::endl;
325 rpm::RpmDb & TargetImpl::rpm()
328 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
329 { return _rpm.hasFile(path_str, name_str); }
331 /** Return the resolvable which provides path_str (rpm -qf)
332 return NULL if no resolvable provides this file */
333 ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
335 string name = _rpm.whoOwnsFile (path_str);
339 for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it) {
340 if ((*it)->name() == name) {
347 //-----------------------------------------------------------------------------
348 /******************************************************************
351 ** FUNCTION NAME : strip_obsoleted_to_delete
352 ** FUNCTION TYPE : void
354 ** strip packages to_delete which get obsoleted by
355 ** to_install (i.e. delay deletion in case the
356 ** obsoleting package likes to save whatever...
359 strip_obsoleted_to_delete( PoolItemList & deleteList_r,
360 const PoolItemList & instlist_r )
362 if ( deleteList_r.size() == 0 || instlist_r.size() == 0 )
363 return; // ---> nothing to do
365 // build obsoletes from instlist_r
367 for ( PoolItemList::const_iterator it = instlist_r.begin();
368 it != instlist_r.end(); ++it )
370 PoolItem_Ref item( *it );
371 obsoletes.insert( item->dep(Dep::OBSOLETES).begin(), item->dep(Dep::OBSOLETES).end() );
373 if ( obsoletes.size() == 0 )
374 return; // ---> nothing to do
377 PoolItemList undelayed;
378 // forall applDelete Packages...
379 for ( PoolItemList::iterator it = deleteList_r.begin();
380 it != deleteList_r.end(); ++it )
382 PoolItem_Ref ipkg( *it );
383 bool delayPkg = false;
384 // ...check whether an obsolets....
385 for ( CapSet::iterator obs = obsoletes.begin();
386 ! delayPkg && obs != obsoletes.end(); ++obs )
388 // ...matches anything provided by the package?
389 for ( CapSet::const_iterator prov = ipkg->dep(Dep::PROVIDES).begin();
390 prov != ipkg->dep(Dep::PROVIDES).end(); ++prov )
392 if ( obs->matches( *prov ) == CapMatch::yes )
394 // if so, delay package deletion
395 DBG << "Ignore appl_delete (should be obsoleted): " << ipkg << endl;
402 MIL << "undelayed " << ipkg << endl;
403 undelayed.push_back( ipkg );
407 deleteList_r.swap( undelayed );
414 TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
415 PoolItemList & dellist_r,
416 PoolItemList & instlist_r,
417 PoolItemList & srclist_r )
422 PoolItemList nonpkglist;
424 for ( ResPool::const_iterator it = pool_r.begin(); it != pool_r.end(); ++it )
426 if ((*it)->kind() != ResTraits<Package>::kind) {
427 nonpkglist.push_back( *it );
431 if (it->status().isToBeInstalled())
433 if (it->resolvable()->arch() == Arch_src)
434 srclist_r.push_back( *it );
436 instlist_r.push_back( *it );
438 else if (it->status().isToBeUninstalled())
440 if ( it->status().isToBeUninstalledDueToObsolete() )
442 DBG << "Ignore auto_delete (should be obsoleted): " << *it << endl;
444 dellist_r.push_back( *it );
449 MIL << "ResolvablesToInsDel: delete " << dellist_r.size()
450 << ", install " << instlist_r.size()
451 << ", srcinstall " << srclist_r.size()
452 << ", nonpkg " << nonpkglist.size() << endl;
454 ///////////////////////////////////////////////////////////////////
456 // strip packages to_delete which get obsoleted by
457 // to_install (i.e. delay deletion in case the
458 // obsoleting package likes to save whatever...
460 ///////////////////////////////////////////////////////////////////
461 strip_obsoleted_to_delete( dellist_r, instlist_r );
463 if ( dellist_r.size() ) {
464 ///////////////////////////////////////////////////////////////////
466 // sort delete list...
468 ///////////////////////////////////////////////////////////////////
469 PoolItemList dlist; // for delete order
470 PoolItemList dummy; // dummy, empty, should contain already installed
471 for ( PoolItemList::iterator pkgIt = dellist_r.begin();
472 pkgIt != dellist_r.end(); ++pkgIt )
474 dlist.push_back( *pkgIt );
477 InstallOrder order( pool_r, dlist, dummy ); // sort according top prereq
479 const PoolItemList dsorted( order.getTopSorted() );
482 for ( PoolItemList::const_reverse_iterator cit = dsorted.rbegin();
483 cit != dsorted.rend(); ++cit )
485 dellist_r.push_back( *cit );
489 ///////////////////////////////////////////////////////////////////
491 // sort installed list...
493 ///////////////////////////////////////////////////////////////////
494 if ( instlist_r.empty() ) {
497 #warning Source Rank Priority ?
499 ///////////////////////////////////////////////////////////////////
500 // Get desired order of InstSrc'es to install from.
501 ///////////////////////////////////////////////////////////////////
502 typedef map<unsigned,unsigned> RankPriority;
504 RankPriority rankPriority;
506 InstSrcManager::ISrcIdList sourcerank( Y2PM::instSrcManager().instOrderSources() );
507 // map InstSrc rank to install priority
509 for ( InstSrcManager::ISrcIdList::const_iterator it = sourcerank.begin();
510 it != sourcerank.end(); ++it, ++prio ) {
511 rankPriority[(*it)->descr()->default_rank()] = prio;
516 ///////////////////////////////////////////////////////////////////
517 // Compute install order according to packages prereq.
518 // Try to group packages with respect to the desired install order
519 ///////////////////////////////////////////////////////////////////
520 // backup list for debug purpose.
521 // You can as well build the set, clear the list and rebuild it in install order.
522 PoolItemList instbackup_r;
523 instbackup_r.swap( instlist_r );
525 PoolItemList ilist; // for install order
526 PoolItemList installed; // dummy, empty, should contain already installed
527 for ( PoolItemList::iterator resIt = instbackup_r.begin(); resIt != instbackup_r.end(); ++resIt ) {
528 ilist.push_back( *resIt );
530 InstallOrder order( pool_r, ilist, installed );
531 // start recursive depth-first-search
534 ///////////////////////////////////////////////////////////////////
535 // build install list in install order
536 ///////////////////////////////////////////////////////////////////
537 PoolItemList best_list;
538 // unsigned best_prio = 0;
539 unsigned best_medianum = 0;
541 PoolItemList last_list;
542 // unsigned last_prio = 0;
543 unsigned last_medianum = 0;
545 PoolItemList other_list;
547 for ( PoolItemList items = order.computeNextSet(); ! items.empty(); items = order.computeNextSet() )
549 MIL << "order.computeNextSet: " << items.size() << " resolvables" << endl;
550 ///////////////////////////////////////////////////////////////////
551 // items contains all packages we could install now. Pick all packages
552 // from current media, or best media if none for current.
553 ///////////////////////////////////////////////////////////////////
559 for ( PoolItemList::iterator cit = items.begin(); cit != items.end(); ++cit )
561 Resolvable::constPtr res( cit->resolvable() );
562 Package::constPtr cpkg( asKind<Package>(res) );
564 MIL << "Not a package " << *cit << endl;
565 order.setInstalled( *cit );
566 other_list.push_back( *cit );
569 MIL << "Package " << *cpkg << ", media " << cpkg->mediaId() << endl;
570 if ( // rankPriority[cpkg->instSrcRank()] == last_prio &&
571 cpkg->mediaId() == last_medianum ) {
572 // prefer packages on current media.
573 last_list.push_back( *cit );
577 if ( last_list.empty() ) {
578 // check for best media as long as there are no packages for current media.
580 if ( ! best_list.empty() ) {
583 if ( rankPriority[cpkg->instSrcRank()] < best_prio ) {
584 best_list.clear(); // new best
585 } else if ( rankPriority[cpkg->instSrcRank()] == best_prio ) {
588 if ( cpkg->mediaId() < best_medianum ) {
589 best_list.clear(); // new best
590 } else if ( cpkg->mediaId() == best_medianum ) {
591 best_list.push_back( *cit ); // same as best -> add
603 if ( best_list.empty() )
605 // first package or new best
606 best_list.push_back( *cit );
607 // best_prio = rankPriority[cpkg->instSrcRank()];
608 best_medianum = cpkg->mediaId();
613 } // for all packages in current set
615 ///////////////////////////////////////////////////////////////////
616 // remove packages picked from install order and append them to
618 ///////////////////////////////////////////////////////////////////
619 PoolItemList & take_list( last_list.empty() ? best_list : last_list );
620 if ( last_list.empty() )
622 MIL << "SET NEW media " << best_medianum << endl;
623 // last_prio = best_prio;
624 last_medianum = best_medianum;
628 MIL << "SET CONTINUE" << endl;
631 for ( PoolItemList::iterator it = take_list.begin(); it != take_list.end(); ++it )
633 order.setInstalled( *it );
634 MIL << "SET isrc " << (*it) << endl;
636 // move everthing from take_list to the end of instlist_r, clean take_list
637 instlist_r.splice( instlist_r.end(), take_list );
638 // same for other_list
639 instlist_r.splice( instlist_r.end(), other_list );
641 } // for all sets computed
644 if ( instbackup_r.size() != instlist_r.size() )
646 INT << "Lost packages in InstallOrder sort." << endl;
648 instlist_r.splice( instlist_r.end(), nonpkglist );
652 /////////////////////////////////////////////////////////////////
653 } // namespace target
654 ///////////////////////////////////////////////////////////////////
655 /////////////////////////////////////////////////////////////////
657 ///////////////////////////////////////////////////////////////////