00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <sys/types.h>
00013 #include <sys/stat.h>
00014
00015 #include <iostream>
00016 #include <string>
00017 #include <list>
00018 #include <set>
00019
00020 #include "zypp/base/Logger.h"
00021 #include "zypp/base/Exception.h"
00022 #include "zypp/base/Gettext.h"
00023 #include "zypp/PoolItem.h"
00024 #include "zypp/Resolvable.h"
00025 #include "zypp/ResObject.h"
00026 #include "zypp/Package.h"
00027 #include "zypp/Script.h"
00028 #include "zypp/Message.h"
00029 #include "zypp/Source.h"
00030 #include "zypp/Url.h"
00031
00032 #include "zypp/target/TargetImpl.h"
00033 #include "zypp/target/TargetCallbackReceiver.h"
00034
00035 #include "zypp/solver/detail/Helper.h"
00036 #include "zypp/solver/detail/InstallOrder.h"
00037
00038 using namespace std;
00039 using zypp::solver::detail::Helper;
00040 using zypp::solver::detail::InstallOrder;
00041
00043 namespace zypp
00044 {
00045
00046 namespace target
00047 {
00048
00050 namespace
00051 {
00052
00053 struct PubKeyHelper
00054 {
00055 };
00056
00058 }
00060
00061 IMPL_PTR_TYPE(TargetImpl);
00062
00063 TargetImpl_Ptr TargetImpl::_nullimpl;
00064
00066 TargetImpl_Ptr TargetImpl::nullimpl()
00067 {
00068 if (_nullimpl == 0)
00069 _nullimpl = new TargetImpl;
00070 return _nullimpl;
00071 }
00072
00073
00075
00076
00077
00078
00079 TargetImpl::TargetImpl(const Pathname & root_r)
00080 : _root(root_r)
00081 {
00082 _rpm.initDatabase(_root);
00083 _storage_enabled = false;
00084 MIL << "Initialized target on " << _root << endl;
00085 }
00086
00088
00089
00090
00091
00092 TargetImpl::~TargetImpl()
00093 {
00094 _rpm.closeDatabase();
00095 MIL << "Targets closed" << endl;
00096 }
00097
00098 bool TargetImpl::isStorageEnabled() const
00099 {
00100 return _storage_enabled;
00101 }
00102
00103
00104 void TargetImpl::enableStorage(const Pathname &root_r)
00105 {
00106 _storage.init(root_r);
00107 _storage_enabled = true;
00108 }
00109
00110 Pathname TargetImpl::root() const
00111 {
00112 return _root;
00113 }
00114
00115 const ResStore & TargetImpl::resolvables()
00116 {
00117 _store.clear();
00118
00119 std::list<Package::Ptr> packages = _rpm.getPackages();
00120 for (std::list<Package::Ptr>::const_iterator it = packages.begin();
00121 it != packages.end();
00122 it++)
00123 {
00124 _store.insert(*it);
00125 }
00126
00127 if ( isStorageEnabled() )
00128 {
00129
00130 std::list<ResObject::Ptr> resolvables = _storage.storedObjects();
00131 for (std::list<ResObject::Ptr>::iterator it = resolvables.begin();
00132 it != resolvables.end();
00133 it++)
00134 {
00135 _store.insert(*it);
00136 }
00137 }
00138 else
00139 {
00140 WAR << "storage target not enabled" << std::endl;
00141 }
00142
00143 return _store;
00144 }
00145
00146
00147
00148 ZYppCommitResult TargetImpl::commit( ResPool pool_r, const ZYppCommitPolicy & policy_r )
00149 {
00150 MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
00151 ZYppCommitResult result;
00152 #warning Commit does not provide ZYppCommitResult::_errors
00153
00154 TargetImpl::PoolItemList to_uninstall;
00155 TargetImpl::PoolItemList to_install;
00156 TargetImpl::PoolItemList to_srcinstall;
00157 getResolvablesToInsDel( pool_r, to_uninstall, to_install, to_srcinstall );
00158
00159 if ( policy_r.restrictToMedia() ) {
00160 MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
00161 }
00162
00163 commit (to_uninstall, policy_r, pool_r );
00164
00165 if (policy_r.restrictToMedia() == 0) {
00166 result._remaining = commit( to_install, policy_r, pool_r );
00167 result._srcremaining = commit( to_srcinstall, policy_r, pool_r );
00168 }
00169 else
00170 {
00171 TargetImpl::PoolItemList current_install;
00172 TargetImpl::PoolItemList current_srcinstall;
00173
00174 for (TargetImpl::PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it)
00175 {
00176 Resolvable::constPtr res( it->resolvable() );
00177 Package::constPtr pkg( asKind<Package>(res) );
00178 if (pkg && policy_r.restrictToMedia() != pkg->mediaId())
00179 {
00180 XXX << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
00181 result._remaining.push_back( *it );
00182 }
00183 else
00184 {
00185 current_install.push_back( *it );
00186 }
00187 }
00188 TargetImpl::PoolItemList bad = commit( current_install, policy_r, pool_r );
00189 result._remaining.insert(result._remaining.end(), bad.begin(), bad.end());
00190
00191 for (TargetImpl::PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
00192 {
00193 Resolvable::constPtr res( it->resolvable() );
00194 Package::constPtr pkg( asKind<Package>(res) );
00195 if (pkg && policy_r.restrictToMedia() != pkg->mediaId())
00196 {
00197 XXX << "Package " << *pkg << ", wrong media " << pkg->mediaId() << endl;
00198 result._srcremaining.push_back( *it );
00199 }
00200 else {
00201 current_srcinstall.push_back( *it );
00202 }
00203 }
00204 bad = commit( current_srcinstall, policy_r, pool_r );
00205 result._srcremaining.insert(result._srcremaining.end(), bad.begin(), bad.end());
00206 }
00207
00208
00209 result._result = (to_install.size() - result._remaining.size());
00210 return result;
00211 }
00212
00213
00214 TargetImpl::PoolItemList
00215 TargetImpl::commit( const TargetImpl::PoolItemList & items_r,
00216 const ZYppCommitPolicy & policy_r,
00217 const ResPool & pool_r )
00218 {
00219 TargetImpl::PoolItemList remaining;
00220
00221 MIL << "TargetImpl::commit(<list>" << policy_r << ")" << endl;
00222
00223 bool abort = false;
00224
00225
00226 Source_Ref lastUsedSource;
00227
00228 for (TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
00229 {
00230 if (isKind<Package>(it->resolvable()))
00231 {
00232 Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
00233 if (it->status().isToBeInstalled())
00234 {
00235 Pathname localfile;
00236 try {
00237 localfile = p->source().providePackage(p);
00238 }
00239 catch( const source::SkipRequestedException & e )
00240 {
00241 ZYPP_CAUGHT( e );
00242 WAR << "Skipping package " << p << " in commit" << endl;
00243 continue;
00244 }
00245
00246 lastUsedSource = p->source();
00247
00248 #warning Exception handling
00249
00250 RpmInstallPackageReceiver progress( it->resolvable() );
00251 progress.connect();
00252 bool success = true;
00253 unsigned flags = 0;
00254 if (p->installOnly()) flags |= rpm::RpmDb::RPMINST_NOUPGRADE;
00255 if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00256 if (policy_r.rpmNoSignature()) flags |= rpm::RpmDb::RPMINST_NOSIGNATURE;
00257
00258 try {
00259 progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
00260 rpm().installPackage( localfile, flags );
00261
00262 if( progress.aborted() )
00263 {
00264 WAR << "commit aborted by the user" << endl;
00265 progress.disconnect();
00266 abort = true;
00267 break;
00268 }
00269
00270 }
00271 catch (Exception & excpt_r) {
00272 ZYPP_CAUGHT(excpt_r);
00273 WAR << "Install failed, retrying with --nodeps" << endl;
00274 if (policy_r.dryRun()) {
00275 WAR << "dry run failed" << endl;
00276 progress.disconnect();
00277 break;
00278 }
00279
00280 try {
00281 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
00282 flags |= rpm::RpmDb::RPMINST_NODEPS;
00283 rpm().installPackage( localfile, flags );
00284
00285 if( progress.aborted() )
00286 {
00287 WAR << "commit aborted by the user" << endl;
00288 abort = true;
00289 progress.disconnect();
00290 break;
00291 }
00292 }
00293 catch (Exception & excpt_r)
00294 {
00295 ZYPP_CAUGHT(excpt_r);
00296 WAR << "Install failed again, retrying with --force --nodeps" << endl;
00297
00298 try {
00299 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
00300 flags |= rpm::RpmDb::RPMINST_FORCE;
00301 rpm().installPackage( localfile, flags );
00302 }
00303 catch (Exception & excpt_r) {
00304 remaining.push_back( *it );
00305 success = false;
00306 ZYPP_CAUGHT(excpt_r);
00307 }
00308
00309 if( progress.aborted() )
00310 {
00311 WAR << "commit aborted by the user" << endl;
00312 abort = true;
00313 progress.disconnect();
00314 break;
00315 }
00316 }
00317 }
00318 if (success
00319 && !policy_r.dryRun())
00320 {
00321 it->status().resetTransact( ResStatus::USER );
00322 }
00323 progress.disconnect();
00324 p->source().releaseFile( p->location(), p->mediaId() );
00325 }
00326 else
00327 {
00328 bool success = true;
00329
00330 RpmRemovePackageReceiver progress( it->resolvable() );
00331 progress.connect();
00332 unsigned flags = rpm::RpmDb::RPMINST_NODEPS;
00333 if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00334 try {
00335 rpm().removePackage( p, flags );
00336 }
00337 catch (Exception & excpt_r) {
00338 WAR << "removal of " << p << " failed";
00339 success = false;
00340 ZYPP_CAUGHT( excpt_r );
00341 }
00342 if (success
00343 && !policy_r.dryRun())
00344 {
00345 it->status().resetTransact( ResStatus::USER );
00346 }
00347 progress.disconnect();
00348 }
00349 }
00350 else if (!policy_r.dryRun())
00351 {
00352 if ( isStorageEnabled() )
00353 {
00354 if (it->status().isToBeInstalled())
00355 {
00356 bool success = false;
00357 try
00358 {
00359 if (isKind<Message>(it->resolvable()))
00360 {
00361 Message::constPtr m = dynamic_pointer_cast<const Message>(it->resolvable());
00362 std::string text = m->text().asString();
00363
00364 callback::SendReport<target::MessageResolvableReport> report;
00365
00366 report->show( m );
00367
00368 MIL << "Displaying the text '" << text << "'" << endl;
00369 }
00370 else if (isKind<Script>(it->resolvable()))
00371 {
00372 Script::constPtr s = dynamic_pointer_cast<const Script>(it->resolvable());
00373 Pathname p = s->do_script();
00374 if (p != "" && p != "/")
00375 {
00376 chmod( p.asString().c_str(), S_IRUSR|S_IXUSR );
00377 ExternalProgram* prog = new ExternalProgram(p.asString(), ExternalProgram::Discard_Stderr, false, -1, true);
00378 if (! prog)
00379 ZYPP_THROW(Exception("Cannot run the script"));
00380 int retval = prog->close();
00381 delete prog;
00382 if (retval != 0)
00383 ZYPP_THROW(Exception("Exit code of script is non-zero"));
00384 }
00385 else
00386 {
00387 ERR << "Do script not defined" << endl;
00388 }
00389 }
00390 else if (!isKind<Atom>(it->resolvable()))
00391 {
00392
00393 if (true)
00394 {
00395
00396
00397 PoolItem_Ref old = Helper::findInstalledItem (pool_r, *it);
00398 if (old)
00399 {
00400 _storage.deleteObject(old.resolvable());
00401 }
00402 }
00403 _storage.storeObject(it->resolvable());
00404 }
00405 success = true;
00406 }
00407 catch (Exception & excpt_r)
00408 {
00409 ZYPP_CAUGHT(excpt_r);
00410 WAR << "Install of Resolvable from storage failed" << endl;
00411 }
00412 if (success)
00413 it->status().resetTransact( ResStatus::USER );
00414 }
00415 else
00416 {
00417 bool success = false;
00418 try
00419 {
00420 if (isKind<Message>(it->resolvable()))
00421 {
00422 DBG << "Uninstalling message - no-op" << endl;
00423 }
00424 else if (isKind<Script>(it->resolvable()))
00425 {
00426 Script::constPtr s = dynamic_pointer_cast<const Script>(it->resolvable());
00427 Pathname p = s->undo_script();
00428 if (! s->undo_available())
00429 {
00430 DBG << "Undo script not available" << endl;
00431 }
00432 if (p != "" && p != "/")
00433 {
00434 ExternalProgram* prog = new ExternalProgram(p.asString(), ExternalProgram::Discard_Stderr, false, -1, true);
00435 if (! prog)
00436 ZYPP_THROW(Exception("Cannot run the script"));
00437 int retval = prog->close();
00438 delete prog;
00439 if (retval != 0)
00440 ZYPP_THROW(Exception("Exit code of script is non-zero"));
00441 }
00442 else
00443 {
00444 ERR << "Undo script not defined" << endl;
00445 }
00446 }
00447 else
00448 {
00449 _storage.deleteObject(it->resolvable());
00450 }
00451 success = true;
00452 }
00453 catch (Exception & excpt_r)
00454 {
00455 ZYPP_CAUGHT(excpt_r);
00456 WAR << "Uninstall of Resolvable from storage failed" << endl;
00457 }
00458 if (success)
00459 it->status().resetTransact( ResStatus::USER );
00460 }
00461 }
00462 else
00463 {
00464 WAR << "storage target disabled" << std::endl;
00465 }
00466
00467 }
00468
00469 }
00470
00471
00472
00473
00474
00475
00476
00477 if (lastUsedSource) {
00478 lastUsedSource.release();
00479 }
00480
00481 if( abort )
00482 ZYPP_THROW( TargetAbortedException( N_("Target commit aborted by user.") ) );
00483
00484 return remaining;
00485 }
00486
00487 rpm::RpmDb & TargetImpl::rpm()
00488 { return _rpm; }
00489
00490 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
00491 { return _rpm.hasFile(path_str, name_str); }
00492
00495 ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
00496 {
00497 string name = _rpm.whoOwnsFile (path_str);
00498 if (name.empty())
00499 return NULL;
00500
00501 for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it) {
00502 if ((*it)->name() == name) {
00503 return *it;
00504 }
00505 }
00506 return NULL;
00507 }
00508
00510 bool TargetImpl::setInstallationLogfile(const Pathname & path_r)
00511 {
00512 return rpm::RpmDb::setInstallationLogfile(path_r);
00513 }
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 static void
00528 strip_obsoleted_to_delete( TargetImpl::PoolItemList & deleteList_r,
00529 const TargetImpl::PoolItemList & instlist_r )
00530 {
00531 if ( deleteList_r.size() == 0 || instlist_r.size() == 0 )
00532 return;
00533
00534
00535 CapSet obsoletes;
00536 for ( TargetImpl::PoolItemList::const_iterator it = instlist_r.begin();
00537 it != instlist_r.end(); ++it )
00538 {
00539 PoolItem_Ref item( *it );
00540 obsoletes.insert( item->dep(Dep::OBSOLETES).begin(), item->dep(Dep::OBSOLETES).end() );
00541 }
00542 if ( obsoletes.size() == 0 )
00543 return;
00544
00545
00546 TargetImpl::PoolItemList undelayed;
00547
00548 for ( TargetImpl::PoolItemList::iterator it = deleteList_r.begin();
00549 it != deleteList_r.end(); ++it )
00550 {
00551 PoolItem_Ref ipkg( *it );
00552 bool delayPkg = false;
00553
00554 for ( CapSet::iterator obs = obsoletes.begin();
00555 ! delayPkg && obs != obsoletes.end(); ++obs )
00556 {
00557
00558 for ( CapSet::const_iterator prov = ipkg->dep(Dep::PROVIDES).begin();
00559 prov != ipkg->dep(Dep::PROVIDES).end(); ++prov )
00560 {
00561 if ( obs->matches( *prov ) == CapMatch::yes )
00562 {
00563
00564 DBG << "Ignore appl_delete (should be obsoleted): " << ipkg << endl;
00565 delayPkg = true;
00566 ipkg.status().resetTransact( ResStatus::USER );
00567 break;
00568 }
00569 }
00570 }
00571 if ( ! delayPkg ) {
00572 DBG << "undelayed " << ipkg << endl;
00573 undelayed.push_back( ipkg );
00574 }
00575 }
00576
00577 deleteList_r.swap( undelayed );
00578 }
00579
00580
00581
00582
00583 void
00584 TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
00585 TargetImpl::PoolItemList & dellist_r,
00586 TargetImpl::PoolItemList & instlist_r,
00587 TargetImpl::PoolItemList & srclist_r ) const
00588 {
00589 dellist_r.clear();
00590 instlist_r.clear();
00591 srclist_r.clear();
00592 TargetImpl::PoolItemList nonpkglist;
00593
00594 for ( ResPool::const_iterator it = pool_r.begin(); it != pool_r.end(); ++it )
00595 {
00596 if (it->status().isToBeInstalled())
00597 {
00598 if ((*it)->kind() == ResTraits<SrcPackage>::kind) {
00599 srclist_r.push_back( *it );
00600 }
00601 else if ((*it)->kind() != ResTraits<Package>::kind) {
00602 nonpkglist.push_back( *it );
00603 }
00604 else
00605 instlist_r.push_back( *it );
00606 }
00607 else if (it->status().isToBeUninstalled())
00608 {
00609 if ( it->status().isToBeUninstalledDueToObsolete() )
00610 {
00611 DBG << "Ignore auto_delete (should be obsoleted): " << *it << endl;
00612 }
00613 else if ( it->status().isToBeUninstalledDueToUpgrade() )
00614 {
00615 DBG << "Ignore auto_delete (should be upgraded): " << *it << endl;
00616 }
00617 else {
00618 dellist_r.push_back( *it );
00619 }
00620 }
00621 }
00622
00623 MIL << "ResolvablesToInsDel: delete " << dellist_r.size()
00624 << ", install " << instlist_r.size()
00625 << ", srcinstall " << srclist_r.size()
00626 << ", nonpkg " << nonpkglist.size() << endl;
00627
00629
00630
00631
00632
00633
00635 strip_obsoleted_to_delete( dellist_r, instlist_r );
00636
00637 if ( dellist_r.size() ) {
00639
00640
00641
00643 TargetImpl::PoolItemSet delset( dellist_r.begin(), dellist_r.end() );
00644 TargetImpl::PoolItemSet dummy;
00645
00646 InstallOrder order( pool_r, delset, dummy );
00647 order.init();
00648 const TargetImpl::PoolItemList dsorted( order.getTopSorted() );
00649
00650 dellist_r.clear();
00651 for ( TargetImpl::PoolItemList::const_reverse_iterator cit = dsorted.rbegin();
00652 cit != dsorted.rend(); ++cit )
00653 {
00654 dellist_r.push_back( *cit );
00655 }
00656 }
00657
00659
00660
00661
00663 if ( instlist_r.empty() ) {
00664 instlist_r.splice( instlist_r.end(), nonpkglist );
00665
00666 return;
00667 }
00668 #warning Source Rank Priority ?
00669 #if 0
00670
00671
00673 typedef map<unsigned,unsigned> RankPriority;
00674
00675 RankPriority rankPriority;
00676 {
00677 InstSrcManager::ISrcIdList sourcerank( Y2PM::instSrcManager().instOrderSources() );
00678
00679 unsigned prio = 0;
00680 for ( InstSrcManager::ISrcIdList::const_iterator it = sourcerank.begin();
00681 it != sourcerank.end(); ++it, ++prio ) {
00682 rankPriority[(*it)->descr()->default_rank()] = prio;
00683 }
00684 }
00685 #endif
00686
00688
00689
00691
00692
00693 TargetImpl::PoolItemList instbackup_r;
00694 instbackup_r.swap( instlist_r );
00695
00696 TargetImpl::PoolItemSet insset( instbackup_r.begin(), instbackup_r.end() );
00697 TargetImpl::PoolItemSet installed;
00698
00699 InstallOrder order( pool_r, insset, installed );
00700
00701 order.init();
00702 MIL << "order.init() done" << endl;
00703 order.printAdj( XXX, false );
00705
00707 TargetImpl::PoolItemList best_list;
00708 unsigned best_prio = 0;
00709 unsigned best_medianum = 0;
00710
00711 TargetImpl::PoolItemList last_list;
00712 unsigned last_prio = 0;
00713 unsigned last_medianum = 0;
00714
00715 TargetImpl::PoolItemList other_list;
00716
00717 for ( TargetImpl::PoolItemList items = order.computeNextSet(); ! items.empty(); items = order.computeNextSet() )
00718 {
00719 MIL << "order.computeNextSet: " << items.size() << " resolvables" << endl;
00721
00722
00724
00725 best_list.clear();
00726 last_list.clear();
00727 other_list.clear();
00728
00729 for ( TargetImpl::PoolItemList::iterator cit = items.begin(); cit != items.end(); ++cit )
00730 {
00731 Resolvable::constPtr res( cit->resolvable() );
00732 if (!res) continue;
00733 Package::constPtr cpkg( asKind<Package>(res) );
00734 if (!cpkg) {
00735 XXX << "Not a package " << *cit << endl;
00736 order.setInstalled( *cit );
00737 other_list.push_back( *cit );
00738 continue;
00739 }
00740 XXX << "Package " << *cpkg << ", media " << cpkg->mediaId() << " last_medianum " << last_medianum << " best_medianum " << best_medianum << endl;
00741 if ( cpkg->source().numericId() == last_prio &&
00742 cpkg->mediaId() == last_medianum ) {
00743
00744 last_list.push_back( *cit );
00745 continue;
00746 }
00747
00748 if ( last_list.empty() ) {
00749
00750
00751 if ( ! best_list.empty() ) {
00752
00753 if ( cpkg->source().numericId() < best_prio ) {
00754 best_list.clear();
00755 } else if ( cpkg->source().numericId() == best_prio ) {
00756 if ( cpkg->mediaId() < best_medianum ) {
00757 best_list.clear();
00758 } else if ( cpkg->mediaId() == best_medianum ) {
00759 best_list.push_back( *cit );
00760 continue;
00761 } else {
00762 continue;
00763 }
00764 } else {
00765 continue;
00766 }
00767 }
00768
00769 if ( best_list.empty() )
00770 {
00771
00772 best_list.push_back( *cit );
00773 best_prio = cpkg->source().numericId();
00774 best_medianum = cpkg->mediaId();
00775 continue;
00776 }
00777 }
00778
00779 }
00780
00782
00783
00785 TargetImpl::PoolItemList & take_list( last_list.empty() ? best_list : last_list );
00786 if ( last_list.empty() )
00787 {
00788 MIL << "SET NEW media " << best_medianum << endl;
00789 last_prio = best_prio;
00790 last_medianum = best_medianum;
00791 }
00792 else
00793 {
00794 MIL << "SET CONTINUE" << endl;
00795 }
00796
00797 for ( TargetImpl::PoolItemList::iterator it = take_list.begin(); it != take_list.end(); ++it )
00798 {
00799 order.setInstalled( *it );
00800 XXX << "SET isrc " << (*it)->source().numericId() << " -> " << (*it) << endl;
00801 }
00802
00803 instlist_r.splice( instlist_r.end(), take_list );
00804
00805 instlist_r.splice( instlist_r.end(), other_list );
00806
00807 }
00808
00809
00810 if ( instbackup_r.size() != instlist_r.size() )
00811 {
00812 ERR << "***************** Lost packages in InstallOrder sort." << endl;
00813 }
00814 instlist_r.splice( instlist_r.end(), nonpkglist );
00815 }
00816
00817
00819 }
00822 }