From 214679d65ba4ebd2d2be0b177f5eeac7df6d32aa Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Fri, 26 Feb 2010 17:43:37 +0100
Subject: [PATCH] Git: Improve Timeouts.

- Observe timeout setting when running synchronous commands.
- Increase Default on Windows
- Stop process with terminate first (signal).
Task-number: QTCREATORBUG-777
---
 src/plugins/git/gitclient.cpp    | 14 +++++++-------
 src/plugins/git/gitcommand.cpp   | 23 ++++++++++++++++++++---
 src/plugins/git/gitcommand.h     |  8 ++++++++
 src/plugins/git/gitsettings.cpp  | 17 ++++++++++++-----
 src/plugins/git/gitsettings.h    |  2 +-
 src/plugins/git/settingspage.cpp |  4 ++--
 6 files changed, 50 insertions(+), 18 deletions(-)

diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 5026295e151..c7a150a2ef4 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -236,20 +236,20 @@ void GitClient::diff(const QString &workingDirectory,
        QStringList arguments(commonDiffArgs);
        arguments << diffArgs;
        VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(binary, arguments));
-       command->addJob(arguments, m_settings.timeout);
+       command->addJob(arguments, m_settings.timeoutSeconds);
     } else {
         // Files diff.
         if (!unstagedFileNames.empty()) {
            QStringList arguments(commonDiffArgs);
            arguments << QLatin1String("--") << unstagedFileNames;
            VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(binary, arguments));
-           command->addJob(arguments, m_settings.timeout);
+           command->addJob(arguments, m_settings.timeoutSeconds);
         }
         if (!stagedFileNames.empty()) {
            QStringList arguments(commonDiffArgs);
            arguments << QLatin1String("--cached") << diffArgs << QLatin1String("--") << stagedFileNames;
            VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(binary, arguments));
-           command->addJob(arguments, m_settings.timeout);
+           command->addJob(arguments, m_settings.timeoutSeconds);
         }
     }
     command->execute();
@@ -985,7 +985,7 @@ GitCommand *GitClient::executeGit(const QString &workingDirectory,
 {
     VCSBase::VCSBaseOutputWindow::instance()->appendCommand(formatCommand(QLatin1String(Constants::GIT_BINARY), arguments));
     GitCommand *command = createCommand(workingDirectory, editor, outputToWindow, editorLineNumber);
-    command->addJob(arguments, m_settings.timeout);
+    command->addJob(arguments, m_settings.timeoutSeconds);
     command->setTerminationReportMode(tm);
     command->execute();
     return command;
@@ -1042,10 +1042,10 @@ bool GitClient::synchronousGit(const QString &workingDirectory,
         return false;
     }
 
-    if (!process.waitForFinished()) {
+    if (!process.waitForFinished(m_settings.timeoutSeconds * 1000)) {
         if (errorText)
-            *errorText = "Error: Git timed out.";
-        process.kill();
+            *errorText = GitCommand::msgTimeout(m_settings.timeoutSeconds).toLocal8Bit();
+        GitCommand::stopProcess(process);
         return false;
     }
 
diff --git a/src/plugins/git/gitcommand.cpp b/src/plugins/git/gitcommand.cpp
index fed9d81b671..e1f4ac3a948 100644
--- a/src/plugins/git/gitcommand.cpp
+++ b/src/plugins/git/gitcommand.cpp
@@ -112,6 +112,22 @@ void GitCommand::execute()
                                      QLatin1String("Git.action"));
 }
 
+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)
@@ -139,10 +155,11 @@ void GitCommand::run()
         }
 
         process.closeWriteChannel();
