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 const ResStore & TargetImpl::resolvables()
80 std::list<Package::Ptr> packages = _rpm.getPackages();
81 for (std::list<Package::Ptr>::const_iterator it = packages.begin();
87 // TODO objects from the XML store
92 Pathname TargetImpl::getRpmFile(Package::constPtr package)
94 callback::SendReport<source::DownloadResolvableReport> report;
96 // FIXME: error handling
98 report->start( package, Url() );
100 Pathname file = package->getPlainRpm();
102 report->finish( package, source::DownloadResolvableReport::NO_ERROR, "" );
108 void TargetImpl::commit(ResPool pool_r, unsigned int medianr, PoolItemList & errors_r, PoolItemList & remaining_r, PoolItemList & srcremaining_r)
110 MIL << "TargetImpl::commit(<pool>, " << medianr << ")" << endl;
114 srcremaining_r.clear();
116 PoolItemList to_uninstall;
117 PoolItemList to_install;
118 PoolItemList to_srcinstall;
119 getResolvablesToInsDel( pool_r, to_uninstall, to_install, to_srcinstall );
122 MIL << "Restrict to media number " << medianr << endl;
125 commit (to_uninstall);
127 if (medianr == 0) { // commit all
128 remaining_r = commit( to_install );
129 srcremaining_r = commit( to_srcinstall );
132 PoolItemList current_install;
133 PoolItemList current_srcinstall;
135 for (PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it) {
136 Resolvable::constPtr res( it->resolvable() );
137 Package::constPtr pkg( asKind<Package>(res) );
139 && medianr != pkg->mediaId()) // check medianr for packages only
141 MIL << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
142 remaining_r.push_back( *it );
145 current_install.push_back( *it );
148 PoolItemList bad = commit (current_install);
149 remaining_r.insert(remaining_r.end(), bad.begin(), bad.end());
151 for (PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it) {
152 Resolvable::constPtr res( it->resolvable() );
153 Package::constPtr pkg( asKind<Package>(res) );
155 && medianr != pkg->mediaId()) // check medianr for packages only
157 MIL << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
158 srcremaining_r.push_back( *it );
161 current_srcinstall.push_back( *it );
164 bad = commit (current_srcinstall);
165 srcremaining_r.insert(remaining_r.end(), bad.begin(), bad.end());
173 TargetImpl::commit( const PoolItemList & items_r)
175 PoolItemList remaining;
177 MIL << "TargetImpl::commit(<list>)" << endl;
178 for (PoolItemList::const_iterator it = items_r.begin();
179 it != items_r.end(); it++)
181 if (isKind<Package>(it->resolvable()))
183 Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
184 if (it->status().isToBeInstalled())
186 Pathname localfile = getRpmFile(p);
188 #warning Exception handling
189 // create a installation progress report proxy
190 RpmInstallPackageReceiver progress(it->resolvable());
196 progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
198 rpm().installPackage(localfile,
199 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : 0);
201 catch (Exception & excpt_r) {
202 ZYPP_CAUGHT(excpt_r);
204 WAR << "Install failed, retrying with --nodeps" << endl;
206 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
207 rpm().installPackage(localfile,
208 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : rpm::RpmDb::RPMINST_NODEPS);
210 catch (Exception & excpt_r) {
211 ZYPP_CAUGHT(excpt_r);
212 WAR << "Install failed again, retrying with --force --nodeps" << endl;
215 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
216 rpm().installPackage(localfile,
217 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : (rpm::RpmDb::RPMINST_NODEPS|rpm::RpmDb::RPMINST_FORCE));
219 catch (Exception & excpt_r) {
220 remaining.push_back( *it );
222 ZYPP_CAUGHT(excpt_r);
227 it->status().setStatus( ResStatus::installed );
229 progress.disconnect();
234 RpmRemovePackageReceiver progress(it->resolvable());
239 rpm().removePackage(p);
241 catch (Exception & excpt_r) {
242 ZYPP_CAUGHT(excpt_r);
243 WAR << "Remove failed, retrying with --nodeps" << endl;
244 rpm().removePackage(p, rpm::RpmDb::RPMINST_NODEPS);
246 progress.disconnect();
247 it->status().setStatus( ResStatus::uninstalled );
251 #warning FIXME other resolvables
258 rpm::RpmDb & TargetImpl::rpm()
261 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
262 { return _rpm.hasFile(path_str, name_str); }
264 /** Return the resolvable which provides path_str (rpm -qf)
265 return NULL if no resolvable provides this file */
266 ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
268 string name = _rpm.whoOwnsFile (path_str);
272 for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it) {
273 if ((*it)->name() == name) {
280 //-----------------------------------------------------------------------------
281 /******************************************************************
284 ** FUNCTION NAME : strip_obsoleted_to_delete
285 ** FUNCTION TYPE : void
287 ** strip packages to_delete which get obsoleted by
288 ** to_install (i.e. delay deletion in case the
289 ** obsoleting package likes to save whatever...
292 strip_obsoleted_to_delete( PoolItemList & deleteList_r,
293 const PoolItemList & instlist_r )
295 if ( deleteList_r.size() == 0 || instlist_r.size() == 0 )
296 return; // ---> nothing to do
298 // build obsoletes from instlist_r
300 for ( PoolItemList::const_iterator it = instlist_r.begin();
301 it != instlist_r.end(); ++it )
303 PoolItem_Ref item( *it );
304 obsoletes.insert( item->dep(Dep::OBSOLETES).begin(), item->dep(Dep::OBSOLETES).end() );
306 if ( obsoletes.size() == 0 )
307 return; // ---> nothing to do
310 PoolItemList undelayed;
311 // forall applDelete Packages...
312 for ( PoolItemList::iterator it = deleteList_r.begin();
313 it != deleteList_r.end(); ++it )
315 PoolItem_Ref ipkg( *it );
316 bool delayPkg = false;
317 // ...check whether an obsolets....
318 for ( CapSet::iterator obs = obsoletes.begin();
319 ! delayPkg && obs != obsoletes.end(); ++obs )
321 // ...matches anything provided by the package?
322 for ( CapSet::const_iterator prov = ipkg->dep(Dep::PROVIDES).begin();
323 prov != ipkg->dep(Dep::PROVIDES).end(); ++prov )
325 if ( obs->matches( *prov ) == CapMatch::yes )
327 // if so, delay package deletion
328 DBG << "Ignore appl_delete (should be obsoleted): " << ipkg << endl;
335 MIL << "undelayed " << ipkg << endl;
336 undelayed.push_back( ipkg );
340 deleteList_r.swap( undelayed );
347 TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
348 PoolItemList & dellist_r,
349 PoolItemList & instlist_r,
350 PoolItemList & srclist_r )
356 for ( ResPool::const_iterator it = pool_r.begin(); it != pool_r.end(); ++it )
358 if (it->status().isToBeInstalled())
360 if (it->resolvable()->arch() == Arch_src)
361 srclist_r.push_back( *it );
363 instlist_r.push_back( *it );
365 else if (it->status().isToBeUninstalled())
367 if ( it->status().isToBeUninstalledDueToObsolete() )
369 DBG << "Ignore auto_delete (should be obsoleted): " << *it << endl;
371 dellist_r.push_back( *it );
376 MIL << "PackagesToInsDel: delete " << dellist_r.size()
377 << ", install " << instlist_r.size()
378 << ", srcinstall " << srclist_r.size() << endl;
380 ///////////////////////////////////////////////////////////////////
382 // strip packages to_delete which get obsoleted by
383 // to_install (i.e. delay deletion in case the
384 // obsoleting package likes to save whatever...
386 ///////////////////////////////////////////////////////////////////
387 strip_obsoleted_to_delete( dellist_r, instlist_r );
389 if ( dellist_r.size() ) {
390 ///////////////////////////////////////////////////////////////////
392 // sort delete list...
394 ///////////////////////////////////////////////////////////////////
395 PoolItemList dlist; // for delete order
396 PoolItemList dummy; // dummy, empty, should contain already installed
397 for ( PoolItemList::iterator pkgIt = dellist_r.begin();
398 pkgIt != dellist_r.end(); ++pkgIt )
400 dlist.push_back( *pkgIt );
403 InstallOrder order( pool_r, dlist, dummy ); // sort according top prereq
405 const PoolItemList dsorted( order.getTopSorted() );
408 for ( PoolItemList::const_reverse_iterator cit = dsorted.rbegin();
409 cit != dsorted.rend(); ++cit )
411 dellist_r.push_back( *cit );
415 ///////////////////////////////////////////////////////////////////
417 // sort installed list...
419 ///////////////////////////////////////////////////////////////////
420 if ( instlist_r.empty() ) {
423 #warning Source Rank Priority ?
425 ///////////////////////////////////////////////////////////////////
426 // Get desired order of InstSrc'es to install from.
427 ///////////////////////////////////////////////////////////////////
428 typedef map<unsigned,unsigned> RankPriority;
430 RankPriority rankPriority;
432 InstSrcManager::ISrcIdList sourcerank( Y2PM::instSrcManager().instOrderSources() );
433 // map InstSrc rank to install priority
435 for ( InstSrcManager::ISrcIdList::const_iterator it = sourcerank.begin();
436 it != sourcerank.end(); ++it, ++prio ) {
437 rankPriority[(*it)->descr()->default_rank()] = prio;
442 ///////////////////////////////////////////////////////////////////
443 // Compute install order according to packages prereq.
444 // Try to group packages with respect to the desired install order
445 ///////////////////////////////////////////////////////////////////
446 // backup list for debug purpose.
447 // You can as well build the set, clear the list and rebuild it in install order.
448 PoolItemList instbackup_r;
449 instbackup_r.swap( instlist_r );
451 PoolItemList ilist; // for install order
452 PoolItemList installed; // dummy, empty, should contain already installed
453 for ( PoolItemList::iterator pkgIt = instbackup_r.begin(); pkgIt != instbackup_r.end(); ++pkgIt ) {
454 ilist.push_back( *pkgIt );
456 InstallOrder order( pool_r, ilist, installed );
457 // start recursive depth-first-search
460 ///////////////////////////////////////////////////////////////////
461 // build install list in install order
462 ///////////////////////////////////////////////////////////////////
463 PoolItemList best_list;
464 // unsigned best_prio = 0;
465 unsigned best_medianum = 0;
467 PoolItemList last_list;
468 // unsigned last_prio = 0;
469 unsigned last_medianum = 0;
471 for ( PoolItemList pkgs = order.computeNextSet(); ! pkgs.empty(); pkgs = order.computeNextSet() )
473 MIL << "order.computeNextSet: " << pkgs.size() << " packages" << endl;
474 ///////////////////////////////////////////////////////////////////
475 // pkgs contains all packages we could install now. Pick all packages
476 // from current media, or best media if none for current.
477 ///////////////////////////////////////////////////////////////////
482 for ( PoolItemList::iterator cit = pkgs.begin(); cit != pkgs.end(); ++cit )
484 Resolvable::constPtr res( cit->resolvable() );
485 Package::constPtr cpkg( asKind<Package>(res) );
487 MIL << "Packge " << cpkg << ", media " << cpkg->mediaId() << endl;
488 if ( // rankPriority[cpkg->instSrcRank()] == last_prio &&
489 cpkg->mediaId() == last_medianum ) {
490 // prefer packages on current media.
491 last_list.push_back( *cit );
495 if ( last_list.empty() ) {
496 // check for best media as long as there are no packages for current media.
498 if ( ! best_list.empty() ) {
501 if ( rankPriority[cpkg->instSrcRank()] < best_prio ) {
502 best_list.clear(); // new best
503 } else if ( rankPriority[cpkg->instSrcRank()] == best_prio ) {
506 if ( cpkg->mediaId() < best_medianum ) {
507 best_list.clear(); // new best
508 } else if ( cpkg->mediaId() == best_medianum ) {
509 best_list.push_back( *cit ); // same as best -> add
521 if ( best_list.empty() )
523 // first package or new best
524 best_list.push_back( *cit );
525 // best_prio = rankPriority[cpkg->instSrcRank()];
526 best_medianum = cpkg->mediaId();
531 } // for all packages in current set
533 ///////////////////////////////////////////////////////////////////
534 // remove packages picked from install order and append them to
536 ///////////////////////////////////////////////////////////////////
537 PoolItemList & take_list( last_list.empty() ? best_list : last_list );
538 if ( last_list.empty() )
540 MIL << "SET NEW media " << best_medianum << endl;
541 // last_prio = best_prio;
542 last_medianum = best_medianum;
546 MIL << "SET CONTINUE" << endl;
549 for ( PoolItemList::iterator it = take_list.begin(); it != take_list.end(); ++it )
551 order.setInstalled( *it );
552 MIL << "SET isrc " << (*it) << endl;
554 instlist_r.splice( instlist_r.end(), take_list );
556 } // for all sets computed
559 if ( instbackup_r.size() != instlist_r.size() )
561 INT << "Lost packages in InstallOrder sort." << endl;
567 /////////////////////////////////////////////////////////////////
568 } // namespace target
569 ///////////////////////////////////////////////////////////////////
570 /////////////////////////////////////////////////////////////////
572 ///////////////////////////////////////////////////////////////////