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 commit( to_install );
129 commit( to_srcinstall );
132 PoolItemList current_install;
134 for (PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it) {
135 Resolvable::constPtr res( it->resolvable() );
136 Package::constPtr pkg( asKind<Package>(res) );
138 && medianr != pkg->mediaId()) // check medianr for packages only
140 MIL << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
141 remaining_r.push_back( *it );
144 current_install.push_back( *it );
147 for (PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it) {
148 Resolvable::constPtr res( it->resolvable() );
149 Package::constPtr pkg( asKind<Package>(res) );
151 && medianr != pkg->mediaId()) // check medianr for packages only
153 MIL << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
154 srcremaining_r.push_back( *it );
157 current_install.push_back( *it );
160 commit (current_install);
167 void TargetImpl::commit(const PoolItemList & items_r)
169 MIL << "TargetImpl::commit(<list>)" << endl;
170 for (PoolItemList::const_iterator it = items_r.begin();
171 it != items_r.end(); it++)
173 if (isKind<Package>(it->resolvable()))
175 Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
176 if (it->status().isToBeInstalled())
178 Pathname localfile = getRpmFile(p);
180 #warning Exception handling
181 // create a installation progress report proxy
182 RpmInstallPackageReceiver progress(it->resolvable());
187 progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
189 rpm().installPackage(localfile,
190 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : 0);
192 catch (Exception & excpt_r) {
193 ZYPP_CAUGHT(excpt_r);
195 WAR << "Install failed, retrying with --nodeps" << endl;
197 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
198 rpm().installPackage(localfile,
199 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : rpm::RpmDb::RPMINST_NODEPS);
201 catch (Exception & excpt_r) {
202 ZYPP_CAUGHT(excpt_r);
203 WAR << "Install failed again, retrying with --force --nodeps" << endl;
206 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
207 rpm().installPackage(localfile,
208 p->installOnly() ? rpm::RpmDb::RPMINST_NOUPGRADE : (rpm::RpmDb::RPMINST_NODEPS|rpm::RpmDb::RPMINST_FORCE));
210 catch (Exception & excpt_r) {
211 progress.disconnect();
212 ZYPP_RETHROW(excpt_r);
217 progress.disconnect();
222 RpmRemovePackageReceiver progress(it->resolvable());
227 rpm().removePackage(p);
229 catch (Exception & excpt_r) {
230 ZYPP_CAUGHT(excpt_r);
231 WAR << "Remove failed, retrying with --nodeps" << endl;
232 rpm().removePackage(p, rpm::RpmDb::RPMINST_NODEPS);
234 progress.disconnect();
237 it->status().setStatus( ResStatus::uninstalled );
238 MIL << "Successful remove, " << *it << " is now uninstalled " << endl;
240 #warning FIXME other resolvables
245 rpm::RpmDb & TargetImpl::rpm()
248 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
249 { return _rpm.hasFile(path_str, name_str); }
251 /** Return the resolvable which provides path_str (rpm -qf)
252 return NULL if no resolvable provides this file */
253 ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
255 string name = _rpm.whoOwnsFile (path_str);
259 for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it) {
260 if ((*it)->name() == name) {
267 //-----------------------------------------------------------------------------
268 /******************************************************************
271 ** FUNCTION NAME : strip_obsoleted_to_delete
272 ** FUNCTION TYPE : void
274 ** strip packages to_delete which get obsoleted by
275 ** to_install (i.e. delay deletion in case the
276 ** obsoleting package likes to save whatever...
279 strip_obsoleted_to_delete( PoolItemList & deleteList_r,
280 const PoolItemList & instlist_r )
282 if ( deleteList_r.size() == 0 || instlist_r.size() == 0 )
283 return; // ---> nothing to do
285 // build obsoletes from instlist_r
287 for ( PoolItemList::const_iterator it = instlist_r.begin();
288 it != instlist_r.end(); ++it )
290 PoolItem_Ref item( *it );
291 obsoletes.insert( item->dep(Dep::OBSOLETES).begin(), item->dep(Dep::OBSOLETES).end() );
293 if ( obsoletes.size() == 0 )
294 return; // ---> nothing to do
297 PoolItemList undelayed;
298 // forall applDelete Packages...
299 for ( PoolItemList::iterator it = deleteList_r.begin();
300 it != deleteList_r.end(); ++it )
302 PoolItem_Ref ipkg( *it );
303 bool delayPkg = false;
304 // ...check whether an obsolets....
305 for ( CapSet::iterator obs = obsoletes.begin();
306 ! delayPkg && obs != obsoletes.end(); ++obs )
308 // ...matches anything provided by the package?
309 for ( CapSet::const_iterator prov = ipkg->dep(Dep::PROVIDES).begin();
310 prov != ipkg->dep(Dep::PROVIDES).end(); ++prov )
312 if ( obs->matches( *prov ) == CapMatch::yes )
314 // if so, delay package deletion
315 DBG << "Ignore appl_delete (should be obsoleted): " << ipkg << endl;
322 MIL << "undelayed " << ipkg << endl;
323 undelayed.push_back( ipkg );
327 deleteList_r.swap( undelayed );
334 TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
335 PoolItemList & dellist_r,
336 PoolItemList & instlist_r,
337 PoolItemList & srclist_r )
343 for ( ResPool::const_iterator it = pool_r.begin(); it != pool_r.end(); ++it )
345 if (it->status().isToBeInstalled())
347 if (it->resolvable()->arch() == Arch_src)
348 srclist_r.push_back( *it );
350 instlist_r.push_back( *it );
352 else if (it->status().isToBeUninstalled())
354 if ( it->status().isToBeUninstalledDueToObsolete() )
356 DBG << "Ignore auto_delete (should be obsoleted): " << *it << endl;
358 dellist_r.push_back( *it );
363 MIL << "PackagesToInsDel: delete " << dellist_r.size()
364 << ", install " << instlist_r.size()
365 << ", srcinstall " << srclist_r.size() << endl;
367 ///////////////////////////////////////////////////////////////////
369 // strip packages to_delete which get obsoleted by
370 // to_install (i.e. delay deletion in case the
371 // obsoleting package likes to save whatever...
373 ///////////////////////////////////////////////////////////////////
374 strip_obsoleted_to_delete( dellist_r, instlist_r );
376 if ( dellist_r.size() ) {
377 ///////////////////////////////////////////////////////////////////
379 // sort delete list...
381 ///////////////////////////////////////////////////////////////////
382 PoolItemList dlist; // for delete order
383 PoolItemList dummy; // dummy, empty, should contain already installed
384 for ( PoolItemList::iterator pkgIt = dellist_r.begin();
385 pkgIt != dellist_r.end(); ++pkgIt )
387 dlist.push_back( *pkgIt );
390 InstallOrder order( pool_r, dlist, dummy ); // sort according top prereq
392 const PoolItemList dsorted( order.getTopSorted() );
395 for ( PoolItemList::const_reverse_iterator cit = dsorted.rbegin();
396 cit != dsorted.rend(); ++cit )
398 dellist_r.push_back( *cit );
402 ///////////////////////////////////////////////////////////////////
404 // sort installed list...
406 ///////////////////////////////////////////////////////////////////
407 if ( instlist_r.empty() ) {
410 #warning Source Rank Priority ?
412 ///////////////////////////////////////////////////////////////////
413 // Get desired order of InstSrc'es to install from.
414 ///////////////////////////////////////////////////////////////////
415 typedef map<unsigned,unsigned> RankPriority;
417 RankPriority rankPriority;
419 InstSrcManager::ISrcIdList sourcerank( Y2PM::instSrcManager().instOrderSources() );
420 // map InstSrc rank to install priority
422 for ( InstSrcManager::ISrcIdList::const_iterator it = sourcerank.begin();
423 it != sourcerank.end(); ++it, ++prio ) {
424 rankPriority[(*it)->descr()->default_rank()] = prio;
429 ///////////////////////////////////////////////////////////////////
430 // Compute install order according to packages prereq.
431 // Try to group packages with respect to the desired install order
432 ///////////////////////////////////////////////////////////////////
433 // backup list for debug purpose.
434 // You can as well build the set, clear the list and rebuild it in install order.
435 PoolItemList instbackup_r;
436 instbackup_r.swap( instlist_r );
438 PoolItemList ilist; // for install order
439 PoolItemList installed; // dummy, empty, should contain already installed
440 for ( PoolItemList::iterator pkgIt = instbackup_r.begin(); pkgIt != instbackup_r.end(); ++pkgIt ) {
441 ilist.push_back( *pkgIt );
443 InstallOrder order( pool_r, ilist, installed );
444 // start recursive depth-first-search
447 ///////////////////////////////////////////////////////////////////
448 // build install list in install order
449 ///////////////////////////////////////////////////////////////////
450 PoolItemList best_list;
451 // unsigned best_prio = 0;
452 unsigned best_medianum = 0;
454 PoolItemList last_list;
455 // unsigned last_prio = 0;
456 unsigned last_medianum = 0;
458 for ( PoolItemList pkgs = order.computeNextSet(); ! pkgs.empty(); pkgs = order.computeNextSet() )
460 MIL << "order.computeNextSet: " << pkgs.size() << " packages" << endl;
461 ///////////////////////////////////////////////////////////////////
462 // pkgs contains all packages we could install now. Pick all packages
463 // from current media, or best media if none for current.
464 ///////////////////////////////////////////////////////////////////
469 for ( PoolItemList::iterator cit = pkgs.begin(); cit != pkgs.end(); ++cit )
471 Resolvable::constPtr res( cit->resolvable() );
472 Package::constPtr cpkg( asKind<Package>(res) );
474 MIL << "Packge " << cpkg << ", media " << cpkg->mediaId() << endl;
475 if ( // rankPriority[cpkg->instSrcRank()] == last_prio &&
476 cpkg->mediaId() == last_medianum ) {
477 // prefer packages on current media.
478 last_list.push_back( *cit );
482 if ( last_list.empty() ) {
483 // check for best media as long as there are no packages for current media.
485 if ( ! best_list.empty() ) {
488 if ( rankPriority[cpkg->instSrcRank()] < best_prio ) {
489 best_list.clear(); // new best
490 } else if ( rankPriority[cpkg->instSrcRank()] == best_prio ) {
493 if ( cpkg->mediaId() < best_medianum ) {
494 best_list.clear(); // new best
495 } else if ( cpkg->mediaId() == best_medianum ) {
496 best_list.push_back( *cit ); // same as best -> add
508 if ( best_list.empty() )
510 // first package or new best
511 best_list.push_back( *cit );
512 // best_prio = rankPriority[cpkg->instSrcRank()];
513 best_medianum = cpkg->mediaId();
518 } // for all packages in current set
520 ///////////////////////////////////////////////////////////////////
521 // remove packages picked from install order and append them to
523 ///////////////////////////////////////////////////////////////////
524 PoolItemList & take_list( last_list.empty() ? best_list : last_list );
525 if ( last_list.empty() )
527 MIL << "SET NEW media " << best_medianum << endl;
528 // last_prio = best_prio;
529 last_medianum = best_medianum;
533 MIL << "SET CONTINUE" << endl;
536 for ( PoolItemList::iterator it = take_list.begin(); it != take_list.end(); ++it )
538 order.setInstalled( *it );
539 MIL << "SET isrc " << (*it) << endl;
541 instlist_r.splice( instlist_r.end(), take_list );
543 } // for all sets computed
546 if ( instbackup_r.size() != instlist_r.size() )
548 INT << "Lost packages in InstallOrder sort." << endl;
554 /////////////////////////////////////////////////////////////////
555 } // namespace target
556 ///////////////////////////////////////////////////////////////////
557 /////////////////////////////////////////////////////////////////
559 ///////////////////////////////////////////////////////////////////