summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/git/gitclient.cpp4
-rw-r--r--src/plugins/git/gitclient.h2
-rw-r--r--src/plugins/vcsbase/commonsettingspage.cpp6
-rw-r--r--src/plugins/vcsbase/commonsettingspage.ui56
-rw-r--r--src/plugins/vcsbase/commonvcssettings.cpp9
-rw-r--r--src/plugins/vcsbase/commonvcssettings.h2
-rw-r--r--src/plugins/vcsbase/vcsbaseeditor.cpp115
-rw-r--r--src/plugins/vcsbase/vcsbaseeditor.h25
-rw-r--r--src/plugins/vcsbase/vcsbaseplugin.cpp49
-rw-r--r--src/plugins/vcsbase/vcsbaseplugin.h4
10 files changed, 251 insertions, 21 deletions
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 3ab4944661..1ed8d8de63 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -521,6 +521,8 @@ void GitClient::diff(const QString &workingDirectory,
editor = createVCSEditor(editorId, title,
workingDirectory, true, "originalFileName", workingDirectory, argWidget);
+ connect(editor, SIGNAL(diffChunkReverted(VCSBase::DiffChunk)), argWidget, SLOT(redoCommand()));
+ editor->setRevertDiffChunkEnabled(true);
}
editor->setDiffBaseDirectory(workingDirectory);
@@ -575,6 +577,8 @@ void GitClient::diff(const QString &workingDirectory,
userDiffArgs = argWidget->arguments();
editor = createVCSEditor(editorId, title, sourceFile, true, "originalFileName", sourceFile, argWidget);
+ connect(editor, SIGNAL(diffChunkReverted(VCSBase::DiffChunk)), argWidget, SLOT(redoCommand()));
+ editor->setRevertDiffChunkEnabled(true);
}
QStringList cmdArgs;
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index b6aef5f2da..c1a67c52e9 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -306,6 +306,8 @@ public:
const QStringList &args);
virtual QStringList arguments() const = 0;
+
+public slots:
virtual void redoCommand() = 0;
protected slots:
diff --git a/src/plugins/vcsbase/commonsettingspage.cpp b/src/plugins/vcsbase/commonsettingspage.cpp
index 6cdeb8b0a7..1e6f0d13b6 100644
--- a/src/plugins/vcsbase/commonsettingspage.cpp
+++ b/src/plugins/vcsbase/commonsettingspage.cpp
@@ -58,6 +58,10 @@ CommonSettingsWidget::CommonSettingsWidget(QWidget *parent) :
m_ui->nickNameFieldsFileChooser->setExpectedKind(Utils::PathChooser::File);
m_ui->nickNameMailMapChooser->setExpectedKind(Utils::PathChooser::File);
m_ui->sshPromptChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
+ const QString patchToolTip = tr("Command used for reverting diff chunks");
+ m_ui->patchCommandLabel->setToolTip(patchToolTip);
+ m_ui->patchChooser->setToolTip(patchToolTip);
+ m_ui->patchChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
}
CommonSettingsWidget::~CommonSettingsWidget()
@@ -74,6 +78,7 @@ CommonVcsSettings CommonSettingsWidget::settings() const
rc.lineWrap= m_ui->lineWrapCheckBox->isChecked();
rc.lineWrapWidth = m_ui->lineWrapSpinBox->value();
rc.sshPasswordPrompt = m_ui->sshPromptChooser->path();
+ rc.patchCommand = m_ui->patchChooser->path();
return rc;
}
@@ -85,6 +90,7 @@ void CommonSettingsWidget::setSettings(const CommonVcsSettings &s)
m_ui->lineWrapCheckBox->setChecked(s.lineWrap);
m_ui->lineWrapSpinBox->setValue(s.lineWrapWidth);
m_ui->sshPromptChooser->setPath(s.sshPasswordPrompt);
+ m_ui->patchChooser->setPath(s.patchCommand);
}
QString CommonSettingsWidget::searchKeyWordMatchString() const
diff --git a/src/plugins/vcsbase/commonsettingspage.ui b/src/plugins/vcsbase/commonsettingspage.ui
index c15f9cd96f..e4a8cdd6b8 100644
--- a/src/plugins/vcsbase/commonsettingspage.ui
+++ b/src/plugins/vcsbase/commonsettingspage.ui
@@ -2,15 +2,10 @@
<ui version="4.0">
<class>CommonSettingsPage</class>
<widget class="QWidget" name="CommonSettingsPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>338</width>
- <height>166</height>
- </rect>
- </property>
<layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
<item row="0" column="0">
<widget class="QCheckBox" name="lineWrapCheckBox">
<property name="text">
@@ -56,12 +51,15 @@
<string>An executable which is called with the submit message in a temporary file as first argument. It should return with an exit != 0 and a message on standard error to indicate failure.</string>
</property>
<property name="text">
- <string>Submit message check script:</string>
+ <string>Submit message &amp;check script:</string>
+ </property>
+ <property name="buddy">
+ <cstring>submitMessageCheckScriptChooser</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
- <widget class="Utils::PathChooser" name="submitMessageCheckScriptChooser" native="true"/>
+ <widget class="Utils::PathChooser" name="submitMessageCheckScriptChooser"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="nickNameMailMapLabel">
@@ -70,12 +68,15 @@
name &lt;email&gt; alias &lt;email&gt;</string>
</property>
<property name="text">
- <string>User/alias configuration file:</string>
+ <string>User/&amp;alias configuration file:</string>
+ </property>
+ <property name="buddy">
+ <cstring>nickNameMailMapChooser</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
- <widget class="Utils::PathChooser" name="nickNameMailMapChooser" native="true"/>
+ <widget class="Utils::PathChooser" name="nickNameMailMapChooser"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="nickNameFieldsFileLabel">
@@ -83,12 +84,18 @@ name &lt;email&gt; alias &lt;email&gt;</string>
<string>A simple file containing lines with field names like &quot;Reviewed-By:&quot; which will be added below the submit editor.</string>
</property>
<property name="text">
- <string>User fields configuration file:</string>
+ <string>User &amp;fields configuration file:</string>
+ </property>
+ <property name="buddy">
+ <cstring>nickNameFieldsFileChooser</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
- <widget class="Utils::PathChooser" name="nickNameFieldsFileChooser" native="true"/>
+ <widget class="Utils::PathChooser" name="nickNameFieldsFileChooser"/>
+ </item>
+ <item row="5" column="1">
+ <widget class="Utils::PathChooser" name="sshPromptChooser"/>
</item>
<item row="6" column="0" colspan="2">
<spacer name="verticalSpacer">
@@ -106,6 +113,19 @@ name &lt;email&gt; alias &lt;email&gt;</string>
</property>
</spacer>
</item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="patchCommandLabel">
+ <property name="text">
+ <string>&amp;Patch command:</string>
+ </property>
+ <property name="buddy">
+ <cstring>patchChooser</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="Utils::PathChooser" name="patchChooser"/>
+ </item>
<item row="5" column="0">
<widget class="QLabel" name="sshPromptLabel">
<property name="toolTip">
@@ -113,13 +133,13 @@ name &lt;email&gt; alias &lt;email&gt;</string>
should a repository require SSH-authentication (see documentation on SSH and the environment variable SSH_ASKPASS).</string>
</property>
<property name="text">
- <string>SSH prompt command:</string>
+ <string>&amp;SSH prompt command:</string>
+ </property>
+ <property name="buddy">
+ <cstring>sshPromptChooser</cstring>
</property>
</widget>
</item>
- <item row="5" column="1">
- <widget class="Utils::PathChooser" name="sshPromptChooser" native="true"/>
- </item>
</layout>
</widget>
<customwidgets>
diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp
index fdb9ec8247..172af681f2 100644
--- a/src/plugins/vcsbase/commonvcssettings.cpp
+++ b/src/plugins/vcsbase/commonvcssettings.cpp
@@ -43,6 +43,8 @@ static const char submitMessageCheckScriptKeyC[] = "SubmitMessageCheckScript";
static const char lineWrapKeyC[] = "LineWrap";
static const char lineWrapWidthKeyC[] = "LineWrapWidth";
static const char sshPasswordPromptKeyC[] = "SshPasswordPrompt";
+static const char patchCommandKeyC[] = "PatchCommand";
+static const char patchCommandDefaultC[] = "patch";
static const int lineWrapWidthDefault = 72;
static const bool lineWrapDefault = true;
@@ -65,6 +67,7 @@ namespace Internal {
CommonVcsSettings::CommonVcsSettings() :
sshPasswordPrompt(sshPasswordPromptDefault()),
+ patchCommand(QLatin1String(patchCommandDefaultC)),
lineWrap(lineWrapDefault),
lineWrapWidth(lineWrapWidthDefault)
{
@@ -78,6 +81,7 @@ void CommonVcsSettings::toSettings(QSettings *s) const
s->setValue(QLatin1String(submitMessageCheckScriptKeyC), submitMessageCheckScript);
s->setValue(QLatin1String(lineWrapKeyC), lineWrap);
s->setValue(QLatin1String(lineWrapWidthKeyC), lineWrapWidth);
+ s->setValue(QLatin1String(patchCommandKeyC), patchCommand);
// Do not store the default setting to avoid clobbering the environment.
if (sshPasswordPrompt != sshPasswordPromptDefault()) {
s->setValue(QLatin1String(sshPasswordPromptKeyC), sshPasswordPrompt);
@@ -96,6 +100,7 @@ void CommonVcsSettings::fromSettings(QSettings *s)
lineWrap = s->value(QLatin1String(lineWrapKeyC), lineWrapDefault).toBool();
lineWrapWidth = s->value(QLatin1String(lineWrapWidthKeyC), lineWrapWidthDefault).toInt();
sshPasswordPrompt = s->value(QLatin1String(sshPasswordPromptKeyC), sshPasswordPromptDefault()).toString();
+ patchCommand = s->value(QLatin1String(patchCommandKeyC), QLatin1String(patchCommandDefaultC)).toString();
s->endGroup();
}
@@ -106,7 +111,8 @@ bool CommonVcsSettings::equals(const CommonVcsSettings &rhs) const
&& nickNameMailMap == rhs.nickNameMailMap
&& nickNameFieldListFile == rhs.nickNameFieldListFile
&& submitMessageCheckScript == rhs.submitMessageCheckScript
- && sshPasswordPrompt == rhs.sshPasswordPrompt;
+ && sshPasswordPrompt == rhs.sshPasswordPrompt
+ && patchCommand == rhs.patchCommand;
}
QDebug operator<<(QDebug d,const CommonVcsSettings& s)
@@ -117,6 +123,7 @@ QDebug operator<<(QDebug d,const CommonVcsSettings& s)
<< "' nickNameFieldListFile='" << s.nickNameFieldListFile
<< "'submitMessageCheckScript='" << s.submitMessageCheckScript
<< "'sshPasswordPrompt='" << s.sshPasswordPrompt
+ << "'patchCommand='" << s.patchCommand
<< "'\n";
return d;
}
diff --git a/src/plugins/vcsbase/commonvcssettings.h b/src/plugins/vcsbase/commonvcssettings.h
index f7e8aef933..8f182e27e7 100644
--- a/src/plugins/vcsbase/commonvcssettings.h
+++ b/src/plugins/vcsbase/commonvcssettings.h
@@ -58,6 +58,8 @@ struct CommonVcsSettings
// Executable run to graphically prompt for a SSH-password.
QString sshPasswordPrompt;
+ QString patchCommand;
+
bool lineWrap;
int lineWrapWidth;
diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp
index 69b7b24a18..4e5da7bf9d 100644
--- a/src/plugins/vcsbase/vcsbaseeditor.cpp
+++ b/src/plugins/vcsbase/vcsbaseeditor.cpp
@@ -36,6 +36,8 @@
#include "baseannotationhighlighter.h"
#include "vcsbasetextdocument.h"
#include "vcsbaseconstants.h"
+#include "vcsbaseoutputwindow.h"
+#include "vcsbaseplugin.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/ifile.h>
@@ -53,6 +55,7 @@
#include <QtCore/QDebug>
#include <QtCore/QFileInfo>
+#include <QtCore/QFile>
#include <QtCore/QProcess>
#include <QtCore/QRegExp>
#include <QtCore/QSet>
@@ -69,9 +72,27 @@
#include <QtGui/QToolBar>
#include <QtGui/QClipboard>
#include <QtGui/QApplication>
+#include <QtGui/QMessageBox>
namespace VCSBase {
+bool DiffChunk::isValid() const
+{
+ return !fileName.isEmpty() && !chunk.isEmpty();
+}
+
+QByteArray DiffChunk::asPatch() const
+{
+ const QByteArray fileNameBA = QFile::encodeName(fileName);
+ QByteArray rc = "--- ";
+ rc += fileNameBA;
+ rc += "\n+++ ";
+ rc += fileNameBA;
+ rc += '\n';
+ rc += chunk;
+ return rc;
+}
+
// VCSBaseEditor: An editor with no support for duplicates.
// Creates a browse combo in the toolbar for diff output.
// It also mirrors the signals of the VCSBaseEditor since the editor
@@ -161,6 +182,7 @@ struct VCSBaseEditorWidgetPrivate
bool m_fileLogAnnotateEnabled;
TextEditor::BaseTextEditor *m_editor;
QWidget *m_configurationWidget;
+ bool m_revertChunkEnabled;
};
VCSBaseEditorWidgetPrivate::VCSBaseEditorWidgetPrivate(const VCSBaseEditorParameters *type) :
@@ -170,7 +192,8 @@ VCSBaseEditorWidgetPrivate::VCSBaseEditorWidgetPrivate(const VCSBaseEditorParame
m_copyRevisionTextFormat(VCSBaseEditorWidget::tr("Copy \"%1\"")),
m_fileLogAnnotateEnabled(false),
m_editor(0),
- m_configurationWidget(0)
+ m_configurationWidget(0),
+ m_revertChunkEnabled(false)
{
}
@@ -444,7 +467,9 @@ void VCSBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e)
{
QMenu *menu = createStandardContextMenu();
// 'click on change-interaction'
- if (d->m_parameters->type == LogOutput || d->m_parameters->type == AnnotateOutput) {
+ switch (d->m_parameters->type) {
+ case LogOutput:
+ case AnnotateOutput:
d->m_currentChange = changeUnderCursor(cursorForPosition(e->pos()));
if (!d->m_currentChange.isEmpty()) {
switch (d->m_parameters->type) {
@@ -471,6 +496,18 @@ void VCSBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e)
break;
} // switch type
} // has current change
+ break;
+ case DiffOutput: {
+ menu->addSeparator();
+ QAction *revertAction = menu->addAction(tr("Revert Chunk..."));
+ const DiffChunk chunk = diffChunk(cursorForPosition(e->pos()));
+ revertAction->setEnabled(canRevertDiffChunk(chunk));
+ revertAction->setData(qVariantFromValue(chunk));
+ connect(revertAction, SIGNAL(triggered()), this, SLOT(slotRevertDiffChunk()));
+ }
+ break;
+ default:
+ break;
}
menu->exec(e->globalPos());
delete menu;
@@ -643,6 +680,40 @@ void VCSBaseEditorWidget::jumpToChangeFromDiff(QTextCursor cursor)
editor->gotoLine(chunkStart + lineCount);
}
+// cut out chunk and determine file name.
+DiffChunk VCSBaseEditorWidget::diffChunk(QTextCursor cursor) const
+{
+ QTC_ASSERT(d->m_parameters->type == DiffOutput, return DiffChunk(); )
+ DiffChunk rc;
+ // Search back for start of chunk.
+ QTextBlock block = cursor.block();
+ int chunkStart = 0;
+ for ( ; block.isValid() ; block = block.previous()) {
+ if (checkChunkLine(block.text(), &chunkStart)) {
+ break;
+ }
+ }
+ if (!chunkStart || !block.isValid())
+ return rc;
+ rc.fileName = fileNameFromDiffSpecification(block);
+ if (rc.fileName.isEmpty())
+ return rc;
+ // Concatenate chunk and convert
+ QString unicode = block.text();
+ for (block = block.next() ; block.isValid() ; block = block.next()) {
+ const QString line = block.text();
+ if (checkChunkLine(line, &chunkStart)) {
+ break;
+ } else {
+ unicode += line;
+ unicode += QLatin1Char('\n');
+ }
+ }
+ const QTextCodec *cd = textCodec();
+ rc.chunk = cd ? cd->fromUnicode(unicode) : unicode.toLocal8Bit();
+ return rc;
+}
+
void VCSBaseEditorWidget::setPlainTextData(const QByteArray &data)
{
if (data.size() > Core::EditorManager::maxTextFileSize()) {
@@ -901,6 +972,46 @@ QStringList VCSBaseEditorWidget::annotationPreviousVersions(const QString &) con
return QStringList();
}
+bool VCSBaseEditorWidget::isRevertDiffChunkEnabled() const
+{
+ return d->m_revertChunkEnabled;
+}
+
+void VCSBaseEditorWidget::setRevertDiffChunkEnabled(bool e)
+{
+ d->m_revertChunkEnabled = e;
+}
+
+bool VCSBaseEditorWidget::canRevertDiffChunk(const DiffChunk &dc) const
+{
+ if (!isRevertDiffChunkEnabled() || !dc.isValid())
+ return false;
+ const QFileInfo fi(dc.fileName);
+ // Default implementation using patch.exe relies on absolute paths.
+ return fi.isFile() && fi.isAbsolute() && fi.isWritable();
+}
+
+// Default implementation of revert: Revert a chunk by piping it into patch
+// with '-R', assuming we got absolute paths from the VCS plugins.
+bool VCSBaseEditorWidget::revertDiffChunk(const DiffChunk &dc) const
+{
+ return VCSBasePlugin::runPatch(dc.asPatch(), QString(), 0, true);
+}
+
+void VCSBaseEditorWidget::slotRevertDiffChunk()
+{
+ const QAction *a = qobject_cast<QAction *>(sender());
+ QTC_ASSERT(a, return ; )
+ const DiffChunk chunk = qvariant_cast<DiffChunk>(a->data());
+ if (QMessageBox::No == QMessageBox::question(this, tr("Revert Chunk"),
+ tr("Would you like to revert the chunk?"),
+ QMessageBox::Yes|QMessageBox::No))
+ return;
+
+ if (revertDiffChunk(chunk))
+ emit diffChunkReverted(chunk);
+}
+
} // namespace VCSBase
#include "vcsbaseeditor.moc"
diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h
index 296c81ae6e..8418a3a579 100644
--- a/src/plugins/vcsbase/vcsbaseeditor.h
+++ b/src/plugins/vcsbase/vcsbaseeditor.h
@@ -86,6 +86,16 @@ struct VCSBASE_EXPORT VCSBaseEditorParameters
const char *extension;
};
+class VCSBASE_EXPORT DiffChunk
+{
+public:
+ bool isValid() const;
+ QByteArray asPatch() const;
+
+ QString fileName;
+ QByteArray chunk;
+};
+
// Base class for editors showing version control system output
// of the type enumerated by EditorContentType.
// The source property should contain the file or directory the log
@@ -99,6 +109,7 @@ class VCSBASE_EXPORT VCSBaseEditorWidget : public TextEditor::BaseTextEditorWidg
Q_PROPERTY(QString annotateRevisionTextFormat READ annotateRevisionTextFormat WRITE setAnnotateRevisionTextFormat)
Q_PROPERTY(QString copyRevisionTextFormat READ copyRevisionTextFormat WRITE setCopyRevisionTextFormat)
Q_PROPERTY(bool isFileLogAnnotateEnabled READ isFileLogAnnotateEnabled WRITE setFileLogAnnotateEnabled)
+ Q_PROPERTY(bool revertDiffChunkEnabled READ isRevertDiffChunkEnabled WRITE setRevertDiffChunkEnabled)
Q_OBJECT
protected:
@@ -146,6 +157,10 @@ public:
QString diffBaseDirectory() const;
void setDiffBaseDirectory(const QString &d);
+ // Diff: Can revert?
+ bool isRevertDiffChunkEnabled() const;
+ void setRevertDiffChunkEnabled(bool e);
+
bool isModified() const;
EditorContentType contentType() const;
@@ -194,6 +209,7 @@ signals:
// for LogOutput/AnnotateOutput content types.
void describeRequested(const QString &source, const QString &change);
void annotateRevisionRequested(const QString &source, const QString &change, int lineNumber);
+ void diffChunkReverted(const VCSBase::DiffChunk &dc);
public slots:
// Convenience slot to set data read from stdout, will use the
@@ -220,6 +236,7 @@ private slots:
void slotDiffCursorPositionChanged();
void slotAnnotateRevision();
void slotCopyRevision();
+ void slotRevertDiffChunk();
protected:
/* A helper that can be used to locate a file in a diff in case it
@@ -227,6 +244,10 @@ protected:
* source and version control. */
QString findDiffFile(const QString &f, Core::IVersionControl *control = 0) const;
+ virtual bool canRevertDiffChunk(const DiffChunk &dc) const;
+ // Revert a patch chunk. Default implemenation uses patch.exe
+ virtual bool revertDiffChunk(const DiffChunk &dc) const;
+
private:
// Implement to return a set of change identifiers in
// annotation mode
@@ -242,6 +263,8 @@ private:
// Implement to return the previous version[s] of an annotation change
// for "Annotate previous version"
virtual QStringList annotationPreviousVersions(const QString &revision) const;
+ // cut out chunk and determine file name.
+ DiffChunk diffChunk(QTextCursor cursor) const;
void jumpToChangeFromDiff(QTextCursor cursor);
QAction *createDescribeAction(const QString &change);
@@ -253,4 +276,6 @@ private:
} // namespace VCSBase
+Q_DECLARE_METATYPE(VCSBase::DiffChunk)
+
#endif // VCSBASE_BASEEDITOR_H
diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp
index 359e02b868..24f28b8651 100644
--- a/src/plugins/vcsbase/vcsbaseplugin.cpp
+++ b/src/plugins/vcsbase/vcsbaseplugin.cpp
@@ -49,6 +49,7 @@
#include <projectexplorer/project.h>
#include <utils/qtcassert.h>
#include <utils/synchronousprocess.h>
+#include <utils/environment.h>
#include <QtCore/QDebug>
#include <QtCore/QDir>
@@ -883,6 +884,54 @@ Utils::SynchronousProcessResponse
return response;
}
+
+bool VCSBasePlugin::runPatch(const QByteArray &input, const QString &workingDirectory,
+ int strip, bool reverse)
+{
+ VCSBaseOutputWindow *ow = VCSBaseOutputWindow::instance();
+ const QString patch = Internal::VCSPlugin::instance()->settings().patchCommand;
+ if (patch.isEmpty()) {
+ ow->appendError(tr("There is no patch-command configured in the commone 'Version Control' settings."));
+ return false;
+ }
+
+ QProcess patchProcess;
+ if (!workingDirectory.isEmpty())
+ patchProcess.setWorkingDirectory(workingDirectory);
+ QStringList args(QLatin1String("-p") + QString::number(strip));
+ if (reverse)
+ args << QLatin1String("-R");
+ ow->appendCommand(QString(), patch, args);
+ patchProcess.start(patch, args);
+ if (!patchProcess.waitForStarted()) {
+ ow->appendError(tr("Unable to launch '%1': %2").arg(patch, patchProcess.errorString()));
+ return false;
+ }
+ patchProcess.write(input);
+ patchProcess.closeWriteChannel();
+ QByteArray stdOut;
+ QByteArray stdErr;
+ if (!Utils::SynchronousProcess::readDataFromProcess(patchProcess, 30000, &stdOut, &stdErr, true)) {
+ Utils::SynchronousProcess::stopProcess(patchProcess);
+ ow->appendError(tr("A timeout occurred running '%1'").arg(patch));
+ return false;
+
+ }
+ if (!stdOut.isEmpty())
+ ow->append(QString::fromLocal8Bit(stdOut));
+ if (!stdErr.isEmpty())
+ ow->append(QString::fromLocal8Bit(stdErr));
+
+ if (patchProcess.exitStatus() != QProcess::NormalExit) {
+ ow->appendError(tr("'%1' crashed.").arg(patch));
+ return false;
+ }
+ if (patchProcess.exitCode() != 0) {
+ ow->appendError(tr("'%1' failed (exit code %2).").arg(patchProcess.exitCode()));
+ return false;
+ }
+ return true;
+}
} // namespace VCSBase
#include "vcsbaseplugin.moc"
diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h
index 8a396763e0..f4fd165ace 100644
--- a/src/plugins/vcsbase/vcsbaseplugin.h
+++ b/src/plugins/vcsbase/vcsbaseplugin.h
@@ -218,6 +218,10 @@ public:
unsigned flags = 0,
QTextCodec *outputCodec = 0);
+ // Utility to run the 'patch' command
+ static bool runPatch(const QByteArray &input, const QString &workingDirectory = QString(),
+ int strip = 0, bool reverse = false);
+
public slots:
// Convenience slot for "Delete current file" action. Prompts to
// delete the file via VCSManager.