diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp index 0cf0caaf1da353540766a92d86ad1ae0397deda9..58b59f4c67a0d2c01e5cb293a039cfcf629adb9b 100644 --- a/src/libs/utils/synchronousprocess.cpp +++ b/src/libs/utils/synchronousprocess.cpp @@ -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: diff --git a/src/libs/utils/synchronousprocess.h b/src/libs/utils/synchronousprocess.h index 5aa1183d7596203af59e7fd0219bb179a1c1f3da..8cb224f00aaf5374af72467848a172f686d5c3fd 100644 --- a/src/libs/utils/synchronousprocess.h +++ b/src/libs/utils/synchronousprocess.h @@ -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. diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp index 18d5415f83f6bfb0905c1a36a77e7634cad91f94..ceb56b5ca65bc1c437cfdc9d73b14feccd71c776 100644 --- a/src/plugins/bazaar/bazaarclient.cpp +++ b/src/plugins/bazaar/bazaarclient.cpp @@ -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; diff --git a/src/plugins/bazaar/bazaarclient.h b/src/plugins/bazaar/bazaarclient.h index 0bc49c230612a435240c50eeda38279f6b72357d..d0b1f4a216f04ec5870e36c2bfceef434829b875 100644 --- a/src/plugins/bazaar/bazaarclient.h +++ b/src/plugins/bazaar/bazaarclient.h @@ -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, diff --git a/src/plugins/vcsbase/command.cpp b/src/plugins/vcsbase/command.cpp index 8aa3d1fdf6df1395ce50c06279b970f8bb1ac660..85148aee10acfdbd4a2b8cadc65db1113256b776 100644 --- a/src/plugins/vcsbase/command.cpp +++ b/src/plugins/vcsbase/command.cpp @@ -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; } diff --git a/src/plugins/vcsbase/command.h b/src/plugins/vcsbase/command.h index dd41f91dcf0688eb89b4b3991b7b969e02373fa9..bf4006187b3b5de3baa2d52946dde392b04aacb1 100644 --- a/src/plugins/vcsbase/command.h +++ b/src/plugins/vcsbase/command.h @@ -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); diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index f23580b72c454830eb0c0f1b31d4bb809fc5974a..1d83c0ef8b125e3afcede8dcff185d00bf7e2687 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -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(); } diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h index 91d90d1e332bd081fcce633b3704edf32b8ffde1..f4c9bf957f35ed45bb37ddceec6df4d58a4aa37d 100644 --- a/src/plugins/vcsbase/vcsbaseclient.h +++ b/src/plugins/vcsbase/vcsbaseclient.h @@ -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);