From 0af3c1f13ab5b16c8fb47780724c707501267dd4 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Mon, 14 Dec 2009 10:56:50 +0100
Subject: [PATCH] VCS Submit: Run check script in repository, do not front-trim
 message.

Make checkscript a bit more verbose.

Task-number: QTCREATORBUG-451
Task-number: QTCREATORBUG-422
---
 src/libs/utils/submiteditorwidget.cpp       | 20 +++++++----
 src/plugins/cvs/cvsplugin.cpp               |  1 +
 src/plugins/git/gitplugin.cpp               |  1 +
 src/plugins/mercurial/mercurialplugin.cpp   |  1 +
 src/plugins/perforce/perforceplugin.cpp     |  1 +
 src/plugins/subversion/subversionplugin.cpp |  1 +
 src/plugins/vcsbase/vcsbaseplugin.cpp       | 10 ++++--
 src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 40 +++++++++++++++++++--
 src/plugins/vcsbase/vcsbasesubmiteditor.h   |  7 ++--
 9 files changed, 69 insertions(+), 13 deletions(-)

diff --git a/src/libs/utils/submiteditorwidget.cpp b/src/libs/utils/submiteditorwidget.cpp
index 3433329d526..69b94f61f14 100644
--- a/src/libs/utils/submiteditorwidget.cpp
+++ b/src/libs/utils/submiteditorwidget.cpp
@@ -221,12 +221,20 @@ void SubmitEditorWidget::unregisterActions(QAction *editorUndoAction,  QAction *
     }
 }
 
-// Make sure we have one terminating NL
-static inline QString trimMessageText(const QString &t)
-{
-    QString rc = t.trimmed();
-    rc += QLatin1Char('\n');
-    return rc;
+// Make sure we have one terminating NL. Do not trim front as leading space might be
+// required for some formattings.
+static inline QString trimMessageText(QString t)
+{
+    if (t.isEmpty())
+        return t;
+    // Trim back of string.
+    const int last = t.size() - 1;
+    int lastWordCharacter = last;
+    for ( ; lastWordCharacter >= 0 && t.at(lastWordCharacter).isSpace() ; lastWordCharacter--) ;
+    if (lastWordCharacter != last)
+        t.truncate(lastWordCharacter + 1);
+    t += QLatin1Char('\n');
+    return t;
 }
 
 // Extract the wrapped text from a text edit, which performs
diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp
index 2f2a70f6ef1..711b557f038 100644
--- a/src/plugins/cvs/cvsplugin.cpp
+++ b/src/plugins/cvs/cvsplugin.cpp
@@ -626,6 +626,7 @@ void CVSPlugin::startCommit(const QString &workingDir, const QStringList &files)
     changeTmpFile.close();
     // Create a submit editor and set file list
     CVSSubmitEditor *editor = openCVSSubmitEditor(m_commitMessageFileName);
+    editor->setCheckScriptWorkingDirectory(m_commitRepository);
     editor->setStateList(statusOutput);
 }
 
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index aa09dd376f2..60d2187c3ff 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -513,6 +513,7 @@ Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const Commit
     // mechanism. Disable them correctly.
     submitEditor->registerActions(m_undoAction, m_redoAction, m_submitCurrentAction, m_diffSelectedFilesAction);
     submitEditor->setCommitData(cd);
+    submitEditor->setCheckScriptWorkingDirectory(m_submitRepository);
     connect(submitEditor, SIGNAL(diff(QStringList,QStringList)), this, SLOT(submitEditorDiff(QStringList,QStringList)));
     return editor;
 }
diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp
index b858e8ab124..3f5f728c1b9 100644
--- a/src/plugins/mercurial/mercurialplugin.cpp
+++ b/src/plugins/mercurial/mercurialplugin.cpp
@@ -555,6 +555,7 @@ void MercurialPlugin::showCommitWidget(const QList<QPair<QString, QString> > &st
     commitEditor->registerActions(editorUndo, editorRedo, editorCommit, editorDiff);
     connect(commitEditor, SIGNAL(diffSelectedFiles(QStringList)),
             this, SLOT(diffFromEditorSelected(QStringList)));
+    commitEditor->setCheckScriptWorkingDirectory(m_submitRepository);
 }
 
 void MercurialPlugin::diffFromEditorSelected(const QStringList &files)
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index 6f7a73e05cd..f3def714224 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -624,6 +624,7 @@ Core::IEditor *PerforcePlugin::openPerforceSubmitEditor(const QString &fileName,
     submitEditor->restrictToProjectFiles(depotFileNames);
     submitEditor->registerActions(m_undoAction, m_redoAction, m_submitCurrentLogAction, m_diffSelectedFiles);
     connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(slotSubmitDiff(QStringList)));
