00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013 #include <fstream>
00014 #include <sstream>
00015 #include <string>
00016 #include <list>
00017 #include <set>
00018
00019 #include <sys/types.h>
00020 #include <dirent.h>
00021
00022 #include "zypp/base/LogTools.h"
00023 #include "zypp/base/Exception.h"
00024 #include "zypp/base/Iterator.h"
00025 #include "zypp/base/Gettext.h"
00026 #include "zypp/base/IOStream.h"
00027 #include "zypp/base/Functional.h"
00028 #include "zypp/base/UserRequestException.h"
00029
00030 #include "zypp/ZConfig.h"
00031 #include "zypp/ZYppFactory.h"
00032
00033 #include "zypp/PoolItem.h"
00034 #include "zypp/ResObjects.h"
00035 #include "zypp/Url.h"
00036 #include "zypp/TmpPath.h"
00037 #include "zypp/RepoStatus.h"
00038 #include "zypp/ExternalProgram.h"
00039 #include "zypp/Repository.h"
00040
00041 #include "zypp/ResFilters.h"
00042 #include "zypp/HistoryLog.h"
00043 #include "zypp/target/TargetImpl.h"
00044 #include "zypp/target/TargetCallbackReceiver.h"
00045 #include "zypp/target/rpm/librpmDb.h"
00046 #include "zypp/target/CommitPackageCache.h"
00047
00048 #include "zypp/parser/ProductFileReader.h"
00049
00050 #include "zypp/pool/GetResolvablesToInsDel.h"
00051 #include "zypp/solver/detail/Testcase.h"
00052
00053 #include "zypp/repo/DeltaCandidates.h"
00054 #include "zypp/repo/PackageProvider.h"
00055 #include "zypp/repo/SrcPackageProvider.h"
00056
00057 #include "zypp/sat/Pool.h"
00058 #include "zypp/sat/Transaction.h"
00059
00060 #include "zypp/PluginScript.h"
00061
00062 using namespace std;
00063
00065 namespace zypp
00066 {
00067
00068 namespace target
00069 {
00070
00074 class CommitPlugins : private base::NonCopyable
00075 {
00076 public:
00077
00078 public:
00080 CommitPlugins()
00081 {}
00082
00084 ~CommitPlugins()
00085 {
00086 for_( it, _scripts.begin(), _scripts.end() )
00087 {
00088 MIL << "Unload plugin: " << *it << endl;
00089 try {
00090 it->send( PluginFrame( "PLUGINEND" ) );
00091 PluginFrame ret( it->receive() );
00092 if ( ! ret.isAckCommand() )
00093 {
00094 WAR << "Failed to unload plugin: Bad plugin response." << endl;
00095 }
00096 it->close();
00097 }
00098 catch( const zypp::Exception & )
00099 {
00100 WAR << "Failed to unload plugin." << endl;
00101 }
00102 }
00103
00104 }
00105
00112 void load( const Pathname & path_r )
00113 {
00114 PathInfo pi( path_r );
00115 if ( pi.isDir() )
00116 {
00117 std::list<Pathname> entries;
00118 if ( filesystem::readdir( entries, pi.path(), false ) != 0 )
00119 {
00120 WAR << "Plugin dir is not readable: " << pi << endl;
00121 return;
00122 }
00123 for_( it, entries.begin(), entries.end() )
00124 {
00125 PathInfo pii( *it );
00126 if ( pii.isFile() && pii.userMayRX() )
00127 doLoad( pii );
00128 }
00129 }
00130 else if ( pi.isFile() )
00131 {
00132 if ( pi.userMayRX() )
00133 doLoad( pi );
00134 else
00135 WAR << "Plugin file is not executable: " << pi << endl;
00136 }
00137 else
00138 {
00139 WAR << "Plugin path is neither dir nor file: " << pi << endl;
00140 }
00141 }
00142
00143 private:
00144 void doLoad( const PathInfo & pi_r )
00145 {
00146 MIL << "Load plugin: " << pi_r << endl;
00147 try {
00148 PluginScript plugin( pi_r.path() );
00149 plugin.open();
00150 plugin.send( PluginFrame( "PLUGINBEGIN" ) );
00151 PluginFrame ret( plugin.receive() );
00152 if ( ret.isAckCommand() )
00153 {
00154 _scripts.push_back( plugin );
00155 }
00156 else
00157 {
00158 WAR << "Failed to load plugin: Bad plugin response." << endl;
00159 }
00160 }
00161 catch( const zypp::Exception & )
00162 {
00163 WAR << "Failed to load plugin." << endl;
00164 }
00165 }
00166
00167 private:
00168 std::list<PluginScript> _scripts;
00169 };
00170
00171 void testCommitPlugins( const Pathname & path_r )
00172 {
00173 USR << "+++++" << endl;
00174 {
00175 CommitPlugins pl;
00176 pl.load( path_r );
00177 USR << "=====" << endl;
00178 }
00179 USR << "-----" << endl;
00180 }
00181
00183
00185 void writeUpgradeTestcase()
00186 {
00187 unsigned toKeep( ZConfig::instance().solver_upgradeTestcasesToKeep() );
00188 MIL << "Testcases to keep: " << toKeep << endl;
00189 if ( !toKeep )
00190 return;
00191 Target_Ptr target( getZYpp()->getTarget() );
00192 if ( ! target )
00193 {
00194 WAR << "No Target no Testcase!" << endl;
00195 return;
00196 }
00197
00198 std::string stem( "updateTestcase" );
00199 Pathname dir( target->assertRootPrefix("/var/log/") );
00200 Pathname next( dir / Date::now().form( stem+"-%Y-%m-%d-%H-%M-%S" ) );
00201
00202 {
00203 std::list<std::string> content;
00204 filesystem::readdir( content, dir, false );
00205 std::set<std::string> cases;
00206 for_( c, content.begin(), content.end() )
00207 {
00208 if ( str::startsWith( *c, stem ) )
00209 cases.insert( *c );
00210 }
00211 if ( cases.size() >= toKeep )
00212 {
00213 unsigned toDel = cases.size() - toKeep + 1;
00214 for_( c, cases.begin(), cases.end() )
00215 {
00216 filesystem::recursive_rmdir( dir/(*c) );
00217 if ( ! --toDel )
00218 break;
00219 }
00220 }
00221 }
00222
00223 MIL << "Write new testcase " << next << endl;
00224 getZYpp()->resolver()->createSolverTestcase( next.asString(), false );
00225 }
00226
00228 namespace
00229 {
00230
00241 std::pair<bool,PatchScriptReport::Action> doExecuteScript( const Pathname & root_r,
00242 const Pathname & script_r,
00243 callback::SendReport<PatchScriptReport> & report_r )
00244 {
00245 MIL << "Execute script " << PathInfo(Pathname::assertprefix( root_r,script_r)) << endl;
00246
00247 HistoryLog historylog;
00248 historylog.comment(script_r.asString() + _(" executed"), true);
00249 ExternalProgram prog( script_r.asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
00250
00251 for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() )
00252 {
00253 historylog.comment(output);
00254 if ( ! report_r->progress( PatchScriptReport::OUTPUT, output ) )
00255 {
00256 WAR << "User request to abort script " << script_r << endl;
00257 prog.kill();
00258
00259
00260 }
00261 }
00262
00263 std::pair<bool,PatchScriptReport::Action> ret( std::make_pair( false, PatchScriptReport::ABORT ) );
00264
00265 if ( prog.close() != 0 )
00266 {
00267 ret.second = report_r->problem( prog.execError() );
00268 WAR << "ACTION" << ret.second << "(" << prog.execError() << ")" << endl;
00269 std::ostringstream sstr;
00270 sstr << script_r << _(" execution failed") << " (" << prog.execError() << ")" << endl;
00271 historylog.comment(sstr.str(), true);
00272 return ret;
00273 }
00274
00275 report_r->finish();
00276 ret.first = true;
00277 return ret;
00278 }
00279
00283 bool executeScript( const Pathname & root_r,
00284 const Pathname & script_r,
00285 callback::SendReport<PatchScriptReport> & report_r )
00286 {
00287 std::pair<bool,PatchScriptReport::Action> action( std::make_pair( false, PatchScriptReport::ABORT ) );
00288
00289 do {
00290 action = doExecuteScript( root_r, script_r, report_r );
00291 if ( action.first )
00292 return true;
00293
00294 switch ( action.second )
00295 {
00296 case PatchScriptReport::ABORT:
00297 WAR << "User request to abort at script " << script_r << endl;
00298 return false;
00299 break;
00300
00301 case PatchScriptReport::IGNORE:
00302 WAR << "User request to skip script " << script_r << endl;
00303 return true;
00304 break;
00305
00306 case PatchScriptReport::RETRY:
00307 break;
00308 }
00309 } while ( action.second == PatchScriptReport::RETRY );
00310
00311
00312 INT << "Abort on unknown ACTION request " << action.second << " returned" << endl;
00313 return false;
00314 }
00315
00321 bool RunUpdateScripts( const Pathname & root_r,
00322 const Pathname & scriptsPath_r,
00323 const std::vector<sat::Solvable> & checkPackages_r,
00324 bool aborting_r )
00325 {
00326 if ( checkPackages_r.empty() )
00327 return true;
00328
00329 MIL << "Looking for new update scripts in (" << root_r << ")" << scriptsPath_r << endl;
00330 Pathname scriptsDir( Pathname::assertprefix( root_r, scriptsPath_r ) );
00331 if ( ! PathInfo( scriptsDir ).isDir() )
00332 return true;
00333
00334 std::list<std::string> scripts;
00335 filesystem::readdir( scripts, scriptsDir, false );
00336 if ( scripts.empty() )
00337 return true;
00338
00339
00340
00341
00342
00343 bool abort = false;
00344 std::map<std::string, Pathname> unify;
00345 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
00346 {
00347 std::string prefix( str::form( "%s-%s", it->name().c_str(), it->edition().c_str() ) );
00348 for_( sit, scripts.begin(), scripts.end() )
00349 {
00350 if ( ! str::hasPrefix( *sit, prefix ) )
00351 continue;
00352
00353 if ( (*sit)[prefix.size()] != '\0' && (*sit)[prefix.size()] != '-' )
00354 continue;
00355
00356 PathInfo script( scriptsDir / *sit );
00357 if ( ! script.isFile() )
00358 continue;
00359
00360
00361 filesystem::addmod( script.path(), 0500 );
00362
00363 Pathname localPath( scriptsPath_r/(*sit) );
00364
00365
00366 std::string md5sum( filesystem::md5sum( script.path() ) );
00367 if ( unify[md5sum].empty() )
00368 {
00369 unify[md5sum] = localPath;
00370 }
00371 else
00372 {
00373
00374
00375
00376 std::string msg( str::form(_("%s already executed as %s)"), localPath.asString().c_str(), unify[md5sum].c_str() ) );
00377 MIL << "Skip update script: " << msg << endl;
00378 HistoryLog().comment( msg, true );
00379 continue;
00380 }
00381
00382 if ( abort || aborting_r )
00383 {
00384 WAR << "Aborting: Skip update script " << *sit << endl;
00385 HistoryLog().comment(
00386 localPath.asString() + _(" execution skipped while aborting"),
00387 true);
00388 }
00389 else
00390 {
00391 MIL << "Found update script " << *sit << endl;
00392 callback::SendReport<PatchScriptReport> report;
00393 report->start( make<Package>( *it ), script.path() );
00394
00395 if ( ! executeScript( root_r, localPath, report ) )
00396 abort = true;
00397 }
00398 }
00399 }
00400 return !abort;
00401 }
00402
00404
00406
00407 inline void copyTo( std::ostream & out_r, const Pathname & file_r )
00408 {
00409 std::ifstream infile( file_r.c_str() );
00410 for( iostr::EachLine in( infile ); in; in.next() )
00411 {
00412 out_r << *in << endl;
00413 }
00414 }
00415
00416 inline std::string notificationCmdSubst( const std::string & cmd_r, const UpdateNotificationFile & notification_r )
00417 {
00418 std::string ret( cmd_r );
00419 #define SUBST_IF(PAT,VAL) if ( ret.find( PAT ) != std::string::npos ) ret = str::gsub( ret, PAT, VAL )
00420 SUBST_IF( "%p", notification_r.solvable().asString() );
00421 SUBST_IF( "%P", notification_r.file().asString() );
00422 #undef SUBST_IF
00423 return ret;
00424 }
00425
00426 void sendNotification( const Pathname & root_r,
00427 const UpdateNotifications & notifications_r )
00428 {
00429 if ( notifications_r.empty() )
00430 return;
00431
00432 std::string cmdspec( ZConfig::instance().updateMessagesNotify() );
00433 MIL << "Notification command is '" << cmdspec << "'" << endl;
00434 if ( cmdspec.empty() )
00435 return;
00436
00437 std::string::size_type pos( cmdspec.find( '|' ) );
00438 if ( pos == std::string::npos )
00439 {
00440 ERR << "Can't send Notification: Missing 'format |' in command spec." << endl;
00441 HistoryLog().comment( str::Str() << _("Error sending update message notification."), true );
00442 return;
00443 }
00444
00445 std::string formatStr( str::toLower( str::trim( cmdspec.substr( 0, pos ) ) ) );
00446 std::string commandStr( str::trim( cmdspec.substr( pos + 1 ) ) );
00447
00448 enum Format { UNKNOWN, NONE, SINGLE, DIGEST, BULK };
00449 Format format = UNKNOWN;
00450 if ( formatStr == "none" )
00451 format = NONE;
00452 else if ( formatStr == "single" )
00453 format = SINGLE;
00454 else if ( formatStr == "digest" )
00455 format = DIGEST;
00456 else if ( formatStr == "bulk" )
00457 format = BULK;
00458 else
00459 {
00460 ERR << "Can't send Notification: Unknown format '" << formatStr << " |' in command spec." << endl;
00461 HistoryLog().comment( str::Str() << _("Error sending update message notification."), true );
00462 return;
00463 }
00464
00465
00466
00467
00468
00469 if ( format == NONE || format == SINGLE )
00470 {
00471 for_( it, notifications_r.begin(), notifications_r.end() )
00472 {
00473 std::vector<std::string> command;
00474 if ( format == SINGLE )
00475 command.push_back( "<"+Pathname::assertprefix( root_r, it->file() ).asString() );
00476 str::splitEscaped( notificationCmdSubst( commandStr, *it ), std::back_inserter( command ) );
00477
00478 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
00479 if ( true )
00480 {
00481 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
00482 {
00483 DBG << line;
00484 }
00485 int ret = prog.close();
00486 if ( ret != 0 )
00487 {
00488 ERR << "Notification command returned with error (" << ret << ")." << endl;
00489 HistoryLog().comment( str::Str() << _("Error sending update message notification."), true );
00490 return;
00491 }
00492 }
00493 }
00494 }
00495 else if ( format == DIGEST || format == BULK )
00496 {
00497 filesystem::TmpFile tmpfile;
00498 ofstream out( tmpfile.path().c_str() );
00499 for_( it, notifications_r.begin(), notifications_r.end() )
00500 {
00501 if ( format == DIGEST )
00502 {
00503 out << it->file() << endl;
00504 }
00505 else if ( format == BULK )
00506 {
00507 copyTo( out << '\f', Pathname::assertprefix( root_r, it->file() ) );
00508 }
00509 }
00510
00511 std::vector<std::string> command;
00512 command.push_back( "<"+tmpfile.path().asString() );
00513 str::splitEscaped( notificationCmdSubst( commandStr, *notifications_r.begin() ), std::back_inserter( command ) );
00514
00515 ExternalProgram prog( command, ExternalProgram::Stderr_To_Stdout, false, -1, true, root_r );
00516 if ( true )
00517 {
00518 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
00519 {
00520 DBG << line;
00521 }
00522 int ret = prog.close();
00523 if ( ret != 0 )
00524 {
00525 ERR << "Notification command returned with error (" << ret << ")." << endl;
00526 HistoryLog().comment( str::Str() << _("Error sending update message notification."), true );
00527 return;
00528 }
00529 }
00530 }
00531 else
00532 {
00533 INT << "Can't send Notification: Missing handler for 'format |' in command spec." << endl;
00534 HistoryLog().comment( str::Str() << _("Error sending update message notification."), true );
00535 return;
00536 }
00537 }
00538
00539
00545 void RunUpdateMessages( const Pathname & root_r,
00546 const Pathname & messagesPath_r,
00547 const std::vector<sat::Solvable> & checkPackages_r,
00548 ZYppCommitResult & result_r )
00549 {
00550 if ( checkPackages_r.empty() )
00551 return;
00552
00553 MIL << "Looking for new update messages in (" << root_r << ")" << messagesPath_r << endl;
00554 Pathname messagesDir( Pathname::assertprefix( root_r, messagesPath_r ) );
00555 if ( ! PathInfo( messagesDir ).isDir() )
00556 return;
00557
00558 std::list<std::string> messages;
00559 filesystem::readdir( messages, messagesDir, false );
00560 if ( messages.empty() )
00561 return;
00562
00563
00564
00565
00566 HistoryLog historylog;
00567 for_( it, checkPackages_r.begin(), checkPackages_r.end() )
00568 {
00569 std::string prefix( str::form( "%s-%s", it->name().c_str(), it->edition().c_str() ) );
00570 for_( sit, messages.begin(), messages.end() )
00571 {
00572 if ( ! str::hasPrefix( *sit, prefix ) )
00573 continue;
00574
00575 if ( (*sit)[prefix.size()] != '\0' && (*sit)[prefix.size()] != '-' )
00576 continue;
00577
00578 PathInfo message( messagesDir / *sit );
00579 if ( ! message.isFile() || message.size() == 0 )
00580 continue;
00581
00582 MIL << "Found update message " << *sit << endl;
00583 Pathname localPath( messagesPath_r/(*sit) );
00584 result_r.rUpdateMessages().push_back( UpdateNotificationFile( *it, localPath ) );
00585 historylog.comment( str::Str() << _("New update message") << " " << localPath, true );
00586 }
00587 }
00588 sendNotification( root_r, result_r.updateMessages() );
00589 }
00590
00592 }
00594
00595 void XRunUpdateMessages( const Pathname & root_r,
00596 const Pathname & messagesPath_r,
00597 const std::vector<sat::Solvable> & checkPackages_r,
00598 ZYppCommitResult & result_r )
00599 { RunUpdateMessages( root_r, messagesPath_r, checkPackages_r, result_r ); }
00600
00602 struct QueryInstalledEditionHelper
00603 {
00604 bool operator()( const std::string & name_r,
00605 const Edition & ed_r,
00606 const Arch & arch_r ) const
00607 {
00608 rpm::librpmDb::db_const_iterator it;
00609 for ( it.findByName( name_r ); *it; ++it )
00610 {
00611 if ( arch_r == it->tag_arch()
00612 && ( ed_r == Edition::noedition || ed_r == it->tag_edition() ) )
00613 {
00614 return true;
00615 }
00616 }
00617 return false;
00618 }
00619 };
00620
00626 struct RepoProvidePackage
00627 {
00628 ResPool _pool;
00629 repo::RepoMediaAccess &_access;
00630
00631 RepoProvidePackage( repo::RepoMediaAccess &access, ResPool pool_r )
00632 : _pool(pool_r), _access(access)
00633 {}
00634
00635 ManagedFile operator()( const PoolItem & pi )
00636 {
00637
00638
00639 repo::PackageProviderPolicy packageProviderPolicy;
00640 packageProviderPolicy.queryInstalledCB( QueryInstalledEditionHelper() );
00641
00642 Package::constPtr p = asKind<Package>(pi.resolvable());
00643
00644
00645
00646 std::list<Repository> repos( _pool.knownRepositoriesBegin(), _pool.knownRepositoriesEnd() );
00647 repo::DeltaCandidates deltas(repos, p->name());
00648 repo::PackageProvider pkgProvider( _access, p, deltas, packageProviderPolicy );
00649
00650 ManagedFile ret( pkgProvider.providePackage() );
00651 return ret;
00652 }
00653 };
00655
00656 IMPL_PTR_TYPE(TargetImpl);
00657
00658 TargetImpl_Ptr TargetImpl::_nullimpl;
00659
00661 TargetImpl_Ptr TargetImpl::nullimpl()
00662 {
00663 if (_nullimpl == 0)
00664 _nullimpl = new TargetImpl;
00665 return _nullimpl;
00666 }
00667
00669
00670
00671
00672
00673 TargetImpl::TargetImpl( const Pathname & root_r, bool doRebuild_r )
00674 : _root( root_r )
00675 , _requestedLocalesFile( home() / "RequestedLocales" )
00676 , _softLocksFile( home() / "SoftLocks" )
00677 , _hardLocksFile( Pathname::assertprefix( _root, ZConfig::instance().locksFile() ) )
00678 {
00679 _rpm.initDatabase( root_r, Pathname(), doRebuild_r );
00680
00681 HistoryLog::setRoot(_root);
00682
00683 createAnonymousId();
00684
00685 MIL << "Initialized target on " << _root << endl;
00686 }
00687
00691 static string generateRandomId()
00692 {
00693 string id;
00694 const char* argv[] =
00695 {
00696 "/usr/bin/uuidgen",
00697 NULL
00698 };
00699
00700 ExternalProgram prog( argv,
00701 ExternalProgram::Normal_Stderr,
00702 false, -1, true);
00703 std::string line;
00704 for(line = prog.receiveLine();
00705 ! line.empty();
00706 line = prog.receiveLine() )
00707 {
00708 MIL << line << endl;
00709 id = line;
00710 break;
00711 }
00712 prog.close();
00713 return id;
00714 }
00715
00721 void updateFileContent( const Pathname &filename,
00722 boost::function<bool ()> condition,
00723 boost::function<string ()> value )
00724 {
00725 string val = value();
00726
00727
00728 if ( val.empty() )
00729 return;
00730
00731 if ( condition() )
00732 {
00733 MIL << "updating '" << filename << "' content." << endl;
00734
00735
00736
00737 std::ofstream filestr;
00738
00739 filesystem::assert_dir( filename.dirname() );
00740 filestr.open( filename.c_str() );
00741
00742 if ( filestr.good() )
00743 {
00744 filestr << val;
00745 filestr.close();
00746 }
00747 else
00748 {
00749
00750 ZYPP_THROW(Exception("Can't openfile '" + filename.asString() + "' for writing"));
00751 }
00752 }
00753 }
00754
00756 static bool fileMissing( const Pathname &pathname )
00757 {
00758 return ! PathInfo(pathname).isExist();
00759 }
00760
00761 void TargetImpl::createAnonymousId() const
00762 {
00763
00764
00765
00766 Pathname idpath( home() / "AnonymousUniqueId");
00767
00768 try
00769 {
00770 updateFileContent( idpath,
00771 boost::bind(fileMissing, idpath),
00772 generateRandomId );
00773 }
00774 catch ( const Exception &e )
00775 {
00776 WAR << "Can't create anonymous id file" << endl;
00777 }
00778
00779 }
00780
00781 void TargetImpl::createLastDistributionFlavorCache() const
00782 {
00783
00784
00785 Pathname flavorpath( home() / "LastDistributionFlavor");
00786
00787
00788 Product::constPtr p = baseProduct();
00789 if ( ! p )
00790 {
00791 WAR << "No base product, I won't create flavor cache" << endl;
00792 return;
00793 }
00794
00795 string flavor = p->flavor();
00796
00797 try
00798 {
00799
00800 updateFileContent( flavorpath,
00801
00802 functor::Constant<bool>( ! flavor.empty() ),
00803 functor::Constant<string>(flavor) );
00804 }
00805 catch ( const Exception &e )
00806 {
00807 WAR << "Can't create flavor cache" << endl;
00808 return;
00809 }
00810 }
00811
00813
00814
00815
00816
00817 TargetImpl::~TargetImpl()
00818 {
00819 _rpm.closeDatabase();
00820 MIL << "Targets closed" << endl;
00821 }
00822
00824
00825
00826
00828
00829 Pathname TargetImpl::defaultSolvfilesPath() const
00830 {
00831 return Pathname::assertprefix( _root, ZConfig::instance().repoSolvfilesPath() / sat::Pool::instance().systemRepoAlias() );
00832 }
00833
00834 void TargetImpl::clearCache()
00835 {
00836 Pathname base = solvfilesPath();
00837 filesystem::recursive_rmdir( base );
00838 }
00839
00840 void TargetImpl::buildCache()
00841 {
00842 Pathname base = solvfilesPath();
00843 Pathname rpmsolv = base/"solv";
00844 Pathname rpmsolvcookie = base/"cookie";
00845
00846 bool build_rpm_solv = true;
00847
00848
00849 RepoStatus rpmstatus( RepoStatus( _root/"/var/lib/rpm/Name" )
00850 && (_root/"/etc/products.d") );
00851
00852 bool solvexisted = PathInfo(rpmsolv).isExist();
00853 if ( solvexisted )
00854 {
00855
00856 PathInfo cookie( rpmsolvcookie );
00857 MIL << "Read cookie: " << cookie << endl;
00858 if ( cookie.isExist() )
00859 {
00860 RepoStatus status = RepoStatus::fromCookieFile(rpmsolvcookie);
00861
00862 if ( status.checksum() == rpmstatus.checksum() )
00863 build_rpm_solv = false;
00864 MIL << "Read cookie: " << rpmsolvcookie << " says: "
00865 << (build_rpm_solv ? "outdated" : "uptodate") << endl;
00866 }
00867 }
00868
00869 if ( build_rpm_solv )
00870 {
00871
00872 filesystem::assert_dir( base );
00873
00874 Pathname oldSolvFile( solvexisted ? rpmsolv : Pathname() );
00875
00876 filesystem::TmpFile tmpsolv( filesystem::TmpFile::makeSibling( rpmsolv ) );
00877 if ( !tmpsolv )
00878 {
00879
00880
00881
00882
00883 bool switchingToTmpSolvfile = false;
00884 Exception ex("Failed to cache rpm database.");
00885 ex.remember(str::form("Cannot create temporary file under %s.", base.c_str()));
00886
00887 if ( ! solvfilesPathIsTemp() )
00888 {
00889 base = getZYpp()->tmpPath() / sat::Pool::instance().systemRepoAlias();
00890 rpmsolv = base/"solv";
00891 rpmsolvcookie = base/"cookie";
00892
00893 filesystem::assert_dir( base );
00894 tmpsolv = filesystem::TmpFile::makeSibling( rpmsolv );
00895
00896 if ( tmpsolv )
00897 {
00898 WAR << "Using a temporary solv file at " << base << endl;
00899 switchingToTmpSolvfile = true;
00900 _tmpSolvfilesPath = base;
00901 }
00902 else
00903 {
00904 ex.remember(str::form("Cannot create temporary file under %s.", base.c_str()));
00905 }
00906 }
00907
00908 if ( ! switchingToTmpSolvfile )
00909 {
00910 ZYPP_THROW(ex);
00911 }
00912 }
00913
00914
00915 ManagedFile guard( base, filesystem::recursive_rmdir );
00916
00917 std::ostringstream cmd;
00918 cmd << "rpmdb2solv";
00919 if ( ! _root.empty() )
00920 cmd << " -r '" << _root << "'";
00921
00922 cmd << " -p '" << Pathname::assertprefix( _root, "/etc/products.d" ) << "'";
00923
00924 if ( ! oldSolvFile.empty() )
00925 cmd << " '" << oldSolvFile << "'";
00926
00927 cmd << " > '" << tmpsolv.path() << "'";
00928
00929 MIL << "Executing: " << cmd << endl;
00930 ExternalProgram prog( cmd.str(), ExternalProgram::Stderr_To_Stdout );
00931
00932 cmd << endl;
00933 for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00934 WAR << " " << output;
00935 cmd << " " << output;
00936 }
00937
00938 int ret = prog.close();
00939 if ( ret != 0 )
00940 {
00941 Exception ex(str::form("Failed to cache rpm database (%d).", ret));
00942 ex.remember( cmd.str() );
00943 ZYPP_THROW(ex);
00944 }
00945
00946 ret = filesystem::rename( tmpsolv, rpmsolv );
00947 if ( ret != 0 )
00948 ZYPP_THROW(Exception("Failed to move cache to final destination"));
00949
00950 filesystem::chmod( rpmsolv, 0644 );
00951
00952 rpmstatus.saveToCookieFile(rpmsolvcookie);
00953
00954
00955 guard.resetDispose();
00956
00957
00958
00959 {
00960 Pathname script( Pathname::assertprefix( _root, ZConfig::instance().pluginsPath()/"system/spacewalk" ) );
00961 if ( PathInfo( script ).isX() )
00962 try {
00963 PluginScript spacewalk( script );
00964 spacewalk.open();
00965
00966 PluginFrame notify( "PACKAGESETCHANGED" );
00967 spacewalk.send( notify );
00968
00969 PluginFrame ret( spacewalk.receive() );
00970 MIL << ret << endl;
00971 if ( ret.command() == "ERROR" )
00972 ret.writeTo( WAR ) << endl;
00973 }
00974 catch ( const Exception & excpt )
00975 {
00976 WAR << excpt.asUserHistory() << endl;
00977 }
00978 }
00979 }
00980 }
00981
00982 void TargetImpl::unload()
00983 {
00984 Repository system( sat::Pool::instance().findSystemRepo() );
00985 if ( system )
00986 system.eraseFromPool();
00987 }
00988
00989
00990 void TargetImpl::load()
00991 {
00992 buildCache();
00993
00994
00995 sat::Pool satpool( sat::Pool::instance() );
00996 Pathname rpmsolv( solvfilesPath() / "solv" );
00997 MIL << "adding " << rpmsolv << " to pool(" << satpool.systemRepoAlias() << ")" << endl;
00998
00999
01000 Repository system( sat::Pool::instance().findSystemRepo() );
01001 if ( system && ! system.solvablesEmpty() )
01002 {
01003 system.eraseFromPool();
01004 }
01005 if ( ! system )
01006 {
01007 system = satpool.systemRepo();
01008 }
01009
01010 try
01011 {
01012 system.addSolv( rpmsolv );
01013 }
01014 catch ( const Exception & exp )
01015 {
01016 ZYPP_CAUGHT( exp );
01017 MIL << "Try to handle exception by rebuilding the solv-file" << endl;
01018 clearCache();
01019 buildCache();
01020
01021 system.addSolv( rpmsolv );
01022 }
01023
01024
01025
01026
01027
01028
01029 {
01030 const LocaleSet & requestedLocales( _requestedLocalesFile.locales() );
01031 if ( ! requestedLocales.empty() )
01032 {
01033 satpool.setRequestedLocales( requestedLocales );
01034 }
01035 }
01036 {
01037 SoftLocksFile::Data softLocks( _softLocksFile.data() );
01038 if ( ! softLocks.empty() )
01039 {
01040
01041 for_( it, system.solvablesBegin(), system.solvablesEnd() )
01042 {
01043 softLocks.erase( it->ident() );
01044 }
01045 ResPool::instance().setAutoSoftLocks( softLocks );
01046 }
01047 }
01048 if ( ZConfig::instance().apply_locks_file() )
01049 {
01050 const HardLocksFile::Data & hardLocks( _hardLocksFile.data() );
01051 if ( ! hardLocks.empty() )
01052 {
01053 ResPool::instance().setHardLockQueries( hardLocks );
01054 }
01055 }
01056
01057
01058 createLastDistributionFlavorCache();
01059
01060 MIL << "Target loaded: " << system.solvablesSize() << " resolvables" << endl;
01061 }
01062
01064
01065
01066
01068 ZYppCommitResult TargetImpl::commit( ResPool pool_r, const ZYppCommitPolicy & policy_rX )
01069 {
01070
01071 ZYppCommitPolicy policy_r( policy_rX );
01072
01073
01074
01075 if ( policy_r.restrictToMedia() > 1 )
01076 policy_r.allMedia();
01077
01078 if ( policy_r.downloadMode() == DownloadDefault ) {
01079 if ( root() == "/" )
01080 policy_r.downloadMode(DownloadInHeaps);
01081 else
01082 policy_r.downloadMode(DownloadAsNeeded);
01083 }
01084
01085 else if ( policy_r.downloadMode() == DownloadOnly )
01086 policy_r.dryRun( true );
01087
01088
01089 MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
01090
01092
01094 CommitPlugins commitPlugins;
01095 if ( root() == "/" && ! policy_r.dryRun() )
01096 {
01097 Pathname plugindir( Pathname::assertprefix( _root, ZConfig::instance().pluginsPath()/"commit" ) );
01098 commitPlugins.load( plugindir );
01099 }
01100
01102
01104 if ( getZYpp()->resolver()->upgradeMode() )
01105 {
01106 if ( ! policy_r.dryRun() )
01107 {
01108 writeUpgradeTestcase();
01109 }
01110 else
01111 {
01112 DBG << "dryRun: Not writing upgrade testcase." << endl;
01113 }
01114 }
01115
01117
01119 if ( ! policy_r.dryRun() )
01120 {
01121 filesystem::assert_dir( home() );
01122
01123 _requestedLocalesFile.setLocales( pool_r.getRequestedLocales() );
01124
01125 {
01126 SoftLocksFile::Data newdata;
01127 pool_r.getActiveSoftLocks( newdata );
01128 _softLocksFile.setData( newdata );
01129 }
01130
01131 if ( ZConfig::instance().apply_locks_file() )
01132 {
01133 HardLocksFile::Data newdata;
01134 pool_r.getHardLockQueries( newdata );
01135 _hardLocksFile.setData( newdata );
01136 }
01137 }
01138 else
01139 {
01140 DBG << "dryRun: Not stroring non-package data." << endl;
01141 }
01142
01144
01146 ZYppCommitResult result( root() );
01147 result.rTransaction() = pool_r.resolver().getTransaction();
01148 result.rTransaction().order();
01149
01150 ZYppCommitResult::TransactionStepList & steps( result.rTransactionStepList() );
01151 if ( policy_r.restrictToMedia() )
01152 {
01153
01154
01155 MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
01156 for_( it, result.transaction().begin(), result.transaction().end() )
01157 {
01158 if ( makeResObject( *it )->mediaNr() > 1 )
01159 break;
01160 steps.push_back( *it );
01161 }
01162 }
01163 else
01164 {
01165 result.rTransactionStepList().insert( steps.end(), result.transaction().begin(), result.transaction().end() );
01166 }
01167 MIL << "Todo: " << result << endl;
01168
01170
01171
01173 if ( ! policy_r.dryRun() )
01174 {
01175 for_( it, steps.begin(), steps.end() )
01176 {
01177 if ( ! it->satSolvable().isKind<Patch>() )
01178 continue;
01179
01180 PoolItem pi( *it );
01181 if ( ! pi.status().isToBeInstalled() )
01182 continue;
01183
01184 Patch::constPtr patch( asKind<Patch>(pi.resolvable()) );
01185 if ( ! patch ||patch->message().empty() )
01186 continue;
01187
01188 MIL << "Show message for " << patch << endl;
01189 callback::SendReport<target::PatchMessageReport> report;
01190 if ( ! report->show( patch ) )
01191 {
01192 WAR << "commit aborted by the user" << endl;
01193 ZYPP_THROW( TargetAbortedException( N_("Installation has been aborted as directed.") ) );
01194 }
01195 }
01196 }
01197 else
01198 {
01199 DBG << "dryRun: Not checking patch messages." << endl;
01200 }
01201
01203
01205 DBG << "commit log file is set to: " << HistoryLog::fname() << endl;
01206 if ( ! policy_r.dryRun() || policy_r.downloadMode() == DownloadOnly )
01207 {
01208
01209 repo::RepoMediaAccess access;
01210 RepoProvidePackage repoProvidePackage( access, pool_r );
01211 CommitPackageCache packageCache( root() / "tmp", repoProvidePackage );
01212 packageCache.setCommitList( steps.begin(), steps.end() );
01213
01214 bool miss = false;
01215 if ( policy_r.downloadMode() != DownloadAsNeeded )
01216 {
01217
01218
01219
01220 for_( it, steps.begin(), steps.end() )
01221 {
01222 switch ( it->stepType() )
01223 {
01224 case sat::Transaction::TRANSACTION_INSTALL:
01225 case sat::Transaction::TRANSACTION_MULTIINSTALL:
01226
01227 break;
01228
01229 default:
01230
01231 continue;
01232 break;
01233 }
01234
01235 PoolItem pi( *it );
01236 if ( pi->isKind<Package>() || pi->isKind<SrcPackage>() )
01237 {
01238 ManagedFile localfile;
01239 try
01240 {
01241
01242 if ( pi->isKind<Package>() )
01243 {
01244 localfile = packageCache.get( pi );
01245 }
01246 else if ( pi->isKind<SrcPackage>() )
01247 {
01248 repo::RepoMediaAccess access;
01249 repo::SrcPackageProvider prov( access );
01250 localfile = prov.provideSrcPackage( pi->asKind<SrcPackage>() );
01251 }
01252 else
01253 {
01254 INT << "Don't know howto cache: Neither Package nor SrcPackage: " << pi << endl;
01255 continue;
01256 }
01257 localfile.resetDispose();
01258 }
01259 catch ( const AbortRequestException & exp )
01260 {
01261 it->stepStage( sat::Transaction::STEP_ERROR );
01262 miss = true;
01263 WAR << "commit cache preload aborted by the user" << endl;
01264 ZYPP_THROW( TargetAbortedException( N_("Installation has been aborted as directed.") ) );
01265 break;
01266 }
01267 catch ( const SkipRequestException & exp )
01268 {
01269 ZYPP_CAUGHT( exp );
01270 it->stepStage( sat::Transaction::STEP_ERROR );
01271 miss = true;
01272 WAR << "Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
01273 continue;
01274 }
01275 catch ( const Exception & exp )
01276 {
01277
01278
01279 ZYPP_CAUGHT( exp );
01280 it->stepStage( sat::Transaction::STEP_ERROR );
01281 miss = true;
01282 INT << "Unexpected Error: Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
01283 continue;
01284 }
01285 }
01286 }
01287 }
01288
01289 if ( miss )
01290 {
01291 ERR << "Some packages could not be provided. Aborting commit."<< endl;
01292 }
01293 else if ( ! policy_r.dryRun() )
01294 {
01295 commit( policy_r, packageCache, result );
01296 }
01297 else
01298 {
01299 DBG << "dryRun: Not installing/deleting anything." << endl;
01300 }
01301 }
01302 else
01303 {
01304 DBG << "dryRun: Not downloading/installing/deleting anything." << endl;
01305 }
01306
01308
01310 if ( ! policy_r.dryRun() )
01311 {
01312 buildCache();
01313 }
01314
01315
01317
01319 result._errors.clear();
01320 result._remaining.clear();
01321 result._srcremaining.clear();
01322 unsigned toInstall = 0;
01323 for_( step, steps.begin(), steps.end() )
01324 {
01325 if ( step->stepType() == sat::Transaction::TRANSACTION_IGNORE )
01326 {
01327
01328
01329 if ( step->satSolvable().isSystem() || ! step->satSolvable().isKind<Product>() )
01330 continue;
01331 }
01332 else if ( step->stepType() == sat::Transaction::TRANSACTION_ERASE )
01333 {
01334 continue;
01335 }
01336
01337 ++toInstall;
01338 switch ( step->stepStage() )
01339 {
01340 case sat::Transaction::STEP_TODO:
01341 if ( step->satSolvable().isKind<Package>() )
01342 result._remaining.push_back( PoolItem( *step ) );
01343 else if ( step->satSolvable().isKind<SrcPackage>() )
01344 result._srcremaining.push_back( PoolItem( *step ) );
01345 break;
01346 case sat::Transaction::STEP_DONE:
01347
01348 break;
01349 case sat::Transaction::STEP_ERROR:
01350 result._errors.push_back( PoolItem( *step ) );
01351 break;
01352 }
01353 }
01354 result._result = (toInstall - result._remaining.size());
01356
01357 MIL << "TargetImpl::commit(<pool>, " << policy_r << ") returns: " << result << endl;
01358 return result;
01359 }
01360
01362
01363
01364
01366 void TargetImpl::commit( const ZYppCommitPolicy & policy_r,
01367 CommitPackageCache & packageCache_r,
01368 ZYppCommitResult & result_r )
01369 {
01370
01371 ZYppCommitResult::TransactionStepList & steps( result_r.rTransactionStepList() );
01372 MIL << "TargetImpl::commit(<list>" << policy_r << ")" << steps.size() << endl;
01373
01374 bool abort = false;
01375 std::vector<sat::Solvable> successfullyInstalledPackages;
01376 TargetImpl::PoolItemList remaining;
01377
01378 for_( step, steps.begin(), steps.end() )
01379 {
01380 PoolItem citem( *step );
01381 if ( step->stepType() == sat::Transaction::TRANSACTION_IGNORE )
01382 {
01383 if ( citem->isKind<Package>() )
01384 {
01385
01386
01387 step->stepStage( sat::Transaction::STEP_DONE );
01388 continue;
01389 }
01390 }
01391
01392 if ( citem->isKind<Package>() )
01393 {
01394 Package::constPtr p = citem->asKind<Package>();
01395 if ( citem.status().isToBeInstalled() )
01396 {
01397 ManagedFile localfile;
01398 try
01399 {
01400 localfile = packageCache_r.get( citem );
01401 }
01402 catch ( const AbortRequestException &e )
01403 {
01404 WAR << "commit aborted by the user" << endl;
01405 abort = true;
01406 step->stepStage( sat::Transaction::STEP_ERROR );
01407 break;
01408 }
01409 catch ( const SkipRequestException &e )
01410 {
01411 ZYPP_CAUGHT( e );
01412 WAR << "Skipping package " << p << " in commit" << endl;
01413 step->stepStage( sat::Transaction::STEP_ERROR );
01414 continue;
01415 }
01416 catch ( const Exception &e )
01417 {
01418
01419
01420 ZYPP_CAUGHT( e );
01421 INT << "Unexpected Error: Skipping package " << p << " in commit" << endl;
01422 step->stepStage( sat::Transaction::STEP_ERROR );
01423 continue;
01424 }
01425
01426 #warning Exception handling
01427
01428 RpmInstallPackageReceiver progress( citem.resolvable() );
01429 progress.connect();
01430
01431 bool success = false;
01432 rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
01433
01434
01435
01436
01437
01438
01439
01440 flags |= rpm::RPMINST_NODEPS;
01441 flags |= rpm::RPMINST_FORCE;
01442
01443 if (p->multiversionInstall()) flags |= rpm::RPMINST_NOUPGRADE;
01444 if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
01445 if (policy_r.rpmExcludeDocs()) flags |= rpm::RPMINST_EXCLUDEDOCS;
01446 if (policy_r.rpmNoSignature()) flags |= rpm::RPMINST_NOSIGNATURE;
01447
01448 try
01449 {
01450 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
01451 rpm().installPackage( localfile, flags );
01452 HistoryLog().install(citem);
01453
01454 if ( progress.aborted() )
01455 {
01456 WAR << "commit aborted by the user" << endl;
01457 localfile.resetDispose();
01458 abort = true;
01459 step->stepStage( sat::Transaction::STEP_ERROR );
01460 break;
01461 }
01462 else
01463 {
01464 success = true;
01465 step->stepStage( sat::Transaction::STEP_DONE );
01466 }
01467 }
01468 catch ( Exception & excpt_r )
01469 {
01470 ZYPP_CAUGHT(excpt_r);
01471 localfile.resetDispose();
01472
01473 if ( policy_r.dryRun() )
01474 {
01475 WAR << "dry run failed" << endl;
01476 step->stepStage( sat::Transaction::STEP_ERROR );
01477 break;
01478 }
01479
01480 if ( progress.aborted() )
01481 {
01482 WAR << "commit aborted by the user" << endl;
01483 abort = true;
01484 }
01485 else
01486 {
01487 WAR << "Install failed" << endl;
01488 }
01489 step->stepStage( sat::Transaction::STEP_ERROR );
01490 break;
01491 }
01492
01493 if ( success && !policy_r.dryRun() )
01494 {
01495 citem.status().resetTransact( ResStatus::USER );
01496 successfullyInstalledPackages.push_back( citem.satSolvable() );
01497 step->stepStage( sat::Transaction::STEP_DONE );
01498 }
01499 }
01500 else
01501 {
01502 RpmRemovePackageReceiver progress( citem.resolvable() );
01503 progress.connect();
01504
01505 bool success = false;
01506 rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
01507 flags |= rpm::RPMINST_NODEPS;
01508 if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
01509 try
01510 {
01511 rpm().removePackage( p, flags );
01512 HistoryLog().remove(citem);
01513
01514 if ( progress.aborted() )
01515 {
01516 WAR << "commit aborted by the user" << endl;
01517 abort = true;
01518 step->stepStage( sat::Transaction::STEP_ERROR );
01519 break;
01520 }
01521 else
01522 {
01523 success = true;
01524 step->stepStage( sat::Transaction::STEP_DONE );
01525 }
01526 }
01527 catch (Exception & excpt_r)
01528 {
01529 ZYPP_CAUGHT( excpt_r );
01530 if ( progress.aborted() )
01531 {
01532 WAR << "commit aborted by the user" << endl;
01533 abort = true;
01534 step->stepStage( sat::Transaction::STEP_ERROR );
01535 break;
01536 }
01537
01538 WAR << "removal of " << p << " failed";
01539 step->stepStage( sat::Transaction::STEP_ERROR );
01540 }
01541 if ( success && !policy_r.dryRun() )
01542 {
01543 citem.status().resetTransact( ResStatus::USER );
01544 step->stepStage( sat::Transaction::STEP_DONE );
01545 }
01546 }
01547 }
01548 else if ( ! policy_r.dryRun() )
01549 {
01550
01551
01552 if ( ! citem.buddy() )
01553 {
01554 if ( citem->isKind<Product>() )
01555 {
01556 Product::constPtr p = citem->asKind<Product>();
01557 if ( citem.status().isToBeInstalled() )
01558 {
01559 ERR << "Can't install orphan product without release-package! " << citem << endl;
01560 }
01561 else
01562 {
01563
01564
01565 std::string referenceFilename( p->referenceFilename() );
01566 if ( referenceFilename.empty() )
01567 {
01568 ERR << "Can't remove orphan product without 'referenceFilename'! " << citem << endl;
01569 }
01570 else
01571 {
01572 PathInfo referenceFile( Pathname::assertprefix( _root, Pathname( "/etc/products.d" ) ) / referenceFilename );
01573 if ( ! referenceFile.isFile() || filesystem::unlink( referenceFile.path() ) != 0 )
01574 {
01575 ERR << "Delete orphan product failed: " << referenceFile << endl;
01576 }
01577 }
01578 }
01579 }
01580 else if ( citem->isKind<SrcPackage>() && citem.status().isToBeInstalled() )
01581 {
01582
01583 SrcPackage::constPtr p = citem->asKind<SrcPackage>();
01584 installSrcPackage( p );
01585 }
01586
01587 citem.status().resetTransact( ResStatus::USER );
01588 step->stepStage( sat::Transaction::STEP_DONE );
01589 }
01590
01591 }
01592
01593 }
01594
01595
01596
01597 if ( ! successfullyInstalledPackages.empty() )
01598 {
01599 if ( ! RunUpdateScripts( _root, ZConfig::instance().update_scriptsPath(),
01600 successfullyInstalledPackages, abort ) )
01601 {
01602 WAR << "Commit aborted by the user" << endl;
01603 abort = true;
01604 }
01605
01606
01607 RunUpdateMessages( _root, ZConfig::instance().update_messagesPath(),
01608 successfullyInstalledPackages,
01609 result_r );
01610 }
01611
01612 if ( abort )
01613 {
01614 ZYPP_THROW( TargetAbortedException( N_("Installation has been aborted as directed.") ) );
01615 }
01616 }
01617
01619
01620 rpm::RpmDb & TargetImpl::rpm()
01621 {
01622 return _rpm;
01623 }
01624
01625 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
01626 {
01627 return _rpm.hasFile(path_str, name_str);
01628 }
01629
01630
01631 Date TargetImpl::timestamp() const
01632 {
01633 return _rpm.timestamp();
01634 }
01635
01637
01638 Product::constPtr TargetImpl::baseProduct() const
01639 {
01640 ResPool pool(ResPool::instance());
01641 for_( it, pool.byKindBegin<Product>(), pool.byKindEnd<Product>() )
01642 {
01643 Product::constPtr p = (*it)->asKind<Product>();
01644 if ( p->isTargetDistribution() )
01645 return p;
01646 }
01647 return 0L;
01648 }
01649
01651
01652 namespace
01653 {
01654 parser::ProductFileData baseproductdata( const Pathname & root_r )
01655 {
01656 PathInfo baseproduct( Pathname::assertprefix( root_r, "/etc/products.d/baseproduct" ) );
01657 if ( baseproduct.isFile() )
01658 {
01659 try
01660 {
01661 return parser::ProductFileReader::scanFile( baseproduct.path() );
01662 }
01663 catch ( const Exception & excpt )
01664 {
01665 ZYPP_CAUGHT( excpt );
01666 }
01667 }
01668 return parser::ProductFileData();
01669 }
01670
01671 inline Pathname staticGuessRoot( const Pathname & root_r )
01672 {
01673 if ( root_r.empty() )
01674 {
01675
01676 Pathname ret ( ZConfig::instance().systemRoot() );
01677 if ( ret.empty() )
01678 return Pathname("/");
01679 return ret;
01680 }
01681 return root_r;
01682 }
01683
01684 inline std::string firstNonEmptyLineIn( const Pathname & file_r )
01685 {
01686 std::ifstream idfile( file_r.c_str() );
01687 for( iostr::EachLine in( idfile ); in; in.next() )
01688 {
01689 std::string line( str::trim( *in ) );
01690 if ( ! line.empty() )
01691 return line;
01692 }
01693 return std::string();
01694 }
01695 }
01696
01697 std::string TargetImpl::targetDistribution() const
01698 { return baseproductdata( _root ).registerTarget(); }
01699
01700 std::string TargetImpl::targetDistribution( const Pathname & root_r )
01701 { return baseproductdata( staticGuessRoot(root_r) ).registerTarget(); }
01702
01703 std::string TargetImpl::targetDistributionRelease() const
01704 { return baseproductdata( _root ).registerRelease(); }
01705
01706 std::string TargetImpl::targetDistributionRelease( const Pathname & root_r )
01707 { return baseproductdata( staticGuessRoot(root_r) ).registerRelease();}
01708
01709 Target::DistributionLabel TargetImpl::distributionLabel() const
01710 {
01711 Target::DistributionLabel ret;
01712 parser::ProductFileData pdata( baseproductdata( _root ) );
01713 ret.shortName = pdata.shortName();
01714 ret.summary = pdata.summary();
01715 return ret;
01716 }
01717
01718 Target::DistributionLabel TargetImpl::distributionLabel( const Pathname & root_r )
01719 {
01720 Target::DistributionLabel ret;
01721 parser::ProductFileData pdata( baseproductdata( staticGuessRoot(root_r) ) );
01722 ret.shortName = pdata.shortName();
01723 ret.summary = pdata.summary();
01724 return ret;
01725 }
01726
01727 std::string TargetImpl::distributionVersion() const
01728 {
01729 if ( _distributionVersion.empty() )
01730 {
01731 _distributionVersion = TargetImpl::distributionVersion(root());
01732 if ( !_distributionVersion.empty() )
01733 MIL << "Remember distributionVersion = '" << _distributionVersion << "'" << endl;
01734 }
01735 return _distributionVersion;
01736 }
01737
01738 std::string TargetImpl::distributionVersion( const Pathname & root_r )
01739 {
01740 std::string distributionVersion = baseproductdata( staticGuessRoot(root_r) ).edition().version();
01741 if ( distributionVersion.empty() )
01742 {
01743
01744
01745
01746
01747 scoped_ptr<rpm::RpmDb> tmprpmdb;
01748 if ( ZConfig::instance().systemRoot() == Pathname() )
01749 {
01750 try
01751 {
01752 tmprpmdb.reset( new rpm::RpmDb );
01753 tmprpmdb->initDatabase( );
01754 }
01755 catch( ... )
01756 {
01757 return "";
01758 }
01759 }
01760 rpm::librpmDb::db_const_iterator it;
01761 if ( it.findByProvides( ZConfig::instance().distroverpkg() ) )
01762 distributionVersion = it->tag_version();
01763 }
01764 return distributionVersion;
01765 }
01766
01767
01768 std::string TargetImpl::distributionFlavor() const
01769 {
01770 return firstNonEmptyLineIn( home() / "LastDistributionFlavor" );
01771 }
01772
01773 std::string TargetImpl::distributionFlavor( const Pathname & root_r )
01774 {
01775 return firstNonEmptyLineIn( staticGuessRoot(root_r) / "/var/lib/zypp/LastDistributionFlavor" );
01776 }
01777
01779
01780 std::string TargetImpl::anonymousUniqueId() const
01781 {
01782 return firstNonEmptyLineIn( home() / "AnonymousUniqueId" );
01783 }
01784
01785 std::string TargetImpl::anonymousUniqueId( const Pathname & root_r )
01786 {
01787 return firstNonEmptyLineIn( staticGuessRoot(root_r) / "/var/lib/zypp/AnonymousUniqueId" );
01788 }
01789
01791
01792 void TargetImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r )
01793 {
01794
01795 repo::RepoMediaAccess access_r;
01796 repo::SrcPackageProvider prov( access_r );
01797 ManagedFile localfile = prov.provideSrcPackage( srcPackage_r );
01798
01799 rpm().installPackage ( localfile );
01800 }
01801
01803 }
01806 }