forked from qt-creator/qt-creator
Introduce ExitCodeInterpreter, useful when exit code != 0 is valid
Task-number: QTCREATORBUG-10207 Change-Id: I3b440d40a968f09afc613b686ee50da6465ad88e Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
This commit is contained in:
@@ -149,6 +149,12 @@ QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessRes
|
||||
return str;
|
||||
}
|
||||
|
||||
SynchronousProcessResponse::Result ExitCodeInterpreter::interpretExitCode(int code) const
|
||||
{
|
||||
return code ? SynchronousProcessResponse::FinishedError
|
||||
: SynchronousProcessResponse::Finished;
|
||||
}
|
||||
|
||||
// Data for one channel buffer (stderr/stdout)
|
||||
struct ChannelBuffer {
|
||||
ChannelBuffer();
|
||||
@@ -197,6 +203,7 @@ struct SynchronousProcessPrivate {
|
||||
void clearForRun();
|
||||
|
||||
QTextCodec *m_codec;
|
||||
ExitCodeInterpreter *m_exitCodeInterpreter;
|
||||
QTextCodec::ConverterState m_stdOutState;
|
||||
QTextCodec::ConverterState m_stdErrState;
|
||||
TerminalControllingProcess m_process;
|
||||
@@ -216,6 +223,7 @@ struct SynchronousProcessPrivate {
|
||||
|
||||
SynchronousProcessPrivate::SynchronousProcessPrivate() :
|
||||
m_codec(QTextCodec::codecForLocale()),
|
||||
m_exitCodeInterpreter(0),
|
||||
m_hangTimerCount(0),
|
||||
m_maxHangTimerCount(defaultMaxHangTimerCount),
|
||||
m_startFailure(false),
|
||||
@@ -339,6 +347,16 @@ void SynchronousProcess::setFlags(unsigned tc)
|
||||
d->m_process.setFlags(tc);
|
||||
}
|
||||
|
||||
void SynchronousProcess::setExitCodeInterpreter(ExitCodeInterpreter *interpreter)
|
||||
{
|
||||
d->m_exitCodeInterpreter = interpreter;
|
||||
}
|
||||
|
||||
ExitCodeInterpreter *SynchronousProcess::exitCodeInterpreter() const
|
||||
{
|
||||
return d->m_exitCodeInterpreter;
|
||||
}
|
||||
|
||||
void SynchronousProcess::setWorkingDirectory(const QString &workingDirectory)
|
||||
{
|
||||
d->m_process.setWorkingDirectory(workingDirectory);
|
||||
@@ -451,9 +469,14 @@ void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e)
|
||||
if (debug)
|
||||
qDebug() << Q_FUNC_INFO << exitCode << e;
|
||||
d->m_hangTimerCount = 0;
|
||||
|
||||
ExitCodeInterpreter defaultInterpreter(this);
|
||||
ExitCodeInterpreter *currentInterpreter = d->m_exitCodeInterpreter
|
||||
? d->m_exitCodeInterpreter : &defaultInterpreter;
|
||||
|
||||
switch (e) {
|
||||
case QProcess::NormalExit:
|
||||
d->m_result.result = exitCode ? SynchronousProcessResponse::FinishedError : SynchronousProcessResponse::Finished;
|
||||
d->m_result.result = currentInterpreter->interpretExitCode(exitCode);
|
||||
d->m_result.exitCode = exitCode;
|
||||
break;
|
||||
case QProcess::CrashExit:
|
||||
|
@@ -71,6 +71,14 @@ struct QTCREATOR_UTILS_EXPORT SynchronousProcessResponse
|
||||
|
||||
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse &);
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT ExitCodeInterpreter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ExitCodeInterpreter(QObject *parent) : QObject(parent) {}
|
||||
virtual SynchronousProcessResponse::Result interpretExitCode(int code) const;
|
||||
};
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -115,6 +123,9 @@ public:
|
||||
unsigned flags() const;
|
||||
void setFlags(unsigned);
|
||||
|
||||
void setExitCodeInterpreter(ExitCodeInterpreter *interpreter);
|
||||
ExitCodeInterpreter *exitCodeInterpreter() const;
|
||||
|
||||
SynchronousProcessResponse run(const QString &binary, const QStringList &args);
|
||||
|
||||
// Create a (derived) processes with flags applied.
|
||||
|
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <vcsbase/vcsbaseplugin.h>
|
||||
#include <vcsbase/vcsbaseeditorparameterwidget.h>
|
||||
#include <utils/synchronousprocess.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
@@ -40,6 +41,22 @@
|
||||
namespace Bazaar {
|
||||
namespace Internal {
|
||||
|
||||
class BazaarDiffExitCodeInterpreter : public Utils::ExitCodeInterpreter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BazaarDiffExitCodeInterpreter(QObject *parent) : Utils::ExitCodeInterpreter(parent) {}
|
||||
Utils::SynchronousProcessResponse::Result interpretExitCode(int code) const;
|
||||
|
||||
};
|
||||
|
||||
Utils::SynchronousProcessResponse::Result BazaarDiffExitCodeInterpreter::interpretExitCode(int code) const
|
||||
{
|
||||
if (code < 0 || code > 2)
|
||||
return Utils::SynchronousProcessResponse::FinishedError;
|
||||
return Utils::SynchronousProcessResponse::Finished;
|
||||
}
|
||||
|
||||
BazaarClient::BazaarClient(BazaarSettings *settings) :
|
||||
VcsBase::VcsBaseClient(settings)
|
||||
{
|
||||
@@ -142,6 +159,16 @@ QString BazaarClient::vcsCommandString(VcsCommand cmd) const
|
||||
}
|
||||
}
|
||||
|
||||
Utils::ExitCodeInterpreter *BazaarClient::exitCodeInterpreter(VcsCommand cmd, QObject *parent) const
|
||||
{
|
||||
switch (cmd) {
|
||||
case DiffCommand:
|
||||
return new BazaarDiffExitCodeInterpreter(parent);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList BazaarClient::revisionSpec(const QString &revision) const
|
||||
{
|
||||
QStringList args;
|
||||
|
@@ -61,6 +61,7 @@ public:
|
||||
protected:
|
||||
Core::Id vcsEditorKind(VcsCommand cmd) const;
|
||||
QString vcsCommandString(VcsCommand cmd) const;
|
||||
Utils::ExitCodeInterpreter *exitCodeInterpreter(VcsCommand cmd, QObject *parent) const;
|
||||
QStringList revisionSpec(const QString &revision) const;
|
||||
VcsBase::VcsBaseEditorParameterWidget *createDiffEditor(const QString &workingDir,
|
||||
const QStringList &files,
|
||||
|
@@ -78,10 +78,11 @@ class CommandPrivate
|
||||
{
|
||||
public:
|
||||
struct Job {
|
||||
explicit Job(const QStringList &a, int t);
|
||||
explicit Job(const QStringList &a, int t, Utils::ExitCodeInterpreter *interpreter = 0);
|
||||
|
||||
QStringList arguments;
|
||||
int timeout;
|
||||
Utils::ExitCodeInterpreter *exitCodeInterpreter;
|
||||
};
|
||||
|
||||
CommandPrivate(const QString &binary,
|
||||
@@ -130,9 +131,10 @@ CommandPrivate::~CommandPrivate()
|
||||
delete m_progressParser;
|
||||
}
|
||||
|
||||
CommandPrivate::Job::Job(const QStringList &a, int t) :
|
||||
CommandPrivate::Job::Job(const QStringList &a, int t, Utils::ExitCodeInterpreter *interpreter) :
|
||||
arguments(a),
|
||||
timeout(t)
|
||||
timeout(t),
|
||||
exitCodeInterpreter(interpreter)
|
||||
{
|
||||
// Finished cookie is emitted via queued slot, needs metatype
|
||||
static const int qvMetaId = qRegisterMetaType<QVariant>();
|
||||
@@ -188,14 +190,14 @@ void Command::addFlags(unsigned f)
|
||||
d->m_flags |= f;
|
||||
}
|
||||
|
||||
void Command::addJob(const QStringList &arguments)
|
||||
void Command::addJob(const QStringList &arguments, Utils::ExitCodeInterpreter *interpreter)
|
||||
{
|
||||
addJob(arguments, defaultTimeout());
|
||||
addJob(arguments, defaultTimeout(), interpreter);
|
||||
}
|
||||
|
||||
void Command::addJob(const QStringList &arguments, int timeout)
|
||||
void Command::addJob(const QStringList &arguments, int timeout, Utils::ExitCodeInterpreter *interpreter)
|
||||
{
|
||||
d->m_jobs.push_back(Internal::CommandPrivate::Job(arguments, timeout));
|
||||
d->m_jobs.push_back(Internal::CommandPrivate::Job(arguments, timeout, interpreter));
|
||||
}
|
||||
|
||||
void Command::execute()
|
||||
@@ -249,10 +251,12 @@ void Command::run(QFutureInterface<void> &future)
|
||||
d->m_lastExecExitCode = -1;
|
||||
d->m_lastExecSuccess = true;
|
||||
for (int j = 0; j < count; j++) {
|
||||
const int timeOutSeconds = d->m_jobs.at(j).timeout;
|
||||
const Internal::CommandPrivate::Job &job = d->m_jobs.at(j);
|
||||
const int timeOutSeconds = job.timeout;
|
||||
Utils::SynchronousProcessResponse resp = runVcs(
|
||||
d->m_jobs.at(j).arguments,
|
||||
timeOutSeconds >= 0 ? timeOutSeconds * 1000 : -1);
|
||||
job.arguments,
|
||||
timeOutSeconds >= 0 ? timeOutSeconds * 1000 : -1,
|
||||
job.exitCodeInterpreter);
|
||||
stdOut += resp.stdOut;
|
||||
stdErr += resp.stdErr;
|
||||
d->m_lastExecExitCode = resp.exitCode;
|
||||
@@ -309,7 +313,8 @@ signals:
|
||||
void appendMessage(const QString &text);
|
||||
};
|
||||
|
||||
Utils::SynchronousProcessResponse Command::runVcs(const QStringList &arguments, int timeoutMS)
|
||||
Utils::SynchronousProcessResponse Command::runVcs(const QStringList &arguments, int timeoutMS,
|
||||
Utils::ExitCodeInterpreter *interpreter)
|
||||
{
|
||||
Utils::SynchronousProcessResponse response;
|
||||
OutputProxy outputProxy;
|
||||
@@ -353,9 +358,10 @@ Utils::SynchronousProcessResponse Command::runVcs(const QStringList &arguments,
|
||||
// if (d->m_flags & ExpectRepoChanges)
|
||||
// Core::DocumentManager::expectDirectoryChange(d->m_workingDirectory);
|
||||
if (d->m_flags & VcsBasePlugin::FullySynchronously) {
|
||||
response = runSynchronous(arguments, timeoutMS);
|
||||
response = runSynchronous(arguments, timeoutMS, interpreter);
|
||||
} else {
|
||||
Utils::SynchronousProcess process;
|
||||
process.setExitCodeInterpreter(interpreter);
|
||||
connect(this, SIGNAL(doTerminate()), &process, SLOT(terminate()));
|
||||
if (!d->m_workingDirectory.isEmpty())
|
||||
process.setWorkingDirectory(d->m_workingDirectory);
|
||||
@@ -412,7 +418,8 @@ Utils::SynchronousProcessResponse Command::runVcs(const QStringList &arguments,
|
||||
return response;
|
||||
}
|
||||
|
||||
Utils::SynchronousProcessResponse Command::runSynchronous(const QStringList &arguments, int timeoutMS)
|
||||
Utils::SynchronousProcessResponse Command::runSynchronous(const QStringList &arguments, int timeoutMS,
|
||||
Utils::ExitCodeInterpreter *interpreter)
|
||||
{
|
||||
Utils::SynchronousProcessResponse response;
|
||||
|
||||
@@ -465,15 +472,15 @@ Utils::SynchronousProcessResponse Command::runSynchronous(const QStringList &arg
|
||||
}
|
||||
}
|
||||
|
||||
Utils::ExitCodeInterpreter defaultInterpreter(this);
|
||||
Utils::ExitCodeInterpreter *currentInterpreter = interpreter ? interpreter : &defaultInterpreter;
|
||||
// Result
|
||||
if (timedOut) {
|
||||
response.result = Utils::SynchronousProcessResponse::Hang;
|
||||
} else if (process->exitStatus() != QProcess::NormalExit) {
|
||||
response.result = Utils::SynchronousProcessResponse::TerminatedAbnormally;
|
||||
} else {
|
||||
response.result = process->exitCode() == 0 ?
|
||||
Utils::SynchronousProcessResponse::Finished :
|
||||
Utils::SynchronousProcessResponse::FinishedError;
|
||||
response.result = currentInterpreter->interpretExitCode(process->exitCode());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
@@ -77,8 +77,8 @@ public:
|
||||
const QProcessEnvironment &environment);
|
||||
~Command();
|
||||
|
||||
void addJob(const QStringList &arguments);
|
||||
void addJob(const QStringList &arguments, int timeout);
|
||||
void addJob(const QStringList &arguments, Utils::ExitCodeInterpreter *interpreter = 0);
|
||||
void addJob(const QStringList &arguments, int timeout, Utils::ExitCodeInterpreter *interpreter = 0);
|
||||
void execute();
|
||||
void terminate();
|
||||
bool lastExecutionSuccess() const;
|
||||
@@ -103,14 +103,16 @@ public:
|
||||
void setProgressParser(ProgressParser *parser);
|
||||
void setProgressiveOutput(bool progressive);
|
||||
|
||||
Utils::SynchronousProcessResponse runVcs(const QStringList &arguments, int timeoutMS);
|
||||
Utils::SynchronousProcessResponse runVcs(const QStringList &arguments, int timeoutMS,
|
||||
Utils::ExitCodeInterpreter *interpreter = 0);
|
||||
// Make sure to not pass through the event loop at all:
|
||||
bool runFullySynchronous(const QStringList &arguments, int timeoutMS,
|
||||
QByteArray *outputData, QByteArray *errorData);
|
||||
|
||||
private:
|
||||
void run(QFutureInterface<void> &future);
|
||||
Utils::SynchronousProcessResponse runSynchronous(const QStringList &arguments, int timeoutMS);
|
||||
Utils::SynchronousProcessResponse runSynchronous(const QStringList &arguments, int timeoutMS,
|
||||
Utils::ExitCodeInterpreter *interpreter = 0);
|
||||
|
||||
private slots:
|
||||
void bufferedOutput(const QString &text);
|
||||
|
@@ -365,7 +365,8 @@ void VcsBaseClient::diff(const QString &workingDir, const QStringList &files,
|
||||
QStringList args;
|
||||
const QStringList paramArgs = paramWidget != 0 ? paramWidget->arguments() : QStringList();
|
||||
args << vcsCmdString << extraOptions << paramArgs << files;
|
||||
enqueueJob(createCommand(workingDir, editor), args);
|
||||
Command *command = createCommand(workingDir, editor);
|
||||
enqueueJob(command, args, exitCodeInterpreter(DiffCommand, command));
|
||||
}
|
||||
|
||||
void VcsBaseClient::log(const QString &workingDir, const QStringList &files,
|
||||
@@ -461,6 +462,13 @@ QString VcsBaseClient::vcsCommandString(VcsCommand cmd) const
|
||||
return QString();
|
||||
}
|
||||
|
||||
Utils::ExitCodeInterpreter *VcsBaseClient::exitCodeInterpreter(VcsCommand cmd, QObject *parent) const
|
||||
{
|
||||
Q_UNUSED(cmd)
|
||||
Q_UNUSED(parent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VcsBaseClient::import(const QString &repositoryRoot, const QStringList &files,
|
||||
const QStringList &extraOptions)
|
||||
{
|
||||
@@ -605,9 +613,9 @@ Command *VcsBaseClient::createCommand(const QString &workingDirectory,
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void VcsBaseClient::enqueueJob(Command *cmd, const QStringList &args)
|
||||
void VcsBaseClient::enqueueJob(Command *cmd, const QStringList &args, Utils::ExitCodeInterpreter *interpreter)
|
||||
{
|
||||
cmd->addJob(args);
|
||||
cmd->addJob(args, interpreter);
|
||||
cmd->execute();
|
||||
}
|
||||
|
||||
|
@@ -44,6 +44,7 @@ QT_END_NAMESPACE
|
||||
|
||||
namespace Utils {
|
||||
struct SynchronousProcessResponse;
|
||||
class ExitCodeInterpreter;
|
||||
}
|
||||
|
||||
namespace VcsBase {
|
||||
@@ -150,6 +151,7 @@ protected:
|
||||
};
|
||||
virtual QString vcsCommandString(VcsCommand cmd) const;
|
||||
virtual Core::Id vcsEditorKind(VcsCommand cmd) const = 0;
|
||||
virtual Utils::ExitCodeInterpreter *exitCodeInterpreter(VcsCommand cmd, QObject *parent) const;
|
||||
|
||||
virtual QStringList revisionSpec(const QString &revision) const = 0;
|
||||
virtual VcsBaseEditorParameterWidget *createDiffEditor(const QString &workingDir,
|
||||
@@ -183,7 +185,7 @@ protected:
|
||||
Command *createCommand(const QString &workingDirectory,
|
||||
VcsBase::VcsBaseEditorWidget *editor = 0,
|
||||
JobOutputBindMode mode = NoOutputBind);
|
||||
void enqueueJob(Command *cmd, const QStringList &args);
|
||||
void enqueueJob(Command *cmd, const QStringList &args, Utils::ExitCodeInterpreter *interpreter = 0);
|
||||
|
||||
void resetCachedVcsInfo(const QString &workingDir);
|
||||
|
||||
|
Reference in New Issue
Block a user