+    submitEditor->setCheckScriptWorkingDirectory(m_commitWorkingDirectory);
     return editor;
 }
 
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
index cc6978cf027..cdf46123512 100644
--- a/src/plugins/subversion/subversionplugin.cpp
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -499,6 +499,7 @@ SubversionSubmitEditor *SubversionPlugin::openSubversionSubmitEditor(const QStri
     QTC_ASSERT(submitEditor, /**/);
     submitEditor->registerActions(m_submitUndoAction, m_submitRedoAction, m_submitCurrentLogAction, m_submitDiffAction);
     connect(submitEditor, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(diffCommitFiles(QStringList)));
+    submitEditor->setCheckScriptWorkingDirectory(m_commitRepository);
 
     return submitEditor;
 }
diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp
index 78c72de5657..dd0007ac850 100644
--- a/src/plugins/vcsbase/vcsbaseplugin.cpp
+++ b/src/plugins/vcsbase/vcsbaseplugin.cpp
@@ -170,11 +170,15 @@ void StateListener::slotStateChanged()
     const Core::ICore *core = Core::ICore::instance();
     Core::VCSManager *vcsManager = core->vcsManager();
 
-    // Get the current file. Are we on a temporary submit editor or something? Ignore.
+    // Get the current file. Are we on a temporary submit editor indicated by
+    // temporary path prefix or does the file contains a hash, indicating a project
+    // folder?
     State state;
     state.currentFile = core->fileManager()->currentFile();
-    if (!state.currentFile.isEmpty() && state.currentFile.startsWith(QDir::tempPath()))
-        state.currentFile.clear();
+    if (!state.currentFile.isEmpty()) {
+        if (state.currentFile.contains(QLatin1Char('#')) || state.currentFile.startsWith(QDir::tempPath()))
+            state.currentFile.clear();
+    }
     // Get the file and its control. Do not use the file unless we find one
     Core::IVersionControl *fileControl = 0;
     if (!state.currentFile.isEmpty()) {
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
index 47b07aeca92..d78bc340692 100644
--- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
@@ -28,6 +28,7 @@
 **************************************************************************/
 
 #include "vcsbasesubmiteditor.h"
+#include "vcsbaseoutputwindow.h"
 #include "vcsbasesettings.h"
 #include "vcsplugin.h"
 #include "nicknamedialog.h"
@@ -88,6 +89,7 @@ struct VCSBaseSubmitEditorPrivate
     QToolBar *m_toolWidget;
     const VCSBaseSubmitEditorParameters *m_parameters;
     QString m_displayName;
+    QString m_checkScriptWorkingDirectory;
     VCSBase::Internal::SubmitEditorFile *m_file;
     QList<int> m_contexts;
 
@@ -314,6 +316,16 @@ void VCSBaseSubmitEditor::setDisplayName(const QString &title)
     m_d->m_displayName = title;
 }
 
+QString VCSBaseSubmitEditor::checkScriptWorkingDirectory() const
+{
+    return m_d->m_checkScriptWorkingDirectory;
+}
+
+void VCSBaseSubmitEditor::setCheckScriptWorkingDirectory(const QString &s)
+{
+    m_d->m_checkScriptWorkingDirectory = s;
+}
+
 bool VCSBaseSubmitEditor::duplicateSupported() const
 {
     return false;
@@ -531,6 +543,13 @@ bool VCSBaseSubmitEditor::checkSubmitMessage(QString *errorMessage) const
     return rc;
 }
 
