diff options
author | Orgad Shaneh <orgad.shaneh@audiocodes.com> | 2013-08-16 17:02:30 +0300 |
---|---|---|
committer | Orgad Shaneh <orgads@gmail.com> | 2013-08-20 12:53:33 +0200 |
commit | cc2610aa71ae012261b5fecbf615d41250d088ac (patch) | |
tree | af25da496ce0ef7b11f2ebf5a00e95f52a1547d8 | |
parent | 1dd44cfba19be1063e2b8ba73a10df4ba36625ea (diff) | |
download | qt-creator-cc2610aa71ae012261b5fecbf615d41250d088ac.tar.gz |
VCS: Enable calling runVcs from non-GUI threads
* Introduce a proxy class for thread synchronization
* Use signals for appending text to output window
Change-Id: Iecbb010e6b6e9dab27d9862a43dafa450f2bb1f8
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
-rw-r--r-- | src/libs/utils/synchronousprocess.cpp | 14 | ||||
-rw-r--r-- | src/plugins/clearcase/clearcaseplugin.cpp | 4 | ||||
-rw-r--r-- | src/plugins/cvs/cvsplugin.cpp | 5 | ||||
-rw-r--r-- | src/plugins/git/gitclient.cpp | 2 | ||||
-rw-r--r-- | src/plugins/mercurial/mercurialclient.cpp | 3 | ||||
-rw-r--r-- | src/plugins/subversion/subversionplugin.cpp | 7 | ||||
-rw-r--r-- | src/plugins/vcsbase/vcsbaseclient.cpp | 4 | ||||
-rw-r--r-- | src/plugins/vcsbase/vcsbaseplugin.cpp | 80 | ||||
-rw-r--r-- | src/plugins/vcsbase/vcsbaseplugin.h | 18 |
9 files changed, 103 insertions, 34 deletions
diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp index f9c181c205..7fb83c6477 100644 --- a/src/libs/utils/synchronousprocess.cpp +++ b/src/libs/utils/synchronousprocess.cpp @@ -36,6 +36,7 @@ #include <QTextCodec> #include <QDir> #include <QMessageBox> +#include <QThread> #include <QApplication> @@ -359,6 +360,11 @@ void SynchronousProcess::setProcessChannelMode(QProcess::ProcessChannelMode m) d->m_process.setProcessChannelMode(m); } +static bool isGuiThread() +{ + return QThread::currentThread() == QCoreApplication::instance()->thread(); +} + SynchronousProcessResponse SynchronousProcess::run(const QString &binary, const QStringList &args) { @@ -375,7 +381,8 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary, d->m_process.closeWriteChannel(); if (!d->m_startFailure) { d->m_timer.start(); - QApplication::setOverrideCursor(Qt::WaitCursor); + if (isGuiThread()) + QApplication::setOverrideCursor(Qt::WaitCursor); d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); if (d->m_result.result == SynchronousProcessResponse::Finished || d->m_result.result == SynchronousProcessResponse::FinishedError) { processStdOut(false); @@ -386,7 +393,8 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary, d->m_result.stdErr = d->m_stdErr.data; d->m_timer.stop(); - QApplication::restoreOverrideCursor(); + if (isGuiThread()) + QApplication::restoreOverrideCursor(); } if (debug) @@ -396,6 +404,8 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary, static inline bool askToKill(const QString &binary = QString()) { + if (!isGuiThread()) + return true; const QString title = SynchronousProcess::tr("Process not Responding"); QString msg = binary.isEmpty() ? SynchronousProcess::tr("The process is not responding.") : diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 571d94fe00..cdb30368fb 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -1376,7 +1376,9 @@ ClearCaseResponse const Utils::SynchronousProcessResponse sp_resp = VcsBase::VcsBasePlugin::runVcs(workingDir, executable, - arguments, timeOut, flags, outputCodec); + arguments, timeOut, + VcsBase::VcsBasePlugin::sshPrompt(), + flags, outputCodec); response.error = sp_resp.result != Utils::SynchronousProcessResponse::Finished; if (response.error) diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 06a54fa683..1371e2418a 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -1236,9 +1236,8 @@ CvsResponse CvsPlugin::runCvs(const QString &workingDirectory, } // Run, connect stderr to the output window const Utils::SynchronousProcessResponse sp_resp = - runVcs(workingDirectory, executable, - m_settings.addOptions(arguments), - timeOut, flags, outputCodec); + runVcs(workingDirectory, executable, m_settings.addOptions(arguments), + timeOut, VcsBase::VcsBasePlugin::sshPrompt(), flags, outputCodec); response.result = CvsResponse::OtherError; response.stdErr = sp_resp.stdErr; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 57a2f37664..17fd2e507d 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2322,7 +2322,7 @@ Utils::SynchronousProcessResponse GitClient::synchronousGit(const QString &worki { return VcsBasePlugin::runVcs(workingDirectory, gitBinaryPath(), gitArguments, settings()->intValue(GitSettings::timeoutKey) * 1000, - processEnvironment(), + processEnvironment(), VcsBase::VcsBasePlugin::sshPrompt(), flags, outputCodec); } diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 274cd57a65..2a98a4ecb0 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -146,7 +146,8 @@ bool MercurialClient::synchronousPull(const QString &workingDir, const QString & QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(QLatin1String("LANGUAGE"), QLatin1String("C")); const Utils::SynchronousProcessResponse resp = VcsBase::VcsBasePlugin::runVcs( - workingDir, binary, args, timeoutSec * 1000, env, flags); + workingDir, binary, args, timeoutSec * 1000, env, + VcsBase::VcsBasePlugin::sshPrompt(), flags); const bool ok = resp.result == Utils::SynchronousProcessResponse::Finished; parsePullOutput(resp.stdOut.trimmed()); diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 13268bc36a..aff1a6e8b2 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -1120,7 +1120,8 @@ SubversionPlugin::Version SubversionPlugin::svnVersion() args << QLatin1String("--version") << QLatin1String("-q"); const Utils::SynchronousProcessResponse response = VcsBase::VcsBasePlugin::runVcs(QDir().absolutePath(), m_settings.binaryPath(), - args, m_settings.timeOutMs(), 0); + args, m_settings.timeOutMs(), + VcsBase::VcsBasePlugin::sshPrompt(), 0); if (response.result == Utils::SynchronousProcessResponse::Finished && response.exitCode == 0) { m_svnVersionBinary = m_settings.binaryPath(); @@ -1154,8 +1155,8 @@ SubversionResponse SubversionPlugin::runSvn(const QString &workingDir, const QStringList completeArguments = SubversionPlugin::addAuthenticationOptions(arguments, userName, password); const Utils::SynchronousProcessResponse sp_resp = - VcsBase::VcsBasePlugin::runVcs(workingDir, executable, - completeArguments, timeOut, flags, outputCodec); + VcsBase::VcsBasePlugin::runVcs(workingDir, executable, completeArguments, timeOut, + VcsBase::VcsBasePlugin::sshPrompt(), flags, outputCodec); response.error = sp_resp.result != Utils::SynchronousProcessResponse::Finished; if (response.error) diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index ffa4b42bbc..9e4f316de9 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -318,8 +318,8 @@ Utils::SynchronousProcessResponse VcsBaseClient::vcsSynchronousExec( { const QString binary = settings()->binaryPath(); const int timeoutSec = settings()->intValue(VcsBaseClientSettings::timeoutKey); - return VcsBase::VcsBasePlugin::runVcs(workingDirectory, binary, args, - timeoutSec * 1000, flags, outputCodec); + return VcsBase::VcsBasePlugin::runVcs(workingDirectory, binary, args, timeoutSec * 1000, + VcsBase::VcsBasePlugin::sshPrompt(), flags, outputCodec); } void VcsBaseClient::annotate(const QString &workingDir, const QString &file, diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index a7133007df..0911da9d7e 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -468,6 +468,34 @@ VCSBASE_EXPORT QDebug operator<<(QDebug in, const VcsBasePluginState &state) return in; } +class OutputProxy : public QObject +{ + Q_OBJECT + + friend class VcsBasePlugin; + +public: + OutputProxy() + { + // Users of this class can either be in the GUI thread or in other threads. + // Use Qt::AutoConnection to always append in the GUI thread (directly or queued) + VcsBase::VcsBaseOutputWindow *outputWindow = VcsBase::VcsBaseOutputWindow::instance(); + connect(this, SIGNAL(append(QString)), outputWindow, SLOT(append(QString))); + connect(this, SIGNAL(appendSilently(QString)), outputWindow, SLOT(appendSilently(QString))); + connect(this, SIGNAL(appendError(QString)), outputWindow, SLOT(appendError(QString))); + connect(this, SIGNAL(appendCommand(QString,QString,QStringList)), + outputWindow, SLOT(appendCommand(QString,QString,QStringList))); + } + +signals: + void append(const QString &text); + void appendSilently(const QString &text); + void appendError(const QString &text); + void appendCommand(const QString &workingDirectory, + const QString &binary, + const QStringList &args); +}; + /*! \class VcsBase::VcsBasePlugin @@ -798,9 +826,9 @@ QString VcsBasePlugin::findRepositoryForDirectory(const QString &dirS, } // Is SSH prompt configured? -static inline QString sshPrompt() +QString VcsBasePlugin::sshPrompt() { - return VcsBase::Internal::VcsPlugin::instance()->settings().sshPasswordPrompt; + return Internal::VcsPlugin::instance()->settings().sshPasswordPrompt; } bool VcsBasePlugin::isSshPromptConfigured() @@ -810,22 +838,30 @@ bool VcsBasePlugin::isSshPromptConfigured() void VcsBasePlugin::setProcessEnvironment(QProcessEnvironment *e, bool forceCLocale) { + setProcessEnvironment(e, forceCLocale, sshPrompt()); +} + +void VcsBasePlugin::setProcessEnvironment(QProcessEnvironment *e, + bool forceCLocale, + const QString &sshPromptBinary) +{ if (forceCLocale) e->insert(QLatin1String("LANG"), QString(QLatin1Char('C'))); - const QString sshPromptBinary = sshPrompt(); if (!sshPromptBinary.isEmpty()) e->insert(QLatin1String("SSH_ASKPASS"), sshPromptBinary); } // Run a process fully synchronously, returning Utils::SynchronousProcessResponse // response struct and using the VcsBasePlugin flags as applicable -static SynchronousProcessResponse runVcsFullySynchronously(const QString &workingDir, +SynchronousProcessResponse VcsBasePlugin::runVcsFullySynchronously( + const QString &workingDir, const QString &binary, const QStringList &arguments, int timeOutMS, QProcessEnvironment env, + const QString &sshPasswordPrompt, unsigned flags, - QTextCodec *outputCodec = 0) + QTextCodec *outputCodec) { SynchronousProcessResponse response; if (binary.isEmpty()) { @@ -833,11 +869,9 @@ static SynchronousProcessResponse runVcsFullySynchronously(const QString &workin return response; } - VcsBase::VcsBaseOutputWindow *outputWindow = VcsBase::VcsBaseOutputWindow::instance(); - // Set up process unsigned processFlags = 0; - if (VcsBasePlugin::isSshPromptConfigured() && (flags & VcsBasePlugin::SshPasswordPrompt)) + if (!sshPasswordPrompt.isEmpty() && (flags & VcsBasePlugin::SshPasswordPrompt)) processFlags |= SynchronousProcess::UnixTerminalDisabled; QSharedPointer<QProcess> process = SynchronousProcess::createProcess(processFlags); if (!workingDir.isEmpty()) @@ -861,11 +895,12 @@ static SynchronousProcessResponse runVcsFullySynchronously(const QString &workin !SynchronousProcess::readDataFromProcess(*process.data(), timeOutMS, &stdOut, &stdErr, true); + OutputProxy output; if (!stdErr.isEmpty()) { response.stdErr = Utils::SynchronousProcess::normalizeNewlines( outputCodec ? outputCodec->toUnicode(stdErr) : QString::fromLocal8Bit(stdErr)); if (!(flags & VcsBasePlugin::SuppressStdErrInLogWindow)) - outputWindow->append(response.stdErr); + emit output.append(response.stdErr); } if (!stdOut.isEmpty()) { @@ -873,9 +908,9 @@ static SynchronousProcessResponse runVcsFullySynchronously(const QString &workin outputCodec ? outputCodec->toUnicode(stdOut) : QString::fromLocal8Bit(stdOut)); if (flags & VcsBasePlugin::ShowStdOutInLogWindow) { if (flags & VcsBasePlugin::SilentOutput) - outputWindow->appendSilently(response.stdOut); + emit output.appendSilently(response.stdOut); else - outputWindow->append(response.stdOut); + emit output.append(response.stdOut); } } @@ -897,12 +932,13 @@ SynchronousProcessResponse VcsBasePlugin::runVcs(const QString &workingDir, const QString &binary, const QStringList &arguments, int timeOutMS, + const QString &sshPasswordPrompt, unsigned flags, QTextCodec *outputCodec) { const QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); return runVcs(workingDir, binary, arguments, timeOutMS, env, - flags, outputCodec); + sshPasswordPrompt, flags, outputCodec); } SynchronousProcessResponse VcsBasePlugin::runVcs(const QString &workingDir, @@ -910,10 +946,12 @@ SynchronousProcessResponse VcsBasePlugin::runVcs(const QString &workingDir, const QStringList &arguments, int timeOutMS, QProcessEnvironment env, + const QString &sshPasswordPrompt, unsigned flags, QTextCodec *outputCodec) { SynchronousProcessResponse response; + OutputProxy output; if (binary.isEmpty()) { response.result = SynchronousProcessResponse::StartFailed; @@ -923,9 +961,9 @@ SynchronousProcessResponse VcsBasePlugin::runVcs(const QString &workingDir, VcsBase::VcsBaseOutputWindow *outputWindow = VcsBase::VcsBaseOutputWindow::instance(); if (!(flags & SuppressCommandLogging)) - outputWindow->appendCommand(workingDir, binary, arguments); + emit output.appendCommand(workingDir, binary, arguments); - const bool sshPromptConfigured = VcsBasePlugin::isSshPromptConfigured(); + const bool sshPromptConfigured = !sshPasswordPrompt.isEmpty(); if (debugExecution) { QDebug nsp = qDebug().nospace(); nsp << "VcsBasePlugin::runVcs" << workingDir << binary << arguments @@ -952,14 +990,14 @@ SynchronousProcessResponse VcsBasePlugin::runVcs(const QString &workingDir, nsp << " Codec: " << outputCodec->name(); } - VcsBase::VcsBasePlugin::setProcessEnvironment(&env, (flags & ForceCLocale)); + setProcessEnvironment(&env, (flags & ForceCLocale), sshPasswordPrompt); // TODO tell the document manager about expected repository changes // if (flags & ExpectRepoChanges) // Core::DocumentManager::expectDirectoryChange(workingDir); if (flags & FullySynchronously) { response = runVcsFullySynchronously(workingDir, binary, arguments, timeOutMS, - env, flags, outputCodec); + env, sshPasswordPrompt, flags, outputCodec); } else { // Run, connect stderr to the output window SynchronousProcess process; @@ -1000,10 +1038,9 @@ SynchronousProcessResponse VcsBasePlugin::runVcs(const QString &workingDir, // Success/Fail message in appropriate window? if (response.result == SynchronousProcessResponse::Finished) { if (flags & ShowSuccessMessage) - outputWindow->append(response.exitMessage(binary, timeOutMS)); - } else { - if (!(flags & SuppressFailMessageInLogWindow)) - outputWindow->appendError(response.exitMessage(binary, timeOutMS)); + emit output.append(response.exitMessage(binary, timeOutMS)); + } else if (!(flags & SuppressFailMessageInLogWindow)) { + emit output.appendError(response.exitMessage(binary, timeOutMS)); } if (flags & ExpectRepoChanges) { // TODO tell the document manager that the directory now received all expected changes @@ -1026,8 +1063,9 @@ bool VcsBasePlugin::runFullySynchronous(const QString &workingDirectory, if (binary.isEmpty()) return false; + OutputProxy output; if (!(flags & SuppressCommandLogging)) - VcsBase::VcsBaseOutputWindow::instance()->appendCommand(workingDirectory, binary, arguments); + emit output.appendCommand(workingDirectory, binary, arguments); // TODO tell the document manager about expected repository changes // if (flags & ExpectRepoChanges) diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h index ed60b866ad..5df80930ee 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.h +++ b/src/plugins/vcsbase/vcsbaseplugin.h @@ -151,6 +151,8 @@ public: // requires a terminal-less process) and sets LANG to 'C' to force English // (suppress LOCALE warnings/parse commands output) if desired. static void setProcessEnvironment(QProcessEnvironment *e, bool forceCLocale); + // Returns SSH prompt configured in settings. + static QString sshPrompt(); // Returns whether an SSH prompt is configured. static bool isSshPromptConfigured(); @@ -175,6 +177,7 @@ public: const QStringList &arguments, int timeOutMS, QProcessEnvironment env, + const QString &sshPasswordPrompt, unsigned flags = 0, QTextCodec *outputCodec = 0); @@ -182,6 +185,7 @@ public: const QString &binary, const QStringList &arguments, int timeOutMS, + const QString &sshPasswordPrompt, unsigned flags = 0, QTextCodec *outputCodec = 0); @@ -241,6 +245,20 @@ private slots: void slotTestRemoveSnapshot(); private: + static void setProcessEnvironment(QProcessEnvironment *e, + bool forceCLocale, + const QString &sshPasswordPrompt); + + static Utils::SynchronousProcessResponse runVcsFullySynchronously( + const QString &workingDir, + const QString &binary, + const QStringList &arguments, + int timeOutMS, + QProcessEnvironment env, + const QString &sshPasswordPrompt, + unsigned flags, + QTextCodec *outputCodec = 0); + VcsBasePluginPrivate *d; }; |