-        if (!process.waitForFinished(m_jobs.at(j).timeout * 1000)) {
-            process.terminate();
+        const int timeOutSeconds = m_jobs.at(j).timeout;
+        if (!process.waitForFinished(timeOutSeconds * 1000)) {
+            stopProcess(process);
             ok = false;
-            error += QLatin1String("Error: Git timed out");
+            error += msgTimeout(timeOutSeconds);
             break;
         }
 
diff --git a/src/plugins/git/gitcommand.h b/src/plugins/git/gitcommand.h
index 8f1c5aad0ec..9345ea4d3f1 100644
--- a/src/plugins/git/gitcommand.h
+++ b/src/plugins/git/gitcommand.h
@@ -34,6 +34,10 @@
 #include <QtCore/QStringList>
 #include <QtCore/QVariant>
 
+QT_BEGIN_NAMESPACE
+class QProcess;
+QT_END_NAMESPACE
+
 namespace Git {
 namespace Internal {
 
@@ -66,6 +70,10 @@ public:
     TerminationReportMode reportTerminationMode() const;
     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();
 
diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp
index 13277d225d2..8c7a87a6afe 100644
--- a/src/plugins/git/gitsettings.cpp
+++ b/src/plugins/git/gitsettings.cpp
@@ -45,7 +45,14 @@ static const char *promptToSubmitKeyC = "PromptForSubmit";
 static const char *omitAnnotationDateKeyC = "OmitAnnotationDate";
 static const char *spaceIgnorantBlameKeyC = "SpaceIgnorantBlame";
 
-enum { defaultLogCount =  100 , defaultTimeOut = 30};
+enum {
+    defaultLogCount =  100 ,
+#ifdef Q_OS_WIN
+    defaultTimeOut = 60
+#else	
+    defaultTimeOut = 30
+#endif	
+};
 
 namespace Git {
 namespace Internal {
@@ -53,7 +60,7 @@ namespace Internal {
 GitSettings::GitSettings() :
     adoptPath(false),
     logCount(defaultLogCount),
-    timeout(defaultTimeOut),
+    timeoutSeconds(defaultTimeOut),
     promptToSubmit(true),
     omitAnnotationDate(false),
     spaceIgnorantBlame(true)
@@ -66,7 +73,7 @@ void GitSettings::fromSettings(QSettings *settings)
     adoptPath = settings->value(QLatin1String(sysEnvKeyC), false).toBool();
     path = settings->value(QLatin1String(pathKeyC), QString()).toString();
     logCount = settings->value(QLatin1String(logCountKeyC), defaultLogCount).toInt();
-    timeout = settings->value(QLatin1String(timeoutKeyC), defaultTimeOut).toInt();
+    timeoutSeconds = settings->value(QLatin1String(timeoutKeyC), defaultTimeOut).toInt();
     promptToSubmit = settings->value(QLatin1String(promptToSubmitKeyC), true).toBool();
     omitAnnotationDate = settings->value(QLatin1String(omitAnnotationDateKeyC), false).toBool();
     spaceIgnorantBlame = settings->value(QLatin1String(spaceIgnorantBlameKeyC), true).toBool();
@@ -79,7 +86,7 @@ void GitSettings::toSettings(QSettings *settings) const
     settings->setValue(QLatin1String(sysEnvKeyC), adoptPath);
     settings->setValue(QLatin1String(pathKeyC), path);
     settings->setValue(QLatin1String(logCountKeyC), logCount);
-    settings->setValue(QLatin1String(timeoutKeyC), timeout);
+    settings->setValue(QLatin1String(timeoutKeyC), timeoutSeconds);
     settings->setValue(QLatin1String(promptToSubmitKeyC), promptToSubmit);
     settings->setValue(QLatin1String(omitAnnotationDateKeyC), omitAnnotationDate);
     settings->setValue(QLatin1String(spaceIgnorantBlameKeyC), spaceIgnorantBlame);
@@ -89,7 +96,7 @@ void GitSettings::toSettings(QSettings *settings) const
 bool GitSettings::equals(const GitSettings &s) const
 {
     return adoptPath == s.adoptPath && path == s.path && logCount == s.logCount
-           && timeout == s.timeout && promptToSubmit == s.promptToSubmit
+           && timeoutSeconds == s.timeoutSeconds && promptToSubmit == s.promptToSubmit
            && omitAnnotationDate == s.omitAnnotationDate && spaceIgnorantBlame == s.spaceIgnorantBlame;
 }
 
diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h
index e1ca964b8a4..ef0b46c21f7 100644
--- a/src/plugins/git/gitsettings.h
+++ b/src/plugins/git/gitsettings.h
@@ -54,7 +54,7 @@ struct GitSettings
     bool adoptPath;
     QString path;
     int logCount;
-    int timeout;
+    int timeoutSeconds;
     bool promptToSubmit;
     bool omitAnnotationDate;
     bool spaceIgnorantBlame;
diff --git a/src/plugins/git/settingspage.cpp b/src/plugins/git/settingspage.cpp
index 61abe4148e5..f9157d7de27 100644
--- a/src/plugins/git/settingspage.cpp
+++ b/src/plugins/git/settingspage.cpp
@@ -55,7 +55,7 @@ GitSettings SettingsPageWidget::settings() const
     rc.path = m_ui.pathLineEdit->text();
     rc.adoptPath = m_ui.environmentGroupBox->isChecked() && !rc.path.isEmpty();
     rc.logCount = m_ui.logCountSpinBox->value();
-    rc.timeout = m_ui.timeoutSpinBox->value();
+    rc.timeoutSeconds = m_ui.timeoutSpinBox->value();
     rc.promptToSubmit = m_ui.promptToSubmitCheckBox->isChecked();
     rc.omitAnnotationDate = m_ui.omitAnnotationDataCheckBox->isChecked();
     rc.spaceIgnorantBlame = m_ui.spaceIgnorantBlameCheckBox->isChecked();
@@ -67,7 +67,7 @@ void SettingsPageWidget::setSettings(const GitSettings &s)
     m_ui.environmentGroupBox->setChecked(s.adoptPath);
     m_ui.pathLineEdit->setText(s.path);
     m_ui.logCountSpinBox->setValue(s.logCount);
-    m_ui.timeoutSpinBox->setValue(s.timeout);
+    m_ui.timeoutSpinBox->setValue(s.timeoutSeconds);
     m_ui.promptToSubmitCheckBox->setChecked(s.promptToSubmit);
     m_ui.omitAnnotationDataCheckBox->setChecked(s.omitAnnotationDate);
     m_ui.spaceIgnorantBlameCheckBox->setChecked(s.spaceIgnorantBlame);
-- 
GitLab