diff --git a/outputview/outputexecutejob.cpp b/outputview/outputexecutejob.cpp index 141de0f588..89de34b2c8 100644 --- a/outputview/outputexecutejob.cpp +++ b/outputview/outputexecutejob.cpp @@ -1,453 +1,490 @@ /* This file is part of KDevelop Copyright 2012 Ivan Shapovalov This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "outputexecutejob.h" #include "outputmodel.h" #include "outputdelegate.h" #include #include #include #include #include #include #include #include namespace KDevelop { -OutputExecuteJob::OutputExecuteJob( QObject* parent, OutputJob::OutputJobVerbosity verbosity ): - OutputJob( parent, verbosity ), - m_process( new KProcess( this ) ), - m_lineMaker( new ProcessLineMaker( this ) ), // do not assign process to the line maker as we'll feed it data ourselves - m_status( JobNotStarted ), - m_properties( DisplayStdout ), +class OutputExecuteJobPrivate +{ +public: + OutputExecuteJobPrivate( KDevelop::OutputExecuteJob* owner ); + + QString joinCommandLine() const; + QString getJobName(); + + static void mergeEnvironment( QProcessEnvironment& dest, const QMap& src ); + QProcessEnvironment effectiveEnvironment() const; + QStringList effectiveCommandLine() const; + + OutputExecuteJob* m_owner; + + KProcess* m_process; + ProcessLineMaker* m_lineMaker; + OutputExecuteJob::JobStatus m_status; + OutputExecuteJob::JobProperties m_properties; + OutputModel::OutputFilterStrategy m_filteringStrategy; + QStringList m_arguments; + QStringList m_privilegedExecutionCommand; + KUrl m_workingDirectory; + QString m_environmentProfile; + QMap m_environmentOverrides; + QString m_jobName; + bool m_outputStarted; + + QByteArray m_processStdout; + QByteArray m_processStderr; +}; + +OutputExecuteJobPrivate::OutputExecuteJobPrivate( OutputExecuteJob* owner ) : + m_owner( owner ), + m_process( new KProcess( m_owner ) ), + m_lineMaker( new ProcessLineMaker( m_owner ) ), // do not assign process to the line maker as we'll feed it data ourselves + m_status( OutputExecuteJob::JobNotStarted ), + m_properties( OutputExecuteJob::DisplayStdout ), m_filteringStrategy( OutputModel::NoFilter ), m_arguments(), m_privilegedExecutionCommand(), m_workingDirectory(), m_environmentProfile(), m_environmentOverrides(), m_jobName(), m_outputStarted( false ), m_processStdout(), m_processStderr() { - m_process->setOutputChannelMode( KProcess::SeparateChannels ); - m_process->setTextModeEnabled( true ); +} + +OutputExecuteJob::OutputExecuteJob( QObject* parent, OutputJob::OutputJobVerbosity verbosity ): + OutputJob( parent, verbosity ), + d( new OutputExecuteJobPrivate( this ) ) +{ + d->m_process->setOutputChannelMode( KProcess::SeparateChannels ); + d->m_process->setTextModeEnabled( true ); - connect( m_process, SIGNAL(finished(int,QProcess::ExitStatus)), - SLOT(childProcessExited(int,QProcess::ExitStatus)) ); - connect( m_process, SIGNAL(error(QProcess::ProcessError)), - SLOT(childProcessError(QProcess::ProcessError)) ); - connect( m_process, SIGNAL(readyReadStandardOutput()), - SLOT(childProcessStdout()) ); - connect( m_process, SIGNAL(readyReadStandardError()), - SLOT(childProcessStderr()) ); + connect( d->m_process, SIGNAL( finished( int, QProcess::ExitStatus ) ), + SLOT( childProcessExited( int, QProcess::ExitStatus ) ) ); + connect( d->m_process, SIGNAL( error( QProcess::ProcessError ) ), + SLOT( childProcessError( QProcess::ProcessError ) ) ); + connect( d->m_process, SIGNAL( readyReadStandardOutput() ), + SLOT( childProcessStdout() ) ); + connect( d->m_process, SIGNAL( readyReadStandardError() ), + SLOT( childProcessStderr() ) ); } OutputExecuteJob::~OutputExecuteJob() { - if( m_process->state() != QProcess::NotRunning ) { + if( d->m_process->state() != QProcess::NotRunning ) { doKill(); } - Q_ASSERT( m_process->state() == QProcess::NotRunning ); + Q_ASSERT( d->m_process->state() == QProcess::NotRunning ); + delete d; } OutputExecuteJob::JobStatus OutputExecuteJob::status() const { - return m_status; + return d->m_status; } OutputModel* OutputExecuteJob::model() const { return dynamic_cast ( OutputJob::model() ); } QStringList OutputExecuteJob::commandLine() const { - return m_arguments; + return d->m_arguments; } OutputExecuteJob& OutputExecuteJob::operator<<( const QString& argument ) { - m_arguments << argument; + d->m_arguments << argument; return *this; } OutputExecuteJob& OutputExecuteJob::operator<<( const QStringList& arguments ) { - m_arguments << arguments; + d->m_arguments << arguments; return *this; } QStringList OutputExecuteJob::privilegedExecutionCommand() const { - return m_privilegedExecutionCommand; + return d->m_privilegedExecutionCommand; } void OutputExecuteJob::setPrivilegedExecutionCommand( const QStringList& command ) { - m_privilegedExecutionCommand = command; + d->m_privilegedExecutionCommand = command; } void OutputExecuteJob::setJobName( const QString& name ) { - m_jobName = name; - updateJobName(); + d->m_jobName = name; + QString jobName = d->getJobName(); + setObjectName( jobName ); + setTitle( jobName ); } KUrl OutputExecuteJob::workingDirectory() const { - return m_workingDirectory; + return d->m_workingDirectory; } void OutputExecuteJob::setWorkingDirectory( const KUrl& url ) { - m_workingDirectory = url; + d->m_workingDirectory = url; } void OutputExecuteJob::start() { - Q_ASSERT( m_status == JobNotStarted ); - m_status = JobRunning; + Q_ASSERT( d->m_status == JobNotStarted ); + d->m_status = JobRunning; - const bool isBuilder = m_properties.testFlag( IsBuilderHint ); + const bool isBuilder = d->m_properties.testFlag( IsBuilderHint ); const KUrl effectiveWorkingDirectory = workingDirectory(); if( effectiveWorkingDirectory.isEmpty() ) { - if( m_properties.testFlag( NeedWorkingDirectory ) ) { + if( d->m_properties.testFlag( NeedWorkingDirectory ) ) { // A directory is not given, but we need it. setError( InvalidWorkingDirectoryError ); if( isBuilder ) { setErrorText( i18n( "No build directory specified for a builder job." ) ); } else { setErrorText( i18n( "No working directory specified for a process." ) ); } return emitResult(); } setModel( new OutputModel ); } else { // Basic sanity checks. if( !effectiveWorkingDirectory.isValid() ) { setError( InvalidWorkingDirectoryError ); if( isBuilder ) { setErrorText( i18n( "Invalid build directory '%1'", effectiveWorkingDirectory.prettyUrl() ) ); } else { setErrorText( i18n( "Invalid working directory '%1'", effectiveWorkingDirectory.prettyUrl() ) ); } return emitResult(); } else if( !effectiveWorkingDirectory.isLocalFile() ) { setError( InvalidWorkingDirectoryError ); if( isBuilder ) { setErrorText( i18n( "Build directory '%1' is not a local path", effectiveWorkingDirectory.prettyUrl() ) ); } else { setErrorText( i18n( "Working directory '%1' is not a local path", effectiveWorkingDirectory.prettyUrl() ) ); } return emitResult(); } QFileInfo workingDirInfo( effectiveWorkingDirectory.toLocalFile() ); if( !workingDirInfo.isDir() ) { // If a working directory does not actually exist, either bail out or create it empty, // depending on what we need by properties. // We use a dedicated bool variable since !isDir() may also mean that it exists, // but is not a directory, or a symlink to an inexistent object. bool successfullyCreated = false; - if( !m_properties.testFlag( CheckWorkingDirectory ) ) { + if( !d->m_properties.testFlag( CheckWorkingDirectory ) ) { successfullyCreated = QDir( effectiveWorkingDirectory.directory() ).mkdir( effectiveWorkingDirectory.fileName() ); } if( !successfullyCreated ) { setError( InvalidWorkingDirectoryError ); if( isBuilder ) { setErrorText( i18n( "Build directory '%1' does not exist or is not a directory", effectiveWorkingDirectory.prettyUrl() ) ); } else { setErrorText( i18n( "Working directory '%1' does not exist or is not a directory", effectiveWorkingDirectory.prettyUrl() ) ); } return emitResult(); } } setModel( new OutputModel( effectiveWorkingDirectory ) ); } Q_ASSERT( model() ); - model()->setFilteringStrategy( m_filteringStrategy ); + model()->setFilteringStrategy( d->m_filteringStrategy ); setDelegate( new OutputDelegate ); // Slots hasRawStdout() and hasRawStderr() are responsible // for feeding raw data to the line maker; so property-based channel filtering is implemented there. - if( m_properties.testFlag( PostProcessOutput ) ) { - connect( m_lineMaker, SIGNAL( receivedStdoutLines( QStringList ) ), + if( d->m_properties.testFlag( PostProcessOutput ) ) { + connect( d->m_lineMaker, SIGNAL( receivedStdoutLines( QStringList ) ), SLOT( postProcessStdout( QStringList ) ) ); - connect( m_lineMaker, SIGNAL( receivedStderrLines( QStringList ) ), + connect( d->m_lineMaker, SIGNAL( receivedStderrLines( QStringList ) ), SLOT( postProcessStderr( QStringList ) ) ); } else { - connect( m_lineMaker, SIGNAL( receivedStdoutLines( QStringList ) ), model(), + connect( d->m_lineMaker, SIGNAL( receivedStdoutLines( QStringList ) ), model(), SLOT(appendLines(QStringList)) ); - connect( m_lineMaker, SIGNAL( receivedStderrLines( QStringList ) ), model(), + connect( d->m_lineMaker, SIGNAL( receivedStderrLines( QStringList ) ), model(), SLOT(appendLines(QStringList)) ); } - if( !m_properties.testFlag( NoSilentOutput ) || verbosity() != Silent ) { - m_outputStarted = true; + if( !d->m_properties.testFlag( NoSilentOutput ) || verbosity() != Silent ) { + d->m_outputStarted = true; startOutput(); } - const QString joinedCommandLine = joinCommandLine(); + const QString joinedCommandLine = d->joinCommandLine(); QString headerLine; if( !effectiveWorkingDirectory.isEmpty() ) { headerLine = effectiveWorkingDirectory.toLocalFile( KUrl::RemoveTrailingSlash ) + "> " + joinedCommandLine; } else { headerLine = joinedCommandLine; } model()->appendLine( headerLine ); if( !effectiveWorkingDirectory.isEmpty() ) { - m_process->setWorkingDirectory( effectiveWorkingDirectory.toLocalFile() ); + d->m_process->setWorkingDirectory( effectiveWorkingDirectory.toLocalFile() ); } - m_process->setProcessEnvironment( effectiveEnvironment() ); - m_process->setProgram( effectiveCommandLine() ); - m_process->start(); + d->m_process->setProcessEnvironment( d->effectiveEnvironment() ); + d->m_process->setProgram( d->effectiveCommandLine() ); + d->m_process->start(); } bool OutputExecuteJob::doKill() { const int terminateKillTimeout = 1000; // msecs - if( m_status != JobRunning ) + if( d->m_status != JobRunning ) return true; - m_status = JobCanceled; + d->m_status = JobCanceled; - m_process->terminate(); - bool terminated = m_process->waitForFinished( terminateKillTimeout ); + d->m_process->terminate(); + bool terminated = d->m_process->waitForFinished( terminateKillTimeout ); if( !terminated ) { - m_process->kill(); - terminated = m_process->waitForFinished( terminateKillTimeout ); + d->m_process->kill(); + terminated = d->m_process->waitForFinished( terminateKillTimeout ); } - m_lineMaker->flushBuffers(); + d->m_lineMaker->flushBuffers(); if( terminated ) { model()->appendLine( i18n( "*** Aborted ***" ) ); } else { // It survived SIGKILL, leave it alone... model()->appendLine( i18n( "*** Warning: could not kill the process ***" ) ); } return true; } void OutputExecuteJob::childProcessError( QProcess::ProcessError processError ) { // This can be called twice: one time via an error() signal, and second - from childProcessExited(). // Avoid doing things in second time. - if( m_status != JobRunning ) + if( d->m_status != OutputExecuteJob::JobRunning ) return; - m_status = JobFailed; + d->m_status = OutputExecuteJob::JobFailed; QString errorValue; switch( processError ) { case QProcess::FailedToStart: - errorValue = i18n("%1 has failed to start", m_arguments.first()); + errorValue = i18n("%1 has failed to start", d->m_arguments.first()); break; case QProcess::Crashed: - errorValue = i18n("%1 has crashed", m_arguments.first()); + errorValue = i18n("%1 has crashed", d->m_arguments.first()); break; case QProcess::ReadError: errorValue = i18n("Read error"); break; case QProcess::WriteError: errorValue = i18n("Write error"); break; case QProcess::Timedout: errorValue = i18n("Waiting for the process has timed out"); break; default: case QProcess::UnknownError: - errorValue = i18n("Exit code %1", m_process->exitCode()); + errorValue = i18n("Exit code %1", d->m_process->exitCode()); break; } // Show the toolview if it's hidden for the user to be able to diagnose errors. - if( !m_outputStarted ) { - m_outputStarted = true; + if( !d->m_outputStarted ) { + d->m_outputStarted = true; startOutput(); } setError( FailedShownError ); setErrorText( errorValue ); - m_lineMaker->flushBuffers(); + d->m_lineMaker->flushBuffers(); model()->appendLine( i18n("*** Failure: %1 ***", errorValue) ); emitResult(); } void OutputExecuteJob::childProcessExited( int exitCode, QProcess::ExitStatus exitStatus ) { - if( m_status != JobRunning ) + if( d->m_status != JobRunning ) return; if( exitStatus == QProcess::CrashExit ) { childProcessError( QProcess::Crashed ); } else if ( exitCode != 0 ) { childProcessError( QProcess::UnknownError ); } else { - m_status = JobSucceeded; - m_lineMaker->flushBuffers(); + d->m_status = JobSucceeded; + d->m_lineMaker->flushBuffers(); model()->appendLine( i18n("*** Finished ***") ); emitResult(); } } void OutputExecuteJob::childProcessStdout() { - QByteArray out = m_process->readAllStandardOutput(); - if( m_properties.testFlag( AccumulateStdout ) ) { - m_processStdout += out; + QByteArray out = d->m_process->readAllStandardOutput(); + if( d->m_properties.testFlag( AccumulateStdout ) ) { + d->m_processStdout += out; } - if( m_properties.testFlag( DisplayStdout ) ) { - m_lineMaker->slotReceivedStdout( out ); + if( d->m_properties.testFlag( DisplayStdout ) ) { + d->m_lineMaker->slotReceivedStdout( out ); } } void OutputExecuteJob::childProcessStderr() { - QByteArray err = m_process->readAllStandardError(); - if( m_properties.testFlag( AccumulateStderr ) ) { - m_processStderr += err; + QByteArray err = d->m_process->readAllStandardError(); + if( d->m_properties.testFlag( AccumulateStderr ) ) { + d->m_processStderr += err; } - if( m_properties.testFlag( DisplayStderr ) ) { - m_lineMaker->slotReceivedStderr( err ); + if( d->m_properties.testFlag( DisplayStderr ) ) { + d->m_lineMaker->slotReceivedStderr( err ); } } void OutputExecuteJob::postProcessStdout( const QStringList& lines ) { model()->appendLines( lines ); } void OutputExecuteJob::postProcessStderr( const QStringList& lines ) { model()->appendLines( lines ); } void OutputExecuteJob::setFilteringStrategy( OutputModel::OutputFilterStrategy strategy ) { - m_filteringStrategy = strategy; + d->m_filteringStrategy = strategy; } OutputExecuteJob::JobProperties OutputExecuteJob::properties() const { - return m_properties; + return d->m_properties; } void OutputExecuteJob::setProperties( OutputExecuteJob::JobProperties properties, bool override ) { if( override ) { - m_properties = properties; + d->m_properties = properties; } else { - m_properties |= properties; + d->m_properties |= properties; } } void OutputExecuteJob::unsetProperties( OutputExecuteJob::JobProperties properties ) { - m_properties &= ~properties; + d->m_properties &= ~properties; } QString OutputExecuteJob::environmentProfile() const { - return m_environmentProfile; + return d->m_environmentProfile; } void OutputExecuteJob::setEnvironmentProfile( const QString& profile ) { - m_environmentProfile = profile; + d->m_environmentProfile = profile; } void OutputExecuteJob::addEnvironmentOverride( const QString& name, const QString& value ) { - m_environmentOverrides[name] = value; + d->m_environmentOverrides[name] = value; } void OutputExecuteJob::removeEnvironmentOverride( const QString& name ) { - m_environmentOverrides.remove( name ); + d->m_environmentOverrides.remove( name ); } -void OutputExecuteJob::mergeEnvironment( QProcessEnvironment& dest, const QMap& src ) +void OutputExecuteJobPrivate::mergeEnvironment( QProcessEnvironment& dest, const QMap& src ) { for( QMap::const_iterator it = src.begin(); it != src.end(); ++it ) { dest.insert( it.key(), it.value() ); } } -QProcessEnvironment OutputExecuteJob::effectiveEnvironment() const +QProcessEnvironment OutputExecuteJobPrivate::effectiveEnvironment() const { QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); const EnvironmentGroupList environmentGroup( KGlobal::config() ); - mergeEnvironment( environment, environmentGroup.variables( environmentProfile() ) ); - mergeEnvironment( environment, m_environmentOverrides ); - if( m_properties.testFlag( PortableMessages ) ) { + OutputExecuteJobPrivate::mergeEnvironment( environment, environmentGroup.variables( m_owner->environmentProfile() ) ); + OutputExecuteJobPrivate::mergeEnvironment( environment, m_environmentOverrides ); + if( m_properties.testFlag( OutputExecuteJob::PortableMessages ) ) { environment.remove( "LC_ALL" ); environment.insert( "LC_MESSAGES", "C" ); } return environment; } -QString OutputExecuteJob::joinCommandLine() const +QString OutputExecuteJobPrivate::joinCommandLine() const { return KShell::joinArgs( effectiveCommandLine() ); } -QStringList OutputExecuteJob::effectiveCommandLine() const +QStringList OutputExecuteJobPrivate::effectiveCommandLine() const { // If we need to use a su-like helper, invoke it as // "helper -- our command line". - QStringList privilegedCommand = privilegedExecutionCommand(); + QStringList privilegedCommand = m_owner->privilegedExecutionCommand(); if( !privilegedCommand.isEmpty() ) { - return QStringList() << privilegedExecutionCommand() << "--" << commandLine(); + return QStringList() << m_owner->privilegedExecutionCommand() << "--" << m_owner->commandLine(); } else { - return commandLine(); + return m_owner->commandLine(); } } -void OutputExecuteJob::updateJobName() +QString OutputExecuteJobPrivate::getJobName() { const QString joinedCommandLine = joinCommandLine(); - QString jobName; - if( m_properties.testFlag( AppendProcessString ) ) { + if( m_properties.testFlag( OutputExecuteJob::AppendProcessString ) ) { if( !m_jobName.isEmpty() ) { - jobName = m_jobName + ": " + joinedCommandLine; + return m_jobName + ": " + joinedCommandLine; } else { - jobName = joinedCommandLine; + return joinedCommandLine; } } else { - jobName = m_jobName; + return m_jobName; } - setObjectName( jobName ); - setTitle( jobName ); } } // namespace KDevelop #include "outputexecutejob.moc" \ No newline at end of file diff --git a/outputview/outputexecutejob.h b/outputview/outputexecutejob.h index 113502fb89..438b239d51 100644 --- a/outputview/outputexecutejob.h +++ b/outputview/outputexecutejob.h @@ -1,270 +1,250 @@ /* This file is part of KDevelop C opyright 2012 Ivan Shapoval*ov This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef OUTPUTEXECUTEJOB_H #define OUTPUTEXECUTEJOB_H #include "outputjob.h" #include "outputmodel.h" #include class KUrl; class KProcess; namespace KDevelop { class ProcessLineMaker; +class OutputExecuteJobPrivate; class KDEVPLATFORMOUTPUTVIEW_EXPORT OutputExecuteJob : public OutputJob { Q_OBJECT public: enum JobStatus { JobRunning = 0, /**< The job is running */ JobSucceeded = 1, /**< The job has succeeded */ JobCanceled = 2, /**< The job has been cancelled */ JobFailed = 3, /**< The job has failed */ JobNotStarted = 4 /**< The job hasn't been started so far */ }; enum { InvalidWorkingDirectoryError = OutputJob::UserDefinedError, UserDefinedError }; enum JobProperty { AppendProcessString, /**< Whether to append a process string to the user-specified job name */ NeedWorkingDirectory, /**< Whether to require a non-empty working directory to be provided */ CheckWorkingDirectory, /**< Whether to check that the working directory actually exists (and not to create it if needed) */ PortableMessages, /**< Whether to set LC_MESSAGES=C in the process' environment */ DisplayStdout, /**< Whether to pass process' stdout to the output model */ AccumulateStdout, /**< Whether to save process' stdout to the internal byte-array buffer for further consumption */ DisplayStderr, /**< Whether to pass process' stderr to the output model */ AccumulateStderr, /**< Whether to save process' stderr to the internal byte-array buffer for further consumption */ NoSilentOutput, /**< Whether to call \ref startOutput() only if verbosity is \ref OutputJob::Verbose */ PostProcessOutput, /**< Whether to connect line maker's signals to \ref postProcessStdout() and \ref postProcessStderr() */ IsBuilderHint, /**< Whether to use builder-specific messages to talk to user (e. g. "build directory" instead of "working directory" */ }; Q_FLAGS(JobProperty JobProperties) Q_DECLARE_FLAGS(JobProperties, JobProperty) OutputExecuteJob( QObject* parent = 0, OutputJobVerbosity verbosity = OutputJob::Verbose ); virtual ~OutputExecuteJob(); /** * Get the job's status (associated with the process). * * @returns The job's status. * @see JobStatus */ JobStatus status() const; /** * Get the job's output model. * * @returns The job's output model, downcasted to \ref OutputModel */ OutputModel* model() const; /** * Returns a working directory for the job's process. * * @returns URL which has been set through \ref setWorkingDirectory(); empty URL if unset. */ virtual KUrl workingDirectory() const; /** * Set a working directory for the job's process. * Effective if \ref workingDirectory() hasn't been overridden. * * @param directory a valid local directory URL, or an empty URL to unset. */ void setWorkingDirectory( const KUrl& directory ); /** * Get process' command line. * * @returns The command line for the process, with first element in list being the program path. */ virtual QStringList commandLine() const; /** * Append an element to the command line argument list for this process. * If no executable is set yet, it will be set instead. * Effective if \ref commandLine() hasn't been overridden. * * @param argument the argument to add */ OutputExecuteJob& operator<<( const QString& argument ); /** * Append a list of elements to the command line argument list for this process. * If no executable is set yet, it will be set from the first argument in given list. * Effective if \ref commandLine() hasn't been overridden. * * @param arguments the arguments to add */ OutputExecuteJob& operator<<( const QStringList& arguments ); /** * Get the privilege escalation command ("su", "sudo", etc.) used for the job's process. * * @returns The privilege escalation command name and arguments; empty list if not set. */ virtual QStringList privilegedExecutionCommand() const; /** * Set the privilege escalation command ("su", "sudo", etc.) which will be used for the job's process. * Effective if \ref privilegedExecutionCommand() hasn't been overridden. * * @param command The privilege escalation command's name and arguments; empty list to unset. * @see privilegedCommand */ void setPrivilegedExecutionCommand( const QStringList& command ); /** * A convenience function to set the job name. * * Calls \ref setTitle() and \ref setObjectName(). * * @note If you need the command-line to be appended to the job name, * make sure that it is already configured upon calling this function. * * @param name The name to set; empty string to use default (process string). */ void setJobName( const QString& name ); /** * Set the filtering strategy for the output model. */ void setFilteringStrategy( OutputModel::OutputFilterStrategy strategy ); /** * Get the current properties of the job. * * @note Default-set properties are: \ref DisplayStdout. */ virtual JobProperties properties() const; /** * Set properties of the job. * Effective if \ref properties() hasn't been overridden. * * @param properties Which flags to add to the job. * @param override Whether to assign instead of doing bitwise OR. * @see JobProperties, properties(), unsetProperties() */ void setProperties( JobProperties properties, bool override = false ); /** * Unset properties of the job. * * @param properties Which flags to remove from the job * @see JobProperties, properties(), setProperties() */ void unsetProperties( JobProperties properties ); /** * Add a variable to the job's process environment. * * The variables added with this method override ones from the system environment and * the global environment profile, but are overridden by "PortableMessages" property. * * @param name The name of a variable to add * @param value The value of a variable to add; empty string to unset. */ void addEnvironmentOverride( const QString& name, const QString& value ); /** * Remove a variable from the override set. * * @param name The name of a variable to remove. * @note This does not force a variable to empty value; this is to undo the overriding itself. */ void removeEnvironmentOverride( const QString& name ); /** * Get the global environment profile name for the job's process. * * @returns The environment profile name to use in the job's process; empty if unset. */ virtual QString environmentProfile() const; /** * Set the environment profile name for the job's process. * Effective if \ref environmentProfile() hasn't been overridden. * * @param profile The name of profile to set. */ void setEnvironmentProfile( const QString& profile ); virtual void start(); protected: virtual bool doKill(); protected slots: // Redefine these functions if you want to post-process the output somehow // before it hits the output model. // Default implementations for either function call "model()->appendLines( lines );". // Do the same if you need the output to be visible. virtual void postProcessStdout( const QStringList& lines ); virtual void postProcessStderr( const QStringList& lines ); +private: + OutputExecuteJobPrivate* d; + private slots: void childProcessExited( int exitCode, QProcess::ExitStatus exitStatus ); void childProcessError( QProcess::ProcessError processError ); void childProcessStdout(); void childProcessStderr(); - -private: - QString joinCommandLine() const; - void updateJobName(); - - static void mergeEnvironment( QProcessEnvironment& dest, const QMap& src ); - QProcessEnvironment effectiveEnvironment() const; - QStringList effectiveCommandLine() const; - - KProcess* m_process; - ProcessLineMaker* m_lineMaker; - JobStatus m_status; - JobProperties m_properties; - OutputModel::OutputFilterStrategy m_filteringStrategy; - QStringList m_arguments; - QStringList m_privilegedExecutionCommand; - KUrl m_workingDirectory; - QString m_environmentProfile; - QMap m_environmentOverrides; - QString m_jobName; - bool m_outputStarted; - - QByteArray m_processStdout; - QByteArray m_processStderr; }; } // namespace KDevelop Q_DECLARE_OPERATORS_FOR_FLAGS(KDevelop::OutputExecuteJob::JobProperties); #endif // OUTPUTEXECUTEJOB_H \ No newline at end of file