Commit 696b0a8b authored by jkobus's avatar jkobus Committed by Jarek Kobus

Introduce ExitCodeInterpreter, useful when exit code != 0 is valid

Task-number: QTCREATORBUG-10207

Change-Id: I3b440d40a968f09afc613b686ee50da6465ad88e
Reviewed-by: default avatarTobias Hunger <tobias.hunger@digia.com>
parent 005bef92
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment