VCS: Fix time-out handling for synchronous processes.

Introduce static utilities to Utils::SynchronousProcess
for synchronous processes that mimicks the handling
of Utils::SynchronousProcess (apply timeout after no
more data are available on stdout/stderr as opposed
to waitForFinished()).

Task-number: QTCREATORBUG-777
This commit is contained in:
Friedemann Kleint
2010-03-01 10:06:05 +01:00
parent 1f940786fb
commit a1fed931c4
15 changed files with 125 additions and 92 deletions

View File

@@ -49,6 +49,7 @@
#include <texteditor/itexteditor.h>
#include <utils/qtcassert.h>
#include <utils/synchronousprocess.h>
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseoutputwindow.h>
@@ -1042,22 +1043,16 @@ bool GitClient::synchronousGit(const QString &workingDirectory,
return false;
}
if (!process.waitForFinished(m_settings.timeoutSeconds * 1000)) {
if (errorText)
*errorText = GitCommand::msgTimeout(m_settings.timeoutSeconds).toLocal8Bit();
GitCommand::stopProcess(process);
if (!Utils::SynchronousProcess::readDataFromProcess(process, m_settings.timeoutSeconds * 1000,
outputText, errorText)) {
*errorText->append(GitCommand::msgTimeout(m_settings.timeoutSeconds).toLocal8Bit());
Utils::SynchronousProcess::stopProcess(process);
return false;
}
if (outputText)
*outputText = process.readAllStandardOutput();
if (errorText)
*errorText = process.readAllStandardError();
if (Git::Constants::debug)
qDebug() << "synchronousGit ex=" << process.exitCode();
return process.exitCode() == 0;
qDebug() << "synchronousGit ex=" << process.exitStatus() << process.exitCode();
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
}
static inline int
@@ -1546,7 +1541,8 @@ QString GitClient::readConfig(const QString &workingDirectory, const QStringList
arguments << QLatin1String("config") << configVar;
QByteArray outputText;
if (synchronousGit(workingDirectory, arguments, &outputText, 0, false))
QByteArray errorText;
if (synchronousGit(workingDirectory, arguments, &outputText, &errorText, false))
return commandOutputFromLocal8Bit(outputText);
return QString();
}

View File

@@ -230,8 +230,8 @@ private:
bool synchronousGit(const QString &workingDirectory,
const QStringList &arguments,
QByteArray* outputText = 0,
QByteArray* errorText = 0,
QByteArray* outputText,
QByteArray* errorText,
bool logCommandToWindow = true);
// determine version as '(major << 16) + (minor << 8) + patch' or 0.
unsigned synchronousGitVersion(bool silent, QString *errorMessage = 0);

View File

@@ -33,6 +33,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/synchronousprocess.h>
#include <QtCore/QDebug>
#include <QtCore/QProcess>
@@ -117,17 +118,6 @@ QString GitCommand::msgTimeout(int seconds)
return tr("Error: Git timed out after %1s.").arg(seconds);
}
bool GitCommand::stopProcess(QProcess &p)
{
if (p.state() != QProcess::Running)
return true;
p.terminate();
if (p.waitForFinished(300))
return true;
p.kill();
return p.waitForFinished(300);
}
void GitCommand::run()
{
if (Git::Constants::debug)
@@ -138,7 +128,8 @@ void GitCommand::run()
process.setEnvironment(m_environment);
QByteArray output;
QByteArray stdOut;
QByteArray stdErr;
QString error;
const int count = m_jobs.size();
@@ -156,20 +147,20 @@ void GitCommand::run()
process.closeWriteChannel();
const int timeOutSeconds = m_jobs.at(j).timeout;
if (!process.waitForFinished(timeOutSeconds * 1000)) {
stopProcess(process);
if (!Utils::SynchronousProcess::readDataFromProcess(process, timeOutSeconds * 1000,
&stdOut, &stdErr)) {
Utils::SynchronousProcess::stopProcess(process);
ok = false;
error += msgTimeout(timeOutSeconds);
break;
}
output += process.readAllStandardOutput();
error += QString::fromLocal8Bit(process.readAllStandardError());
error += QString::fromLocal8Bit(stdErr);
switch (m_reportTerminationMode) {
case NoReport:
break;
case ReportStdout:
output += msgTermination(process.exitCode(), m_binaryPath, m_jobs.at(j).arguments).toUtf8();
stdOut += msgTermination(process.exitCode(), m_binaryPath, m_jobs.at(j).arguments).toUtf8();
break;
case ReportStderr:
error += msgTermination(process.exitCode(), m_binaryPath, m_jobs.at(j).arguments);
@@ -178,16 +169,16 @@ void GitCommand::run()
}
// Special hack: Always produce output for diff
if (ok && output.isEmpty() && m_jobs.front().arguments.at(0) == QLatin1String("diff")) {
output += "The file does not differ from HEAD";
if (ok && stdOut.isEmpty() && m_jobs.front().arguments.at(0) == QLatin1String("diff")) {
stdOut += "The file does not differ from HEAD";
} else {
// @TODO: Remove, see below
if (ok && m_jobs.front().arguments.at(0) == QLatin1String("status"))
removeColorCodes(&output);
removeColorCodes(&stdOut);
}
if (ok && !output.isEmpty())
emit outputData(output);
if (ok && !stdOut.isEmpty())
emit outputData(stdOut);
if (!error.isEmpty())
emit errorText(error);

View File

@@ -71,8 +71,6 @@ public:
void setTerminationReportMode(TerminationReportMode m);
static QString msgTimeout(int seconds);
// Helper to kill a process by SIGNAL first, allowing for cleanup
static bool stopProcess(QProcess &p);
private:
void run();