forked from qt-creator/qt-creator
VCS: Allow to run commands synchronously
Run some commands synchronously. This avoids issues with the UI reacting to file changes done by the VCS on windows which can lead to crashes. Task-number: QTCREATORBUG-3021 Reviewed-by: Tobias Hunger
This commit is contained in:
committed by
Tobias Hunger
parent
a13014eb4e
commit
818f5f0e78
@@ -934,13 +934,13 @@ bool PerforcePlugin::vcsMove(const QString &workingDir, const QString &from, con
|
|||||||
QStringList args;
|
QStringList args;
|
||||||
args << QLatin1String("edit") << from;
|
args << QLatin1String("edit") << from;
|
||||||
const PerforceResponse editResult = runP4Cmd(workingDir, args,
|
const PerforceResponse editResult = runP4Cmd(workingDir, args,
|
||||||
CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
|
RunFullySynchronous|CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
|
||||||
if (editResult.error)
|
if (editResult.error)
|
||||||
return false;
|
return false;
|
||||||
args.clear();
|
args.clear();
|
||||||
args << QLatin1String("move") << from << to;
|
args << QLatin1String("move") << from << to;
|
||||||
const PerforceResponse moveResult = runP4Cmd(workingDir, args,
|
const PerforceResponse moveResult = runP4Cmd(workingDir, args,
|
||||||
CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
|
RunFullySynchronous|CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
|
||||||
return !moveResult.error;
|
return !moveResult.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1219,11 +1219,9 @@ bool SubversionPlugin::vcsMove(const QString &workingDir, const QString &from, c
|
|||||||
{
|
{
|
||||||
QStringList args(QLatin1String("move"));
|
QStringList args(QLatin1String("move"));
|
||||||
args << QDir::toNativeSeparators(from) << QDir::toNativeSeparators(to);
|
args << QDir::toNativeSeparators(from) << QDir::toNativeSeparators(to);
|
||||||
qDebug()<<args;
|
|
||||||
const SubversionResponse response =
|
const SubversionResponse response =
|
||||||
runSvn(workingDir, args, m_settings.timeOutMS(),
|
runSvn(workingDir, args, m_settings.timeOutMS(),
|
||||||
SshPasswordPrompt|ShowStdOutInLogWindow);
|
SshPasswordPrompt|ShowStdOutInLogWindow|FullySynchronously);
|
||||||
qDebug() << response.stdOut << "\n"<<response.stdErr;
|
|
||||||
return !response.error;
|
return !response.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -50,6 +50,7 @@
|
|||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QSharedData>
|
#include <QtCore/QSharedData>
|
||||||
#include <QtCore/QScopedPointer>
|
#include <QtCore/QScopedPointer>
|
||||||
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QtCore/QProcessEnvironment>
|
#include <QtCore/QProcessEnvironment>
|
||||||
#include <QtCore/QTextStream>
|
#include <QtCore/QTextStream>
|
||||||
#include <QtCore/QTextCodec>
|
#include <QtCore/QTextCodec>
|
||||||
@@ -701,6 +702,72 @@ void VCSBasePlugin::setProcessEnvironment(QProcessEnvironment *e, bool forceCLoc
|
|||||||
e->insert(QLatin1String("SSH_ASKPASS"), sshPromptBinary);
|
e->insert(QLatin1String("SSH_ASKPASS"), sshPromptBinary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run a process fully synchronously, returning Utils::SynchronousProcessResponse
|
||||||
|
// response struct and using the VCSBasePlugin flags as applicable
|
||||||
|
static Utils::SynchronousProcessResponse
|
||||||
|
runVCS_FullySynchronously(const QString &workingDir,
|
||||||
|
const QString &binary,
|
||||||
|
const QStringList &arguments,
|
||||||
|
int timeOutMS,
|
||||||
|
QProcessEnvironment env,
|
||||||
|
unsigned flags,
|
||||||
|
QTextCodec *outputCodec = 0)
|
||||||
|
{
|
||||||
|
VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
|
||||||
|
|
||||||
|
// Set up process
|
||||||
|
unsigned processFlags = 0;
|
||||||
|
if (VCSBasePlugin::isSshPromptConfigured() && (flags & VCSBasePlugin::SshPasswordPrompt))
|
||||||
|
processFlags |= Utils::SynchronousProcess::UnixTerminalDisabled;
|
||||||
|
QSharedPointer<QProcess> process = Utils::SynchronousProcess::createProcess(processFlags);
|
||||||
|
if (!workingDir.isEmpty())
|
||||||
|
process->setWorkingDirectory(workingDir);
|
||||||
|
process->setProcessEnvironment(env);
|
||||||
|
if (flags & VCSBasePlugin::MergeOutputChannels)
|
||||||
|
process->setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
|
||||||
|
// Start
|
||||||
|
process->start(binary, arguments);
|
||||||
|
Utils::SynchronousProcessResponse response;
|
||||||
|
if (!process->waitForStarted()) {
|
||||||
|
response.result = Utils::SynchronousProcessResponse::StartFailed;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process output
|
||||||
|
QByteArray stdOut;
|
||||||
|
QByteArray stdErr;
|
||||||
|
const bool timedOut =
|
||||||
|
!Utils::SynchronousProcess::readDataFromProcess(*process.data(), timeOutMS,
|
||||||
|
&stdOut, &stdErr, true);
|
||||||
|
|
||||||
|
if (!stdErr.isEmpty()) {
|
||||||
|
response.stdErr = QString::fromLocal8Bit(stdErr).remove('\r');
|
||||||
|
if (!(flags & VCSBasePlugin::SuppressStdErrInLogWindow))
|
||||||
|
outputWindow->append(response.stdErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stdOut.isEmpty()) {
|
||||||
|
response.stdOut = (outputCodec ? outputCodec->toUnicode(stdOut) : QString::fromLocal8Bit(stdOut))
|
||||||
|
.remove('\r');
|
||||||
|
if (flags & VCSBasePlugin::ShowStdOutInLogWindow)
|
||||||
|
outputWindow->append(response.stdOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Utils::SynchronousProcessResponse
|
Utils::SynchronousProcessResponse
|
||||||
VCSBasePlugin::runVCS(const QString &workingDir,
|
VCSBasePlugin::runVCS(const QString &workingDir,
|
||||||
const QString &binary,
|
const QString &binary,
|
||||||
@@ -747,56 +814,66 @@ Utils::SynchronousProcessResponse
|
|||||||
nsp << "suppress_log";
|
nsp << "suppress_log";
|
||||||
if (flags & ForceCLocale)
|
if (flags & ForceCLocale)
|
||||||
nsp << "c_locale";
|
nsp << "c_locale";
|
||||||
|
if (flags & FullySynchronously)
|
||||||
|
nsp << "fully_synchronously";
|
||||||
if (outputCodec)
|
if (outputCodec)
|
||||||
nsp << " Codec: " << outputCodec->name();
|
nsp << " Codec: " << outputCodec->name();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run, connect stderr to the output window
|
|
||||||
Utils::SynchronousProcess process;
|
|
||||||
if (!workingDir.isEmpty())
|
|
||||||
process.setWorkingDirectory(workingDir);
|
|
||||||
|
|
||||||
VCSBase::VCSBasePlugin::setProcessEnvironment(&env, (flags & ForceCLocale));
|
VCSBase::VCSBasePlugin::setProcessEnvironment(&env, (flags & ForceCLocale));
|
||||||
process.setProcessEnvironment(env);
|
|
||||||
process.setTimeout(timeOutMS);
|
|
||||||
if (outputCodec)
|
|
||||||
process.setStdOutCodec(outputCodec);
|
|
||||||
|
|
||||||
// Suppress terminal on UNIX for ssh prompts if it is configured.
|
Utils::SynchronousProcessResponse response;
|
||||||
if (sshPromptConfigured && (flags & SshPasswordPrompt))
|
|
||||||
process.setFlags(Utils::SynchronousProcess::UnixTerminalDisabled);
|
|
||||||
|
|
||||||
// connect stderr to the output window if desired
|
if (flags & FullySynchronously) {
|
||||||
if (flags & MergeOutputChannels) {
|
response = runVCS_FullySynchronously(workingDir, binary, arguments, timeOutMS,
|
||||||
process.setProcessChannelMode(QProcess::MergedChannels);
|
env, flags, outputCodec);
|
||||||
} else {
|
} else {
|
||||||
if (!(flags & SuppressStdErrInLogWindow)) {
|
// Run, connect stderr to the output window
|
||||||
process.setStdErrBufferedSignalsEnabled(true);
|
Utils::SynchronousProcess process;
|
||||||
connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
|
if (!workingDir.isEmpty())
|
||||||
|
process.setWorkingDirectory(workingDir);
|
||||||
|
|
||||||
|
process.setProcessEnvironment(env);
|
||||||
|
process.setTimeout(timeOutMS);
|
||||||
|
if (outputCodec)
|
||||||
|
process.setStdOutCodec(outputCodec);
|
||||||
|
|
||||||
|
// Suppress terminal on UNIX for ssh prompts if it is configured.
|
||||||
|
if (sshPromptConfigured && (flags & SshPasswordPrompt))
|
||||||
|
process.setFlags(Utils::SynchronousProcess::UnixTerminalDisabled);
|
||||||
|
|
||||||
|
// connect stderr to the output window if desired
|
||||||
|
if (flags & MergeOutputChannels) {
|
||||||
|
process.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
} else {
|
||||||
|
if (!(flags & SuppressStdErrInLogWindow)) {
|
||||||
|
process.setStdErrBufferedSignalsEnabled(true);
|
||||||
|
connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// connect stdout to the output window if desired
|
||||||
|
if (flags & ShowStdOutInLogWindow) {
|
||||||
|
process.setStdOutBufferedSignalsEnabled(true);
|
||||||
|
connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
|
||||||
|
}
|
||||||
|
|
||||||
|
process.setTimeOutMessageBoxEnabled(true);
|
||||||
|
|
||||||
|
// Run!
|
||||||
|
response = process.run(binary, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// connect stdout to the output window if desired
|
|
||||||
if (flags & ShowStdOutInLogWindow) {
|
|
||||||
process.setStdOutBufferedSignalsEnabled(true);
|
|
||||||
connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
|
|
||||||
}
|
|
||||||
|
|
||||||
process.setTimeOutMessageBoxEnabled(true);
|
|
||||||
|
|
||||||
// Run!
|
|
||||||
const Utils::SynchronousProcessResponse sp_resp = process.run(binary, arguments);
|
|
||||||
|
|
||||||
// Success/Fail message in appropriate window?
|
// Success/Fail message in appropriate window?
|
||||||
if (sp_resp.result == Utils::SynchronousProcessResponse::Finished) {
|
if (response.result == Utils::SynchronousProcessResponse::Finished) {
|
||||||
if (flags & ShowSuccessMessage)
|
if (flags & ShowSuccessMessage)
|
||||||
outputWindow->append(sp_resp.exitMessage(binary, timeOutMS));
|
outputWindow->append(response.exitMessage(binary, timeOutMS));
|
||||||
} else {
|
} else {
|
||||||
if (!(flags & SuppressFailMessageInLogWindow))
|
if (!(flags & SuppressFailMessageInLogWindow))
|
||||||
outputWindow->appendError(sp_resp.exitMessage(binary, timeOutMS));
|
outputWindow->appendError(response.exitMessage(binary, timeOutMS));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sp_resp;
|
return response;
|
||||||
}
|
}
|
||||||
} // namespace VCSBase
|
} // namespace VCSBase
|
||||||
|
|
||||||
|
@@ -192,7 +192,9 @@ public:
|
|||||||
SuppressFailMessageInLogWindow = 0x10, // No message VCS about failure in VCS output window.
|
SuppressFailMessageInLogWindow = 0x10, // No message VCS about failure in VCS output window.
|
||||||
SuppressCommandLogging = 0x20, // No command log entry in VCS output window.
|
SuppressCommandLogging = 0x20, // No command log entry in VCS output window.
|
||||||
ShowSuccessMessage = 0x40, // Show message about successful completion in VCS output window.
|
ShowSuccessMessage = 0x40, // Show message about successful completion in VCS output window.
|
||||||
ForceCLocale = 0x80 // Force C-locale for commands whose output is parsed.
|
ForceCLocale = 0x80, // Force C-locale for commands whose output is parsed.
|
||||||
|
FullySynchronously = 0x100 // Suppress local event loop (in case UI actions are
|
||||||
|
// triggered by file watchers).
|
||||||
};
|
};
|
||||||
|
|
||||||
static Utils::SynchronousProcessResponse
|
static Utils::SynchronousProcessResponse
|
||||||
|
Reference in New Issue
Block a user