+static inline QString msgCheckScript(const QString &workingDir, const QString &cmd)
+{
+    return workingDir.isEmpty() ?
+           VCSBaseSubmitEditor::tr("Executing %1").arg(cmd) :
+           VCSBaseSubmitEditor::tr("Executing [%1] %2").arg(workingDir, cmd);
+}
+
 bool VCSBaseSubmitEditor::runSubmitMessageCheckScript(const QString &checkScript, QString *errorMessage) const
 {
     // Write out message
@@ -548,8 +567,13 @@ bool VCSBaseSubmitEditor::runSubmitMessageCheckScript(const QString &checkScript
     messageFile.write(fileContents().toUtf8());
     messageFile.close();
     // Run check process
+    VCSBaseOutputWindow *outputWindow = VCSBaseOutputWindow::instance();
+    outputWindow->appendCommand(msgCheckScript(m_d->m_checkScriptWorkingDirectory, checkScript));
     QProcess checkProcess;
+    if (!m_d->m_checkScriptWorkingDirectory.isEmpty())
+        checkProcess.setWorkingDirectory(m_d->m_checkScriptWorkingDirectory);
     checkProcess.start(checkScript, QStringList(messageFileName));
+    checkProcess.closeWriteChannel();
     if (!checkProcess.waitForStarted()) {
         *errorMessage = tr("The check script '%1' could not be started: %2").arg(checkScript, checkProcess.errorString());
         return false;
@@ -558,11 +582,23 @@ bool VCSBaseSubmitEditor::runSubmitMessageCheckScript(const QString &checkScript
         *errorMessage = tr("The check script '%1' could not be run: %2").arg(checkScript, checkProcess.errorString());
         return false;
     }
+    if (checkProcess.exitStatus() != QProcess::NormalExit) {
+        *errorMessage = tr("The check script '%1' crashed").arg(checkScript);
+        return false;
+    }
+    const QString stdOut = QString::fromLocal8Bit(checkProcess.readAllStandardOutput());
+    if (!stdOut.isEmpty())
+        outputWindow->appendSilently(stdOut);
+    const QString stdErr = QString::fromLocal8Bit(checkProcess.readAllStandardError());    
+    if (!stdErr.isEmpty())
+        outputWindow->appendSilently(stdErr);
     const int exitCode = checkProcess.exitCode();
     if (exitCode != 0) {
-        *errorMessage = QString::fromLocal8Bit(checkProcess.readAllStandardError());
+        const QString exMessage = tr("The check script returned exit code %1.").arg(exitCode);
+        outputWindow->appendError(exMessage);
+        *errorMessage = stdErr;
         if (errorMessage->isEmpty())
-            *errorMessage = tr("The check script returned exit code %1.").arg(exitCode);
+            *errorMessage = exMessage;
         return false;
     }
     return true;
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.h b/src/plugins/vcsbase/vcsbasesubmiteditor.h
index fea9e469a22..75acdcbca15 100644
--- a/src/plugins/vcsbase/vcsbasesubmiteditor.h
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.h
@@ -79,8 +79,7 @@ struct VCSBASE_EXPORT VCSBaseSubmitEditorParameters {
  * signal and then asking the IFile interface of the editor to save the file
  * within a IFileManager::blockFileChange() section
  * and to launch the submit process. In addition, the action registered
- * for submit sho src/libs/utils/submiteditorwidget.h
-uld be connected to a slot triggering the close of the
+ * for submit should be connected to a slot triggering the close of the
  * current editor in the editor manager. */
 
 class VCSBASE_EXPORT VCSBaseSubmitEditor : public Core::IEditor
@@ -90,6 +89,7 @@ class VCSBASE_EXPORT VCSBaseSubmitEditor : public Core::IEditor
     Q_PROPERTY(QAbstractItemView::SelectionMode fileListSelectionMode READ fileListSelectionMode WRITE setFileListSelectionMode DESIGNABLE true)
     Q_PROPERTY(bool lineWrap READ lineWrap WRITE setLineWrap DESIGNABLE true)
     Q_PROPERTY(int lineWrapWidth READ lineWrapWidth WRITE setLineWrapWidth DESIGNABLE true)
+    Q_PROPERTY(QString checkScriptWorkingDirectory READ checkScriptWorkingDirectory WRITE setCheckScriptWorkingDirectory DESIGNABLE true)
 public:
     typedef QList<int> Context;
 
@@ -130,6 +130,9 @@ public:
     int lineWrapWidth() const;
     void setLineWrapWidth(int);
 
+    QString checkScriptWorkingDirectory() const;
+    void setCheckScriptWorkingDirectory(const QString &);
+
     // Core::IEditor
     virtual bool createNew(const QString &contents);
     virtual bool open(const QString &fileName);
-- 
GitLab