diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index d61b0d2a55aae30d44f9517046ac01850ea667b8..1e369b18f5be020812992de7e9d9e76819412b47 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -163,7 +163,6 @@ bool BazaarPlugin::initialize(const QStringList &arguments, QString *errorMessag addAutoReleasedObject(m_optionsPage); m_bazaarSettings.readSettings(m_core->settings()); - connect(m_optionsPage, SIGNAL(settingsChanged()), m_client, SLOT(handleSettingsChanged())); connect(m_client, SIGNAL(changed(QVariant)), versionControl(), SLOT(changed(QVariant))); static const char *describeSlot = SLOT(view(QString,QString)); diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 73bb5737c42203d5015706f1950ed9f3e075c0dc..6986af378cc5410ba8b4a201f5d911499b32215f 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -33,11 +33,11 @@ #include "mercurialclient.h" #include "constants.h" +#include <vcsbase/command.h> #include <vcsbase/vcsbaseoutputwindow.h> #include <vcsbase/vcsbaseplugin.h> #include <vcsbase/vcsbaseeditor.h> #include <vcsbase/vcsbaseeditorparameterwidget.h> -#include <vcsbase/vcsjobrunner.h> #include <utils/synchronousprocess.h> #include <utils/fileutils.h> #include <utils/qtcassert.h> @@ -277,12 +277,10 @@ void MercurialClient::incoming(const QString &repositoryRoot, const QString &rep VCSBase::VCSBaseEditorWidget *editor = createVCSEditor(kind, title, repositoryRoot, true, "incoming", id); - - QSharedPointer<VCSBase::VCSJob> job(new VCSBase::VCSJob(repositoryRoot, args, editor)); - // Suppress SSH prompting. + VCSBase::Command *cmd = createCommand(repository, editor); if (!repository.isEmpty() && VCSBase::VCSBasePlugin::isSshPromptConfigured()) - job->setUnixTerminalDisabled(true); - enqueueJob(job); + cmd->setUnixTerminalDisabled(true); + enqueueJob(cmd, args); } void MercurialClient::outgoing(const QString &repositoryRoot) @@ -297,10 +295,9 @@ void MercurialClient::outgoing(const QString &repositoryRoot) VCSBase::VCSBaseEditorWidget *editor = createVCSEditor(kind, title, repositoryRoot, true, "outgoing", repositoryRoot); - QSharedPointer<VCSBase::VCSJob> job(new VCSBase::VCSJob(repositoryRoot, args, editor)); - // Suppress SSH prompting - job->setUnixTerminalDisabled(VCSBase::VCSBasePlugin::isSshPromptConfigured()); - enqueueJob(job); + VCSBase::Command *cmd = createCommand(repositoryRoot, editor); + cmd->setUnixTerminalDisabled(VCSBase::VCSBasePlugin::isSshPromptConfigured()); + enqueueJob(cmd, args); } void MercurialClient::annotate(const QString &workingDir, const QString &file, diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 90e7271cd6cbc295b27a5c649027022e8fbb2eef..8c70e93b68494ee9c065ed4bdfcac456db29c98b 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -166,8 +166,6 @@ bool MercurialPlugin::initialize(const QStringList & /* arguments */, QString * addAutoReleasedObject(optionsPage); mercurialSettings.readSettings(core->settings()); - connect(optionsPage, SIGNAL(settingsChanged()), m_client, SLOT(handleSettingsChanged())); - connect(m_client, SIGNAL(changed(QVariant)), versionControl(), SLOT(changed(QVariant))); static const char *describeSlot = SLOT(view(QString,QString)); diff --git a/src/plugins/vcsbase/command.cpp b/src/plugins/vcsbase/command.cpp new file mode 100644 index 0000000000000000000000000000000000000000..917a49aadd47780dbb71c217b3d8d94922e9d85c --- /dev/null +++ b/src/plugins/vcsbase/command.cpp @@ -0,0 +1,340 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Brian McGillion & Hugues Delorme +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "command.h" +#include "vcsbaseconstants.h" + +#include <coreplugin/icore.h> +#include <coreplugin/progressmanager/progressmanager.h> +#include <extensionsystem/pluginmanager.h> +#include <utils/synchronousprocess.h> + +#include <QtCore/QDebug> +#include <QtCore/QProcess> +#include <QtCore/QFuture> +#include <QtCore/QtConcurrentRun> +#include <QtCore/QFileInfo> +#include <QtCore/QCoreApplication> + +Q_DECLARE_METATYPE(QVariant) + +namespace VCSBase { + +static QString msgTermination(int exitCode, const QString &binaryPath, const QStringList &args) +{ + QString cmd = QFileInfo(binaryPath).baseName(); + if (!args.empty()) { + cmd += QLatin1Char(' '); + cmd += args.front(); + } + return exitCode ? + QCoreApplication::translate("VcsCommand", "\n'%1' failed (exit code %2).\n").arg(cmd).arg(exitCode) : + QCoreApplication::translate("VcsCommand", "\n'%1' completed (exit code %2).\n").arg(cmd).arg(exitCode); +} + +class CommandPrivate +{ +public: + struct Job { + explicit Job(const QStringList &a, int t); + + QStringList arguments; + int timeout; + }; + + CommandPrivate(const QString &binary, + const QString &workingDirectory, + const QProcessEnvironment &environment); + + const QString m_binaryPath; + const QString m_workingDirectory; + const QProcessEnvironment m_environment; + QVariant m_cookie; + bool m_unixTerminalDisabled; + int m_defaultTimeout; + + QList<Job> m_jobs; + Command::TerminationReportMode m_reportTerminationMode; + + bool m_lastExecSuccess; + int m_lastExecExitCode; +}; + +CommandPrivate::CommandPrivate(const QString &binary, + const QString &workingDirectory, + const QProcessEnvironment &environment) : + m_binaryPath(binary), + m_workingDirectory(workingDirectory), + m_environment(environment), + m_unixTerminalDisabled(false), + m_defaultTimeout(10), + m_reportTerminationMode(Command::NoReport), + m_lastExecSuccess(false), + m_lastExecExitCode(-1) +{ +} + +CommandPrivate::Job::Job(const QStringList &a, int t) : + arguments(a), + timeout(t) +{ + // Finished cookie is emitted via queued slot, needs metatype + static const int qvMetaId = qRegisterMetaType<QVariant>(); + Q_UNUSED(qvMetaId) +} + +Command::Command(const QString &binary, + const QString &workingDirectory, + const QProcessEnvironment &environment) : + d(new CommandPrivate(binary, workingDirectory, environment)) +{ +} + +Command::~Command() +{ + delete d; +} + +const QString &Command::binaryPath() const +{ + return d->m_binaryPath; +} + +const QString &Command::workingDirectory() const +{ + return d->m_workingDirectory; +} + +const QProcessEnvironment &Command::processEnvironment() const +{ + return d->m_environment; +} + +Command::TerminationReportMode Command::reportTerminationMode() const +{ + return d->m_reportTerminationMode; +} + +void Command::setTerminationReportMode(TerminationReportMode m) +{ + d->m_reportTerminationMode = m; +} + +int Command::defaultTimeout() const +{ + return d->m_defaultTimeout; +} + +void Command::setDefaultTimeout(int timeout) +{ + d->m_defaultTimeout = timeout; +} + +bool Command::unixTerminalDisabled() const +{ + return d->m_unixTerminalDisabled; +} + +void Command::setUnixTerminalDisabled(bool e) +{ + d->m_unixTerminalDisabled = e; +} + +void Command::addJob(const QStringList &arguments) +{ + addJob(arguments, defaultTimeout()); +} + +void Command::addJob(const QStringList &arguments, int timeout) +{ + d->m_jobs.push_back(CommandPrivate::Job(arguments, timeout)); +} + +void Command::execute() +{ + if (Constants::Internal::debug) + qDebug() << "Command::execute" << d->m_workingDirectory << d->m_jobs.size(); + + d->m_lastExecSuccess = false; + d->m_lastExecExitCode = -1; + + if (d->m_jobs.empty()) + return; + + // For some reason QtConcurrent::run() only works on this + QFuture<void> task = QtConcurrent::run(this, &Command::run); + QString binary = QFileInfo(d->m_binaryPath).baseName(); + if (!binary.isEmpty()) + binary = binary.replace(0, 1, binary[0].toUpper()); // Upper the first letter + const QString taskName = binary + QLatin1Char(' ') + d->m_jobs.front().arguments.at(0); + + Core::ICore::instance()->progressManager()->addTask(task, taskName, binary + QLatin1String(".action")); +} + +bool Command::lastExecutionSuccess() const +{ + return d->m_lastExecSuccess; +} + +int Command::lastExecutionExitCode() const +{ + return d->m_lastExecExitCode; +} + +QString Command::msgTimeout(int seconds) +{ + return tr("Error: VCS timed out after %1s.").arg(seconds); +} + +void Command::run() +{ + if (Constants::Internal::debug) + qDebug() << "Command::run" << workingDirectory() << d->m_jobs.size() + << "terminal_disabled" << unixTerminalDisabled(); + + // Check that the binary path is not empty + if (binaryPath().trimmed().isEmpty()) { + emit errorText(tr("Unable to start process, binary is empty")); + return; + } + + const unsigned processFlags = unixTerminalDisabled() ? + unsigned(Utils::SynchronousProcess::UnixTerminalDisabled) : + unsigned(0); + const QSharedPointer<QProcess> process = Utils::SynchronousProcess::createProcess(processFlags); + if (!workingDirectory().isEmpty()) + process->setWorkingDirectory(workingDirectory()); + + process->setProcessEnvironment(processEnvironment()); + + QByteArray stdOut; + QByteArray stdErr; + QString error; + + const int count = d->m_jobs.size(); + int exitCode = -1; + bool ok = true; + for (int j = 0; j < count; j++) { + if (Constants::Internal::debug) + qDebug() << "Command::run" << j << '/' << count << d->m_jobs.at(j).arguments; + + process->start(binaryPath(), d->m_jobs.at(j).arguments); + if (!process->waitForStarted()) { + ok = false; + error += QString::fromLatin1("Error: \"%1\" could not be started: %2") + .arg(binaryPath(), process->errorString()); + break; + } + + process->closeWriteChannel(); + const int timeOutSeconds = d->m_jobs.at(j).timeout; + if (!Utils::SynchronousProcess::readDataFromProcess(*process, timeOutSeconds * 1000, + &stdOut, &stdErr, false)) { + Utils::SynchronousProcess::stopProcess(*process); + ok = false; + error += msgTimeout(timeOutSeconds); + break; + } + + error += QString::fromLocal8Bit(stdErr); + exitCode = process->exitCode(); + switch (reportTerminationMode()) { + case NoReport: + break; + case ReportStdout: + stdOut += msgTermination(exitCode, binaryPath(), d->m_jobs.at(j).arguments).toUtf8(); + break; + case ReportStderr: + error += msgTermination(exitCode, binaryPath(), d->m_jobs.at(j).arguments); + break; + } + } + + // Special hack: Always produce output for diff + if (ok && stdOut.isEmpty() && d->m_jobs.front().arguments.at(0) == QLatin1String("diff")) { + stdOut += "No difference to HEAD"; + } else { + // @TODO: Remove, see below + if (ok && d->m_jobs.front().arguments.at(0) == QLatin1String("status")) + removeColorCodes(&stdOut); + } + + d->m_lastExecSuccess = ok; + d->m_lastExecExitCode = exitCode; + + if (ok && !stdOut.isEmpty()) + emit outputData(stdOut); + + if (!error.isEmpty()) + emit errorText(error); + + emit finished(ok, exitCode, cookie()); + if (ok) + emit success(cookie()); + // As it is used asynchronously, we need to delete ourselves + this->deleteLater(); +} + +// Clean output from carriage return and ANSI color codes. +// @TODO: Remove once all relevant commands support "--no-color", +//("status" is missing it as of git 1.6.2) + +void Command::removeColorCodes(QByteArray *data) +{ + // Remove ansi color codes that look like "ESC[<stuff>m" + const QByteArray ansiColorEscape("\033["); + int escapePos = 0; + while (true) { + const int nextEscapePos = data->indexOf(ansiColorEscape, escapePos); + if (nextEscapePos == -1) + break; + const int endEscapePos = data->indexOf('m', nextEscapePos + ansiColorEscape.size()); + if (endEscapePos != -1) { + data->remove(nextEscapePos, endEscapePos - nextEscapePos + 1); + escapePos = nextEscapePos; + } else { + escapePos = nextEscapePos + ansiColorEscape.size(); + } + } +} + +const QVariant &Command::cookie() const +{ + return d->m_cookie; +} + +void Command::setCookie(const QVariant &cookie) +{ + d->m_cookie = cookie; +} + +} // namespace VCSBase diff --git a/src/plugins/vcsbase/command.h b/src/plugins/vcsbase/command.h new file mode 100644 index 0000000000000000000000000000000000000000..04d0b053a08a34bfff527bdc885deca8d6b6deb5 --- /dev/null +++ b/src/plugins/vcsbase/command.h @@ -0,0 +1,105 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Brian McGillion & Hugues Delorme +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef VCSBASE_COMMAND_H +#define VCSBASE_COMMAND_H + +#include "vcsbase_global.h" + +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtCore/QProcessEnvironment> + +namespace VCSBase { + +class VCSBASE_EXPORT Command : public QObject +{ + Q_OBJECT + +public: + // Where to report command termination with exit code if desired + enum TerminationReportMode { NoReport, + ReportStdout, // This assumes UTF8 + ReportStderr }; + + Command(const QString &binary, + const QString &workingDirectory, + const QProcessEnvironment &environment); + ~Command(); + + void addJob(const QStringList &arguments); + void addJob(const QStringList &arguments, int timeout); + void execute(); + bool lastExecutionSuccess() const; + int lastExecutionExitCode() const; + + // Clean output from carriage return and ANSI color codes + // Workaround until all relevant commands support "--no-color" + static void removeColorCodes(QByteArray *data); + + const QString &binaryPath() const; + const QString &workingDirectory() const; + const QProcessEnvironment &processEnvironment() const; + + // Report command termination with exit code + TerminationReportMode reportTerminationMode() const; + void setTerminationReportMode(TerminationReportMode m); + + int defaultTimeout() const; + void setDefaultTimeout(int timeout); + + // Disable Terminal on UNIX (see VCS SSH handling) + bool unixTerminalDisabled() const; + void setUnixTerminalDisabled(bool); + + static QString msgTimeout(int seconds); + + const QVariant &cookie() const; + void setCookie(const QVariant &cookie); + +private: + void run(); + +signals: + void outputData(const QByteArray &); + void errorText(const QString &); + void finished(bool ok, int exitCode, const QVariant &cookie); + void success(const QVariant &cookie); + +private: + class CommandPrivate *d; +}; + +} //namespace VCSBase + +#endif // VCSBASE_COMMAND_H diff --git a/src/plugins/vcsbase/vcsbase.pro b/src/plugins/vcsbase/vcsbase.pro index 6a4cc9e37ca0da0f08a24215274b273d52b81f84..f9cd7b796313bb63df70803c68417fde9a282d8f 100644 --- a/src/plugins/vcsbase/vcsbase.pro +++ b/src/plugins/vcsbase/vcsbase.pro @@ -29,7 +29,7 @@ HEADERS += vcsbase_global.h \ vcsbaseoutputwindow.h \ cleandialog.h \ vcsbaseoptionspage.h \ - vcsjobrunner.h \ + command.h \ vcsbaseclient.h \ vcsbaseclientsettings.h \ vcsbaseeditorparameterwidget.h @@ -58,7 +58,7 @@ SOURCES += vcsplugin.cpp \ vcsbaseoutputwindow.cpp \ cleandialog.cpp \ vcsbaseoptionspage.cpp \ - vcsjobrunner.cpp \ + command.cpp \ vcsbaseclient.cpp \ vcsbaseclientsettings.cpp \ vcsbaseeditorparameterwidget.cpp diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index d936d3ceed1284bcbacde6e90639911154af33a9..e522ce37b9feb86e108b646a53f8a88c11a3dd3e 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -30,8 +30,9 @@ ** **************************************************************************/ +#include "command.h" #include "vcsbaseclient.h" -#include "vcsjobrunner.h" +#include "vcsbaseconstants.h" #include "vcsbaseclientsettings.h" #include "vcsbaseeditorparameterwidget.h" @@ -49,6 +50,7 @@ #include <QtCore/QSharedPointer> #include <QtCore/QDir> #include <QtCore/QProcess> +#include <QtCore/QSignalMapper> #include <QtCore/QTextCodec> #include <QtCore/QtDebug> #include <QtCore/QFileInfo> @@ -75,6 +77,15 @@ inline Core::IEditor *locateEditor(const Core::ICore *core, const char *property return 0; } +namespace { + +VCSBase::VCSBaseOutputWindow *vcsOutputWindow() +{ + return VCSBase::VCSBaseOutputWindow::instance(); +} + +} + namespace VCSBase { class VCSBaseClientPrivate @@ -86,18 +97,22 @@ public: void annotateRevision(QString source, QString change, int lineNumber); void saveSettings(); - void updateJobRunnerSettings(); + void bindCommandToEditor(Command *cmd, VCSBaseEditorWidget *editor); + void commandFinishedGotoLine(QObject *editorObject); - VCSJobRunner *m_jobManager; Core::ICore *m_core; VCSBaseClientSettings *m_clientSettings; + QSignalMapper *m_cmdFinishedMapper; private: VCSBaseClient *m_client; }; VCSBaseClientPrivate::VCSBaseClientPrivate(VCSBaseClient *client, VCSBaseClientSettings *settings) : - m_jobManager(0), m_core(Core::ICore::instance()), m_clientSettings(settings), m_client(client) + m_core(Core::ICore::instance()), + m_clientSettings(settings), + m_cmdFinishedMapper(new QSignalMapper(client)), + m_client(client) { } @@ -132,11 +147,23 @@ void VCSBaseClientPrivate::saveSettings() m_clientSettings->writeSettings(m_core->settings()); } -void VCSBaseClientPrivate::updateJobRunnerSettings() +void VCSBaseClientPrivate::bindCommandToEditor(Command *cmd, VCSBaseEditorWidget *editor) +{ + QObject::connect(cmd, SIGNAL(finished(bool,int,QVariant)), m_cmdFinishedMapper, SLOT(map())); + m_cmdFinishedMapper->setMapping(cmd, editor); +} + +void VCSBaseClientPrivate::commandFinishedGotoLine(QObject *editorObject) { - if (m_jobManager && m_clientSettings) { - m_jobManager->setBinary(m_clientSettings->stringValue(VCSBaseClientSettings::binaryPathKey)); - m_jobManager->setTimeoutMs(m_clientSettings->intValue(VCSBaseClientSettings::timeoutKey) * 1000); + VCSBase::VCSBaseEditorWidget *editor = qobject_cast<VCSBase::VCSBaseEditorWidget *>(editorObject); + Command *cmd = qobject_cast<Command *>(m_cmdFinishedMapper->mapping(editor)); + if (editor && cmd) { + if (cmd->lastExecutionSuccess() && cmd->cookie().type() == QVariant::Int) { + const int line = cmd->cookie().toInt(); + if (line >= 0) + editor->gotoLine(line); + } + m_cmdFinishedMapper->removeMappings(cmd); } } @@ -154,12 +181,11 @@ VCSBaseClient::VCSBaseClient(VCSBaseClientSettings *settings) : { qRegisterMetaType<QVariant>(); connect(d->m_core, SIGNAL(saveSettingsRequested()), this, SLOT(saveSettings())); + connect(d->m_cmdFinishedMapper, SIGNAL(mapped(QObject*)), this, SLOT(commandFinishedGotoLine(QObject*))); } VCSBaseClient::~VCSBaseClient() { - delete d->m_jobManager; - d->m_jobManager = 0; delete d; } @@ -173,7 +199,7 @@ bool VCSBaseClient::synchronousCreateRepository(const QString &workingDirectory, return false; QString output = QString::fromLocal8Bit(outputData); output.remove(QLatin1Char('\r')); - VCSBase::VCSBaseOutputWindow::instance()->append(output); + ::vcsOutputWindow()->append(output); resetCachedVcsInfo(workingDirectory); @@ -262,17 +288,17 @@ bool VCSBaseClient::vcsFullySynchronousExec(const QString &workingDir, QProcess vcsProcess; if (!workingDir.isEmpty()) vcsProcess.setWorkingDirectory(workingDir); - VCSJobRunner::setProcessEnvironment(&vcsProcess); + vcsProcess.setProcessEnvironment(processEnvironment()); const QString binary = settings()->stringValue(VCSBaseClientSettings::binaryPathKey); - VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance(); - outputWindow->appendCommand(workingDir, binary, args); + ::vcsOutputWindow()->appendCommand(workingDir, binary, args); vcsProcess.start(binary, args); if (!vcsProcess.waitForStarted()) { - outputWindow->appendError(VCSJobRunner::msgStartFailed(binary, vcsProcess.errorString())); + ::vcsOutputWindow()->appendError(tr("Unable to start process '%1': %2") + .arg(QDir::toNativeSeparators(binary), vcsProcess.errorString())); return false; } @@ -283,20 +309,21 @@ bool VCSBaseClient::vcsFullySynchronousExec(const QString &workingDir, if (!Utils::SynchronousProcess::readDataFromProcess(vcsProcess, timeoutSec * 1000, output, &stdErr, true)) { Utils::SynchronousProcess::stopProcess(vcsProcess); - outputWindow->appendError(VCSJobRunner::msgTimeout(binary, timeoutSec)); + ::vcsOutputWindow()->appendError(tr("Timed out after %1s waiting for the process %2 to finish.") + .arg(timeoutSec).arg(binary)); return false; } if (!stdErr.isEmpty()) - outputWindow->append(QString::fromLocal8Bit(stdErr)); + ::vcsOutputWindow()->append(QString::fromLocal8Bit(stdErr)); return vcsProcess.exitStatus() == QProcess::NormalExit && vcsProcess.exitCode() == 0; } Utils::SynchronousProcessResponse VCSBaseClient::vcsSynchronousExec( - const QString &workingDirectory, - const QStringList &args, - unsigned flags, - QTextCodec *outputCodec) + const QString &workingDirectory, + const QStringList &args, + unsigned flags, + QTextCodec *outputCodec) { const QString binary = settings()->stringValue(VCSBaseClientSettings::binaryPathKey); const int timeoutSec = settings()->intValue(VCSBaseClientSettings::timeoutKey); @@ -321,8 +348,9 @@ void VCSBaseClient::annotate(const QString &workingDir, const QString &file, VCSBase::VCSBaseEditorWidget *editor = createVCSEditor(kind, title, source, true, vcsCmdString.toLatin1().constData(), id); - QSharedPointer<VCSJob> job(new VCSJob(workingDir, args, editor)); - enqueueJob(job); + Command *cmd = createCommand(workingDir, editor); + cmd->setCookie(lineNumber); + enqueueJob(cmd, args); } void VCSBaseClient::diff(const QString &workingDir, const QStringList &files, @@ -348,8 +376,7 @@ void VCSBaseClient::diff(const QString &workingDir, const QStringList &files, QStringList args; const QStringList paramArgs = paramWidget != 0 ? paramWidget->arguments() : QStringList(); args << vcsCmdString << extraOptions << paramArgs << files; - QSharedPointer<VCSJob> job(new VCSJob(workingDir, args, editor)); - enqueueJob(job); + enqueueJob(createCommand(workingDir, editor), args); } void VCSBaseClient::log(const QString &workingDir, const QStringList &files, @@ -373,8 +400,7 @@ void VCSBaseClient::log(const QString &workingDir, const QStringList &files, QStringList args; const QStringList paramArgs = paramWidget != 0 ? paramWidget->arguments() : QStringList(); args << vcsCmdString << extraOptions << paramArgs << files; - QSharedPointer<VCSJob> job(new VCSJob(workingDir, args, editor)); - enqueueJob(job); + enqueueJob(createCommand(workingDir, editor), args); } void VCSBaseClient::revertFile(const QString &workingDir, @@ -385,11 +411,10 @@ void VCSBaseClient::revertFile(const QString &workingDir, QStringList args(vcsCommandString(RevertCommand)); args << revisionSpec(revision) << extraOptions << file; // Indicate repository change or file list - QSharedPointer<VCSJob> job(new VCSJob(workingDir, args)); - job->setCookie(QStringList(workingDir + QLatin1Char('/') + file)); - connect(job.data(), SIGNAL(succeeded(QVariant)), - this, SIGNAL(changed(QVariant)), Qt::QueuedConnection); - enqueueJob(job); + Command *cmd = createCommand(workingDir); + cmd->setCookie(QStringList(workingDir + QLatin1Char('/') + file)); + connect(cmd, SIGNAL(success(QVariant)), this, SIGNAL(changed(QVariant)), Qt::QueuedConnection); + enqueueJob(cmd, args); } void VCSBaseClient::revertAll(const QString &workingDir, const QString &revision, @@ -398,10 +423,10 @@ void VCSBaseClient::revertAll(const QString &workingDir, const QString &revision QStringList args(vcsCommandString(RevertCommand)); args << revisionSpec(revision) << extraOptions; // Indicate repository change or file list - QSharedPointer<VCSJob> job(new VCSJob(workingDir, args)); - connect(job.data(), SIGNAL(succeeded(QVariant)), - this, SIGNAL(changed(QVariant)), Qt::QueuedConnection); - enqueueJob(job); + Command *cmd = createCommand(workingDir); + cmd->setCookie(QStringList(workingDir)); + connect(cmd, SIGNAL(success(QVariant)), this, SIGNAL(changed(QVariant)), Qt::QueuedConnection); + enqueueJob(createCommand(workingDir), args); } void VCSBaseClient::status(const QString &workingDir, const QString &file, @@ -409,21 +434,20 @@ void VCSBaseClient::status(const QString &workingDir, const QString &file, { QStringList args(vcsCommandString(StatusCommand)); args << extraOptions << file; - VCSBase::VCSBaseOutputWindow *outwin = VCSBase::VCSBaseOutputWindow::instance(); - outwin->setRepository(workingDir); - QSharedPointer<VCSJob> job(new VCSJob(workingDir, args)); - connect(job.data(), SIGNAL(succeeded(QVariant)), - outwin, SLOT(clearRepository()), Qt::QueuedConnection); - enqueueJob(job); + ::vcsOutputWindow()->setRepository(workingDir); + Command *cmd = createCommand(workingDir, 0, VcsWindowOutputBind); + connect(cmd, SIGNAL(finished(bool,int,QVariant)), ::vcsOutputWindow(), SLOT(clearRepository()), + Qt::QueuedConnection); + enqueueJob(cmd, args); } void VCSBaseClient::emitParsedStatus(const QString &repository, const QStringList &extraOptions) { QStringList args(vcsCommandString(StatusCommand)); args << extraOptions; - QSharedPointer<VCSJob> job(new VCSJob(repository, args, VCSJob::RawDataEmitMode)); - connect(job.data(), SIGNAL(rawData(QByteArray)), this, SLOT(statusParser(QByteArray))); - enqueueJob(job); + Command *cmd = createCommand(repository); + connect(cmd, SIGNAL(outputData(QByteArray)), this, SLOT(statusParser(QByteArray))); + enqueueJob(cmd, args); } QString VCSBaseClient::vcsCommandString(VCSCommand cmd) const @@ -453,8 +477,7 @@ void VCSBaseClient::import(const QString &repositoryRoot, const QStringList &fil { QStringList args(vcsCommandString(ImportCommand)); args << extraOptions << files; - QSharedPointer<VCSJob> job(new VCSJob(repositoryRoot, args)); - enqueueJob(job); + enqueueJob(createCommand(repositoryRoot), args); } void VCSBaseClient::view(const QString &source, const QString &id, @@ -470,8 +493,7 @@ void VCSBaseClient::view(const QString &source, const QString &id, const QFileInfo fi(source); const QString workingDirPath = fi.isFile() ? fi.absolutePath() : source; - QSharedPointer<VCSJob> job(new VCSJob(workingDirPath, args, editor)); - enqueueJob(job); + enqueueJob(createCommand(workingDirPath, editor), args); } void VCSBaseClient::update(const QString &repositoryRoot, const QString &revision, @@ -479,12 +501,11 @@ void VCSBaseClient::update(const QString &repositoryRoot, const QString &revisio { QStringList args(vcsCommandString(UpdateCommand)); args << revisionSpec(revision) << extraOptions; - QSharedPointer<VCSJob> job(new VCSJob(repositoryRoot, args)); - job->setCookie(repositoryRoot); - // Suppress SSH prompting - job->setUnixTerminalDisabled(VCSBase::VCSBasePlugin::isSshPromptConfigured()); - connect(job.data(), SIGNAL(succeeded(QVariant)), this, SIGNAL(changed(QVariant)), Qt::QueuedConnection); - enqueueJob(job); + Command *cmd = createCommand(repositoryRoot); + cmd->setCookie(repositoryRoot); + cmd->setUnixTerminalDisabled(VCSBase::VCSBasePlugin::isSshPromptConfigured()); + connect(cmd, SIGNAL(success(QVariant)), this, SIGNAL(changed(QVariant)), Qt::QueuedConnection); + enqueueJob(cmd, args); } void VCSBaseClient::commit(const QString &repositoryRoot, @@ -503,8 +524,7 @@ void VCSBaseClient::commit(const QString &repositoryRoot, Q_UNUSED(commitMessageFile); QStringList args(vcsCommandString(CommitCommand)); args << extraOptions << files; - QSharedPointer<VCSJob> job(new VCSJob(repositoryRoot, args)); - enqueueJob(job); + enqueueJob(createCommand(repositoryRoot), args); } VCSBaseClientSettings *VCSBaseClient::settings() const @@ -512,14 +532,6 @@ VCSBaseClientSettings *VCSBaseClient::settings() const return d->m_clientSettings; } -void VCSBaseClient::handleSettingsChanged() -{ - if (d->m_jobManager) { - d->updateJobRunnerSettings(); - d->m_jobManager->restart(); - } -} - VCSBaseEditorParameterWidget *VCSBaseClient::createDiffEditor(const QString &workingDir, const QStringList &files, const QStringList &extraOptions) @@ -578,20 +590,58 @@ VCSBase::VCSBaseEditorWidget *VCSBaseClient::createVCSEditor(const QString &kind return baseEditor; } -void VCSBaseClient::resetCachedVcsInfo(const QString &workingDir) +QProcessEnvironment VCSBaseClient::processEnvironment() const { - Core::VcsManager *vcsManager = d->m_core->vcsManager(); - vcsManager->resetVersionControlForDirectory(workingDir); + QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); + VCSBase::VCSBasePlugin::setProcessEnvironment(&environment, false); + return environment; } -void VCSBaseClient::enqueueJob(const QSharedPointer<VCSJob> &job) +Command *VCSBaseClient::createCommand(const QString &workingDirectory, + VCSBase::VCSBaseEditorWidget *editor, + JobOutputBindMode mode) { - if (!d->m_jobManager) { - d->m_jobManager = new VCSJobRunner(); - d->updateJobRunnerSettings(); - d->m_jobManager->start(); + if (Constants::Internal::debug) + qDebug() << Q_FUNC_INFO << workingDirectory << editor; + + Command *cmd = new Command(d->m_clientSettings->stringValue(VCSBaseClientSettings::binaryPathKey), + workingDirectory, processEnvironment()); + cmd->setDefaultTimeout(d->m_clientSettings->intValue(VCSBaseClientSettings::timeoutKey)); + if (editor) + d->bindCommandToEditor(cmd, editor); + if (mode == VcsWindowOutputBind) { + if (editor) { // assume that the commands output is the important thing + connect(cmd, SIGNAL(outputData(QByteArray)), + ::vcsOutputWindow(), SLOT(appendDataSilently(QByteArray))); + } + else { + connect(cmd, SIGNAL(outputData(QByteArray)), + ::vcsOutputWindow(), SLOT(appendData(QByteArray))); + } + } + else if (editor) { + connect(cmd, SIGNAL(outputData(QByteArray)), + editor, SLOT(setPlainTextData(QByteArray))); } - d->m_jobManager->enqueueJob(job); + + if (::vcsOutputWindow()) + connect(cmd, SIGNAL(errorText(QString)), + ::vcsOutputWindow(), SLOT(appendError(QString))); + return cmd; +} + +void VCSBaseClient::enqueueJob(Command *cmd, const QStringList &args) +{ + const QString binary = QFileInfo(d->m_clientSettings->stringValue(VCSBaseClientSettings::binaryPathKey)).baseName(); + ::vcsOutputWindow()->appendCommand(cmd->workingDirectory(), binary, args); + cmd->addJob(args); + cmd->execute(); +} + +void VCSBaseClient::resetCachedVcsInfo(const QString &workingDir) +{ + Core::VcsManager *vcsManager = d->m_core->vcsManager(); + vcsManager->resetVersionControlForDirectory(workingDir); } } // namespace VCSBase diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h index c6cffb79643cdbafa9b927b3edaa54479c948397..eb0e82a52a9eb686d0b923f8ec13e4512de89c69 100644 --- a/src/plugins/vcsbase/vcsbaseclient.h +++ b/src/plugins/vcsbase/vcsbaseclient.h @@ -38,6 +38,8 @@ #include <QtCore/QObject> #include <QtCore/QStringList> #include <QtCore/QSharedPointer> +#include <QtCore/QVariant> +#include <QtCore/QProcessEnvironment> QT_BEGIN_NAMESPACE class QFileInfo; @@ -49,6 +51,7 @@ struct SynchronousProcessResponse; namespace VCSBase { +class Command; class VCSBaseEditorWidget; class VCSBaseClientSettings; class VCSJob; @@ -126,7 +129,6 @@ signals: public slots: virtual void view(const QString &source, const QString &id, const QStringList &extraOptions = QStringList()); - void handleSettingsChanged(); protected: enum VCSCommand @@ -160,7 +162,6 @@ protected: virtual StatusItem parseStatusLine(const QString &line) const = 0; QString vcsEditorTitle(const QString &vcsCmd, const QString &sourceId) const; - void enqueueJob(const QSharedPointer<VCSJob> &); // Fully synchronous VCS execution (QProcess-based) bool vcsFullySynchronousExec(const QString &workingDir, const QStringList &args, @@ -176,6 +177,17 @@ protected: const char *registerDynamicProperty, const QString &dynamicPropertyValue) const; + virtual QProcessEnvironment processEnvironment() const; + + enum JobOutputBindMode { + NoOutputBind, + VcsWindowOutputBind + }; + Command *createCommand(const QString &workingDirectory, + VCSBase::VCSBaseEditorWidget *editor = 0, + JobOutputBindMode mode = NoOutputBind); + void enqueueJob(Command *cmd, const QStringList &args); + void resetCachedVcsInfo(const QString &workingDir); private: @@ -185,6 +197,7 @@ private: Q_PRIVATE_SLOT(d, void statusParser(QByteArray)) Q_PRIVATE_SLOT(d, void annotateRevision(QString, QString, int)) Q_PRIVATE_SLOT(d, void saveSettings()) + Q_PRIVATE_SLOT(d, void commandFinishedGotoLine(QObject *)) }; } //namespace VCSBase diff --git a/src/plugins/vcsbase/vcsjobrunner.cpp b/src/plugins/vcsbase/vcsjobrunner.cpp deleted file mode 100644 index c09dd8fceb8bf52df5e2b4528ad9772f5ffd2c27..0000000000000000000000000000000000000000 --- a/src/plugins/vcsbase/vcsjobrunner.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Brian McGillion & Hugues Delorme -** -** Contact: Nokia Corporation (info@qt.nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#include "vcsjobrunner.h" -#include "vcsbaseconstants.h" -#include "vcsbaseoutputwindow.h" -#include "vcsbaseeditor.h" -#include "vcsbaseplugin.h" - -#include <utils/synchronousprocess.h> - -#include <QtCore/QMutexLocker> -#include <QtCore/QProcess> -#include <QtCore/QProcessEnvironment> -#include <QtCore/QString> -#include <QtCore/QDebug> -#include <QtCore/QDir> -#include <QtCore/QQueue> -#include <QtCore/QMutex> -#include <QtCore/QWaitCondition> -#include <QtCore/QSharedPointer> - -namespace { - -//Helper class to automatically disconnect a signal from all its receivers. -//The disconnect occurs on destruction of the helper object. -class DisconnectSignalHelper -{ -public: - DisconnectSignalHelper(QObject *sender, const char *signal) : - m_sender(sender), m_signal(signal) - { - } - - ~DisconnectSignalHelper() - { - QObject::disconnect(m_sender, m_signal, 0, 0); - } - -private: - QObject *m_sender; - const char *m_signal; -}; - -} // Anonymous namespace - -/*! - \class VCSBase::VCSJob - - \brief Version control system background command execution job. - - Takes arguments, etc. as parameters and emits signals on output/termination. - - \sa VCSBase::VCSJobRunner, VCSBase::VCSBaseClient -*/ - -namespace VCSBase { - -VCSJob::VCSJob(const QString &workingDir, - const QStringList &args, - DataEmitMode emitMode) : - m_workingDir(workingDir), - m_arguments(args), - m_emitRaw(emitMode == RawDataEmitMode), - m_cookie(), - m_editor(0), - m_unixTerminalDisabled(false) -{ -} - -VCSJob::VCSJob(const QString &workingDir, - const QStringList &args, - VCSBase::VCSBaseEditorWidget *editor) : - m_workingDir(workingDir), - m_arguments(args), - m_emitRaw(false), - m_cookie(), - m_editor(editor), - m_unixTerminalDisabled(false) -{ -} - - -VCSJob::DataEmitMode VCSJob::dataEmitMode() const -{ - if (m_emitRaw) - return RawDataEmitMode; - else if (displayEditor() != 0) - return EditorDataEmitMode; - else - return NoDataEmitMode; -} - -VCSBase::VCSBaseEditorWidget *VCSJob::displayEditor() const -{ - return m_editor; -} - -QStringList VCSJob::arguments() const -{ - return m_arguments; -} - -QString VCSJob::workingDirectory() const -{ - return m_workingDir; -} - -const QVariant &VCSJob::cookie() const -{ - return m_cookie; -} - -bool VCSJob::unixTerminalDisabled() const -{ - return m_unixTerminalDisabled; -} - -void VCSJob::setDisplayEditor(VCSBase::VCSBaseEditorWidget *editor) -{ - m_editor = editor; - m_emitRaw = false; -} - -void VCSJob::setCookie(const QVariant &cookie) -{ - m_cookie = cookie; -} - -void VCSJob::setUnixTerminalDisabled(bool v) -{ - m_unixTerminalDisabled = v; -} - -/*! - \class VCSBase::VCSJobRunner - - \brief Job queue for version control system background command execution. - - A job queue running in a separate thread, executing commands - and emitting status/log signals. - - \sa VCSBase::VCSJob, VCSBase::VCSBaseClient -*/ - -class VCSJobRunnerPrivate -{ -public: - VCSJobRunnerPrivate(); - - QQueue<QSharedPointer<VCSJob> > m_jobs; - QMutex m_mutex; - QWaitCondition m_waiter; - bool m_keepRunning; - QString m_binary; - int m_timeoutMs; -}; - -VCSJobRunnerPrivate::VCSJobRunnerPrivate() : - m_keepRunning(true), m_timeoutMs(30000) -{ -} - -VCSJobRunner::VCSJobRunner() : d(new VCSJobRunnerPrivate) -{ - VCSBase::VCSBaseOutputWindow *ow = VCSBase::VCSBaseOutputWindow::instance(); - connect(this, SIGNAL(error(QString)), - ow, SLOT(appendError(QString)), Qt::QueuedConnection); - connect(this, SIGNAL(commandStarted(QString)), - ow, SLOT(appendCommand(QString)), Qt::QueuedConnection); -} - -VCSJobRunner::~VCSJobRunner() -{ - stop(); - delete d; -} - -void VCSJobRunner::stop() -{ - { - QMutexLocker mutexLocker(&d->m_mutex); Q_UNUSED(mutexLocker); - d->m_keepRunning = false; - //Create a dummy task to break the cycle - QSharedPointer<VCSJob> job(0); - d->m_jobs.enqueue(job); - d->m_waiter.wakeAll(); - } - - wait(); -} - -void VCSJobRunner::restart() -{ - stop(); - d->m_mutex.lock(); - d->m_keepRunning = true; - d->m_mutex.unlock(); - start(); -} - -void VCSJobRunner::enqueueJob(const QSharedPointer<VCSJob> &job) -{ - QMutexLocker mutexLocker(&d->m_mutex); Q_UNUSED(mutexLocker); - d->m_jobs.enqueue(job); - d->m_waiter.wakeAll(); -} - -void VCSJobRunner::run() -{ - forever { - d->m_mutex.lock(); - while (d->m_jobs.count() == 0) - d->m_waiter.wait(&d->m_mutex); - - if (!d->m_keepRunning) { - d->m_jobs.clear(); - d->m_mutex.unlock(); - return; - } - - QSharedPointer<VCSJob> job = d->m_jobs.dequeue(); - d->m_mutex.unlock(); - - task(job); - } -} - -QString VCSJobRunner::msgStartFailed(const QString &binary, const QString &why) -{ - return tr("Unable to start process '%1': %2"). - arg(QDir::toNativeSeparators(binary), why); -} - -QString VCSJobRunner::msgTimeout(const QString &binary, int timeoutSeconds) -{ - return tr("Timed out after %1s waiting for the process %2 to finish.").arg(timeoutSeconds).arg(binary); -} - -// Set environment for a VCS process to run in locale "C". Note that there appears -// to be a bug in some VCSs (like hg) that causes special characters to be garbled -// when running in a different language, which seems to be independent from the encoding. -void VCSJobRunner::setProcessEnvironment(QProcess *p) -{ - if (p == 0) - return; - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - VCSBase::VCSBasePlugin::setProcessEnvironment(&env, false); - p->setProcessEnvironment(env); -} - -const QString &VCSJobRunner::binary() const -{ - return d->m_binary; -} - -void VCSJobRunner::setBinary(const QString &bin) -{ - d->m_binary = bin; -} - -int VCSJobRunner::timeoutMs() const -{ - return d->m_timeoutMs; -} - -void VCSJobRunner::setTimeoutMs(int msec) -{ - d->m_timeoutMs = msec; -} - -void VCSJobRunner::task(const QSharedPointer<VCSJob> &job) -{ - VCSJob *taskData = job.data(); - - VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance(); - - switch (taskData->dataEmitMode()) { - case VCSJob::NoDataEmitMode : - //Just output the data to the "Version control" output window - connect(this, SIGNAL(output(QByteArray)), outputWindow, SLOT(appendData(QByteArray)), - Qt::QueuedConnection); - break; - case VCSJob::RawDataEmitMode : - //Call the job's signal so the Initator of the job can process the data - //Because the QSharedPointer that holds the VCSJob will go out of scope and hence be deleted - //we have to block and wait until the signal is delivered - connect(this, SIGNAL(output(QByteArray)), taskData, SIGNAL(rawData(QByteArray)), - Qt::BlockingQueuedConnection); - break; - case VCSJob::EditorDataEmitMode : - //An editor has been created to display the data so send it there - connect(this, SIGNAL(output(QByteArray)), - taskData->displayEditor(), SLOT(setPlainTextData(QByteArray)), - Qt::QueuedConnection); - break; - } - - //the signal connection is to last only for the duration of a job/task. next time a new - //output signal connection must be made - DisconnectSignalHelper autoDisconnectOutputSig(this, SIGNAL(output(QByteArray))); - Q_UNUSED(autoDisconnectOutputSig); - - // Check that the binary path is not empty - if (binary().trimmed().isEmpty()) { - emit error(tr("Unable to start process, binary is empty")); - return; - } - - const QStringList args = taskData->arguments(); - emit commandStarted(VCSBase::VCSBaseOutputWindow::msgExecutionLogEntry(taskData->workingDirectory(), binary(), args)); - //infom the user of what we are going to try and perform - - if (Constants::Internal::debug) - qDebug() << Q_FUNC_INFO << "Repository root is " - << taskData->workingDirectory() << " terminal_disabled" - << taskData->unixTerminalDisabled(); - - const unsigned processFlags = taskData->unixTerminalDisabled() ? - unsigned(Utils::SynchronousProcess::UnixTerminalDisabled) : - unsigned(0); - - QSharedPointer<QProcess> vcsProcess = Utils::SynchronousProcess::createProcess(processFlags); - vcsProcess->setWorkingDirectory(taskData->workingDirectory()); - VCSJobRunner::setProcessEnvironment(vcsProcess.data()); - - vcsProcess->start(binary(), args); - - if (!vcsProcess->waitForStarted()) { - emit error(msgStartFailed(binary(), vcsProcess->errorString())); - return; - } - - vcsProcess->closeWriteChannel(); - - QByteArray stdOutput; - QByteArray stdErr; - - if (!Utils::SynchronousProcess::readDataFromProcess(*vcsProcess, timeoutMs(), &stdOutput, &stdErr, false)) { - Utils::SynchronousProcess::stopProcess(*vcsProcess); - emit error(msgTimeout(binary(), timeoutMs() / 1000)); - return; - } - - if (vcsProcess->exitStatus() == QProcess::NormalExit) { - /* - * sometimes success means output is actually on error channel (stderr) - * e.g. "hg revert" outputs "no changes needed to 'file'" on stderr if file has not changed - * from revision specified - */ - if (stdOutput.isEmpty()) - stdOutput = stdErr; - emit output(stdOutput); // This will clear the diff "Working..." text. - if (vcsProcess->exitCode() == 0) - emit taskData->succeeded(taskData->cookie()); - else - emit error(QString::fromLocal8Bit(stdErr)); - } - - vcsProcess->close(); -} - -} // namespace VCSBase diff --git a/src/plugins/vcsbase/vcsjobrunner.h b/src/plugins/vcsbase/vcsjobrunner.h deleted file mode 100644 index ece94fa7dd055747cbced7fa650061b6f6e91477..0000000000000000000000000000000000000000 --- a/src/plugins/vcsbase/vcsjobrunner.h +++ /dev/null @@ -1,134 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Brian McGillion & Hugues Delorme -** -** Contact: Nokia Corporation (info@qt.nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#ifndef VCSJOBRUNNER_H -#define VCSJOBRUNNER_H - -#include "vcsbase_global.h" - -#include <QtCore/QThread> -#include <QtCore/QStringList> -#include <QtCore/QString> -#include <QtCore/QPointer> -#include <QtCore/QSharedPointer> -#include <QtCore/QVariant> - -QT_BEGIN_NAMESPACE -class QProcess; -QT_END_NAMESPACE - -namespace VCSBase { -class VCSBaseEditorWidget; -class VCSJobRunnerPrivate; - -class VCSBASE_EXPORT VCSJob : public QObject -{ - Q_OBJECT - -public: - enum DataEmitMode { - NoDataEmitMode, - RawDataEmitMode, - EditorDataEmitMode - }; - - VCSJob(const QString &workingDir, const QStringList &args, - DataEmitMode emitMode = NoDataEmitMode); - VCSJob(const QString &workingDir, const QStringList &args, - VCSBase::VCSBaseEditorWidget *editor); - - DataEmitMode dataEmitMode() const; - VCSBase::VCSBaseEditorWidget *displayEditor() const; - QStringList arguments() const; - QString workingDirectory() const; - const QVariant &cookie() const; - bool unixTerminalDisabled() const; - - void setDisplayEditor(VCSBase::VCSBaseEditorWidget *editor); - void setCookie(const QVariant &cookie); - // Disable terminal to suppress SSH prompting - void setUnixTerminalDisabled(bool v); - -signals: - void succeeded(const QVariant &cookie); // Use a queued connection - void rawData(const QByteArray &data); - -private: - friend class VCSJobRunner; - const QString m_workingDir; - const QStringList m_arguments; - bool m_emitRaw; - QVariant m_cookie; - QPointer<VCSBase::VCSBaseEditorWidget> m_editor; // User might close it - bool m_unixTerminalDisabled; -}; - -class VCSBASE_EXPORT VCSJobRunner : public QThread -{ - Q_OBJECT - -public: - VCSJobRunner(); - ~VCSJobRunner(); - void enqueueJob(const QSharedPointer<VCSJob> &job); - void restart(); - - static QString msgStartFailed(const QString &binary, const QString &why); - static QString msgTimeout(const QString &binary, int timeoutSeconds); - - // Set environment for a VCS process to run in locale "C" - static void setProcessEnvironment(QProcess *p); - - const QString &binary() const; - void setBinary(const QString &bin); - - int timeoutMs() const; - void setTimeoutMs(int msec); - -protected: - void run(); - -signals: - void commandStarted(const QString ¬ice); - void error(const QString &error); - void output(const QByteArray &output); - -private: - void task(const QSharedPointer<VCSJob> &job); - void stop(); - - VCSJobRunnerPrivate *d; -}; - -} //namespace VCSBase - -#endif // VCSJOBRUNNER_H