#include "zypp/target/RpmPostTransCollector.h"
#include "zypp/parser/ProductFileReader.h"
-
-#include "zypp/solver/detail/Testcase.h"
-
#include "zypp/repo/SrcPackageProvider.h"
#include "zypp/sat/Pool.h"
+#include "zypp/sat/detail/PoolImpl.h"
#include "zypp/sat/Transaction.h"
-#include "zypp/PluginScript.h"
+#include "zypp/PluginExecutor.h"
using namespace std;
///////////////////////////////////////////////////////////////////
namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
+ /////////////////////////////////////////////////////////////////
+ namespace
+ {
+ // HACK for bnc#906096: let pool re-evaluate multiversion spec
+ // if target root changes. ZConfig returns data sensitive to
+ // current target root.
+ inline void sigMultiversionSpecChanged()
+ {
+ sat::detail::PoolMember::myPool().multiversionSpecChanged();
+ }
+ } //namespace
+ /////////////////////////////////////////////////////////////////
+
///////////////////////////////////////////////////////////////////
namespace json
{
} // namespace
///////////////////////////////////////////////////////////////////
- /** Helper for commit plugin execution.
- * \ingroup g_RAII
- */
- class CommitPlugins : private base::NonCopyable
- {
- public:
- /** Default ctor: Empty plugin list */
- CommitPlugins()
- {}
-
- /** Dtor: Send PLUGINEND message and close plugins. */
- ~CommitPlugins()
- {
- if ( ! _scripts.empty() )
- send( PluginFrame( "PLUGINEND" ) );
- // ~PluginScript will disconnect all remaining plugins!
- }
-
- /** Whether no plugins are waiting */
- bool empty() const
- { return _scripts.empty(); }
-
-
- /** Send \ref PluginFrame to all open plugins.
- * Failed plugins are removed from the execution list.
- */
- void send( const PluginFrame & frame_r )
- {
- DBG << "+++++++++++++++ send " << frame_r << endl;
- for ( auto it = _scripts.begin(); it != _scripts.end(); )
- {
- doSend( *it, frame_r );
- if ( it->isOpen() )
- ++it;
- else
- it = _scripts.erase( it );
- }
- DBG << "--------------- send " << frame_r << endl;
- }
-
- /** Find and launch plugins sending PLUGINSTART message.
- *
- * If \a path_r is a directory all executable files whithin are
- * expected to be plugins. Otherwise \a path_r must point to an
- * executable plugin.
- */
- void load( const Pathname & path_r )
- {
- PathInfo pi( path_r );
- DBG << "+++++++++++++++ load " << pi << endl;
- if ( pi.isDir() )
- {
- std::list<Pathname> entries;
- if ( filesystem::readdir( entries, pi.path(), false ) != 0 )
- {
- WAR << "Plugin dir is not readable: " << pi << endl;
- return;
- }
- for_( it, entries.begin(), entries.end() )
- {
- PathInfo pii( *it );
- if ( pii.isFile() && pii.userMayRX() )
- doLoad( pii );
- }
- }
- else if ( pi.isFile() )
- {
- if ( pi.userMayRX() )
- doLoad( pi );
- else
- WAR << "Plugin file is not executable: " << pi << endl;
- }
- else
- {
- WAR << "Plugin path is neither dir nor file: " << pi << endl;
- }
- DBG << "--------------- load " << pi << endl;
- }
-
- private:
- /** Send \ref PluginFrame and expect valid answer (ACK|_ENOMETHOD).
- * Upon invalid answer or error, close the plugin. and remove it from the
- * execution list.
- * \returns the received \ref PluginFrame (empty Frame upon Exception)
- */
- PluginFrame doSend( PluginScript & script_r, const PluginFrame & frame_r )
- {
- PluginFrame ret;
-
- try {
- script_r.send( frame_r );
- ret = script_r.receive();
- }
- catch( const zypp::Exception & e )
- { ZYPP_CAUGHT(e); }
-
- if ( ! ( ret.isAckCommand() || ret.isEnomethodCommand() ) )
- {
- WAR << "Bad plugin response from " << script_r << endl;
- WAR << dump(ret) << endl;
- script_r.close();
- }
-
- return ret;
- }
-
- /** Launch a plugin sending PLUGINSTART message. */
- void doLoad( const PathInfo & pi_r )
- {
- MIL << "Load plugin: " << pi_r << endl;
- try {
- PluginScript plugin( pi_r.path() );
- plugin.open();
-
- PluginFrame frame( "PLUGINBEGIN" );
- if ( ZConfig::instance().hasUserData() )
- frame.setHeader( "userdata", ZConfig::instance().userData() );
-
- doSend( plugin, frame ); // closes on error
- if ( plugin.isOpen() )
- _scripts.push_back( plugin );
- }
- catch( const zypp::Exception & e )
- {
- WAR << "Failed to load plugin " << pi_r << endl;
- }
- }
-
- private:
- std::list<PluginScript> _scripts;
- };
-
- void testCommitPlugins( const Pathname & path_r ) // for testing only
- {
- USR << "+++++" << endl;
- {
- CommitPlugins pl;
- pl.load( path_r );
- USR << "=====" << endl;
- }
- USR << "-----" << endl;
- }
-
///////////////////////////////////////////////////////////////////
namespace
{
IMPL_PTR_TYPE(TargetImpl);
- TargetImpl_Ptr TargetImpl::_nullimpl;
-
- /** Null implementation */
- TargetImpl_Ptr TargetImpl::nullimpl()
- {
- if (_nullimpl == 0)
- _nullimpl = new TargetImpl;
- return _nullimpl;
- }
-
///////////////////////////////////////////////////////////////////
//
// METHOD NAME : TargetImpl::TargetImpl
HistoryLog::setRoot(_root);
createAnonymousId();
-
+ sigMultiversionSpecChanged(); // HACK: see sigMultiversionSpecChanged
MIL << "Initialized target on " << _root << endl;
}
void TargetImpl::createAnonymousId() const
{
+ // bsc#1024741: Omit creating a new uid for chrooted systems (if it already has one, fine)
+ if ( root() != "/" )
+ return;
- // create the anonymous unique id
- // this value is used for statistics
+ // Create the anonymous unique id, used for download statistics
Pathname idpath( home() / "AnonymousUniqueId");
try
TargetImpl::~TargetImpl()
{
_rpm.closeDatabase();
+ sigMultiversionSpecChanged(); // HACK: see sigMultiversionSpecChanged
MIL << "Targets closed" << endl;
}
// Take care we unlink the solvfile on exception
ManagedFile guard( base, filesystem::recursive_rmdir );
- std::ostringstream cmd;
- cmd << "rpmdb2solv";
- if ( ! _root.empty() )
- cmd << " -r '" << _root << "'";
- cmd << " -X"; // autogenerate pattern/product/... from -package
- cmd << " -A"; // autogenerate application pseudo packages
- cmd << " -p '" << Pathname::assertprefix( _root, "/etc/products.d" ) << "'";
+ ExternalProgram::Arguments cmd;
+ cmd.push_back( "rpmdb2solv" );
+ if ( ! _root.empty() ) {
+ cmd.push_back( "-r" );
+ cmd.push_back( _root.asString() );
+ }
+ cmd.push_back( "-X" ); // autogenerate pattern/product/... from -package
+ cmd.push_back( "-A" ); // autogenerate application pseudo packages
+ cmd.push_back( "-p" );
+ cmd.push_back( Pathname::assertprefix( _root, "/etc/products.d" ).asString() );
if ( ! oldSolvFile.empty() )
- cmd << " '" << oldSolvFile << "'";
+ cmd.push_back( oldSolvFile.asString() );
- cmd << " > '" << tmpsolv.path() << "'";
+ cmd.push_back( "-o" );
+ cmd.push_back( tmpsolv.path().asString() );
- MIL << "Executing: " << cmd << endl;
- ExternalProgram prog( cmd.str(), ExternalProgram::Stderr_To_Stdout );
+ ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
+ std::string errdetail;
- cmd << endl;
for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
WAR << " " << output;
- cmd << " " << output;
+ if ( errdetail.empty() ) {
+ errdetail = prog.command();
+ errdetail += '\n';
+ }
+ errdetail += output;
}
int ret = prog.close();
if ( ret != 0 )
{
Exception ex(str::form("Failed to cache rpm database (%d).", ret));
- ex.remember( cmd.str() );
+ ex.remember( errdetail );
ZYPP_THROW(ex);
}
// We keep it.
guard.resetDispose();
+ sat::updateSolvFileIndex( rpmsolv ); // content digest for zypper bash completion
- // Finally send notification to plugins
- // NOTE: quick hack looking for spacewalk plugin only
+ // system-hook: Finally send notification to plugins
+ if ( root() == "/" )
{
- Pathname script( Pathname::assertprefix( _root, ZConfig::instance().pluginsPath()/"system/spacewalk" ) );
- if ( PathInfo( script ).isX() )
- try {
- PluginScript spacewalk( script );
- spacewalk.open();
-
- PluginFrame notify( "PACKAGESETCHANGED" );
- spacewalk.send( notify );
-
- PluginFrame ret( spacewalk.receive() );
- MIL << ret << endl;
- if ( ret.command() == "ERROR" )
- ret.writeTo( WAR ) << endl;
- }
- catch ( const Exception & excpt )
- {
- WAR << excpt.asUserHistory() << endl;
- }
+ PluginExecutor plugins;
+ plugins.load( ZConfig::instance().pluginsPath()/"system" );
+ if ( plugins )
+ plugins.send( PluginFrame( "PACKAGESETCHANGED" ) );
}
}
+ else
+ {
+ // On the fly add missing solv.idx files for bash completion.
+ if ( ! PathInfo(base/"solv.idx").isExist() )
+ sat::updateSolvFileIndex( rpmsolv );
+ }
return build_rpm_solv;
}
system.addSolv( rpmsolv );
}
- sat::Pool::instance().rootDir( _root );
+ satpool.rootDir( _root );
// (Re)Load the requested locales et al.
// If the requested locales are empty, we leave the pool untouched
const LocaleSet & requestedLocales( _requestedLocalesFile.locales() );
if ( ! requestedLocales.empty() )
{
- satpool.setRequestedLocales( requestedLocales );
+ satpool.initRequestedLocales( requestedLocales );
}
}
{
///////////////////////////////////////////////////////////////////
// Prepare execution of commit plugins:
///////////////////////////////////////////////////////////////////
- CommitPlugins commitPlugins;
+ PluginExecutor commitPlugins;
if ( root() == "/" && ! policy_r.dryRun() )
{
- Pathname plugindir( Pathname::assertprefix( _root, ZConfig::instance().pluginsPath()/"commit" ) );
- commitPlugins.load( plugindir );
+ commitPlugins.load( ZConfig::instance().pluginsPath()/"commit" );
}
- if ( ! commitPlugins.empty() )
+ if ( commitPlugins )
commitPlugins.send( transactionPluginFrame( "COMMITBEGIN", steps ) );
///////////////////////////////////////////////////////////////////
// Write out a testcase if we're in dist upgrade mode.
///////////////////////////////////////////////////////////////////
- if ( getZYpp()->resolver()->upgradeMode() )
+ if ( pool_r.resolver().upgradeMode() || pool_r.resolver().upgradingRepos() )
{
if ( ! policy_r.dryRun() )
{
if ( ! policy_r.dryRun() || policy_r.downloadMode() == DownloadOnly )
{
// Prepare the package cache. Pass all items requiring download.
- CommitPackageCache packageCache( root() );
+ CommitPackageCache packageCache;
packageCache.setCommitList( steps.begin(), steps.end() );
bool miss = false;
ManagedFile localfile;
try
{
- // TODO: unify packageCache.get for Package and SrcPackage
- if ( pi->isKind<Package>() )
- {
- localfile = packageCache.get( pi );
- }
- else if ( pi->isKind<SrcPackage>() )
- {
- repo::RepoMediaAccess access;
- repo::SrcPackageProvider prov( access );
- localfile = prov.provideSrcPackage( pi->asKind<SrcPackage>() );
- }
- else
- {
- INT << "Don't know howto cache: Neither Package nor SrcPackage: " << pi << endl;
- continue;
- }
+ localfile = packageCache.get( pi );
localfile.resetDispose(); // keep the package file in the cache
}
catch ( const AbortRequestException & exp )
///////////////////////////////////////////////////////////////////
// Send result to commit plugins:
///////////////////////////////////////////////////////////////////
- if ( ! commitPlugins.empty() )
+ if ( commitPlugins )
commitPlugins.send( transactionPluginFrame( "COMMITEND", steps ) );
///////////////////////////////////////////////////////////////////
// COMMIT internal
//
///////////////////////////////////////////////////////////////////
+ namespace
+ {
+ struct NotifyAttemptToModify
+ {
+ NotifyAttemptToModify( ZYppCommitResult & result_r ) : _result( result_r ) {}
+
+ void operator()()
+ { if ( _guard ) { _result.attemptToModify( true ); _guard = false; } }
+
+ TrueBool _guard;
+ ZYppCommitResult & _result;
+ };
+ } // namespace
+
void TargetImpl::commit( const ZYppCommitPolicy & policy_r,
CommitPackageCache & packageCache_r,
ZYppCommitResult & result_r )
ZYppCommitResult::TransactionStepList & steps( result_r.rTransactionStepList() );
MIL << "TargetImpl::commit(<list>" << policy_r << ")" << steps.size() << endl;
+ HistoryLog().stampCommand();
+
+ // Send notification once upon 1st call to rpm
+ NotifyAttemptToModify attemptToModify( result_r );
+
bool abort = false;
+
RpmPostTransCollector postTransCollector( _root );
std::vector<sat::Solvable> successfullyInstalledPackages;
TargetImpl::PoolItemList remaining;
if (policy_r.rpmExcludeDocs()) flags |= rpm::RPMINST_EXCLUDEDOCS;
if (policy_r.rpmNoSignature()) flags |= rpm::RPMINST_NOSIGNATURE;
+ attemptToModify();
try
{
progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
rpm::RpmInstFlags flags( policy_r.rpmInstFlags() & rpm::RPMINST_JUSTDB );
flags |= rpm::RPMINST_NODEPS;
if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
+
+ attemptToModify();
try
{
rpm().removePackage( p, flags );
}
return std::string();
}
- } // namescpace
+ } // namespace
///////////////////////////////////////////////////////////////////
Product::constPtr TargetImpl::baseProduct() const
return RequestedLocalesFile( home(needroot) / "RequestedLocales" ).locales();
}
+ void TargetImpl::updateAutoInstalled()
+ {
+ MIL << "updateAutoInstalled if changed..." << endl;
+ SolvIdentFile::Data newdata;
+ for ( auto id : sat::Pool::instance().autoInstalled() )
+ newdata.insert( IdString(id) ); // explicit ctor!
+ _autoInstalledFile.setData( std::move(newdata) );
+ }
+
std::string TargetImpl::targetDistribution() const
{ return baseproductdata( _root ).registerTarget(); }
// static version:
}
///////////////////////////////////////////////////////////////////
+ namespace
+ {
+ std::string guessAnonymousUniqueId( const Pathname & root_r )
+ {
+ // bsc#1024741: Omit creating a new uid for chrooted systems (if it already has one, fine)
+ std::string ret( firstNonEmptyLineIn( root_r / "/var/lib/zypp/AnonymousUniqueId" ) );
+ if ( ret.empty() && root_r != "/" )
+ {
+ // if it has nonoe, use the outer systems one
+ ret = firstNonEmptyLineIn( "/var/lib/zypp/AnonymousUniqueId" );
+ }
+ return ret;
+ }
+ }
std::string TargetImpl::anonymousUniqueId() const
{
- return firstNonEmptyLineIn( home() / "AnonymousUniqueId" );
+ return guessAnonymousUniqueId( root() );
}
// static version:
std::string TargetImpl::anonymousUniqueId( const Pathname & root_r )
{
- return firstNonEmptyLineIn( staticGuessRoot(root_r) / "/var/lib/zypp/AnonymousUniqueId" );
+ return guessAnonymousUniqueId( staticGuessRoot(root_r) );
}
///////////////////////////////////////////////////////////////////
{
// provide on local disk
ManagedFile localfile = provideSrcPackage(srcPackage_r);
+ // create a installation progress report proxy
+ RpmInstallPackageReceiver progress( srcPackage_r );
+ progress.connect(); // disconnected on destruction.
// install it
rpm().installPackage ( localfile );
}