From 491a27163a9a843356a686ea405723608b10aa11 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Thu, 24 Mar 2011 15:44:39 +0100 Subject: [PATCH] VCS[git]: Add 'Revert this chunk' context menu option to diff view. Implement in git. Add infrastructure to revert single chhunks by using patch -R. Currently only implemented in git since only that has functionality to re-run diff. Rubber-stamped-by: hunger <tobias.hunger@nokia.com> --- src/plugins/git/gitclient.cpp | 4 + src/plugins/git/gitclient.h | 2 + src/plugins/vcsbase/commonsettingspage.cpp | 6 ++ src/plugins/vcsbase/commonsettingspage.ui | 56 ++++++---- src/plugins/vcsbase/commonvcssettings.cpp | 9 +- src/plugins/vcsbase/commonvcssettings.h | 2 + src/plugins/vcsbase/vcsbaseeditor.cpp | 115 ++++++++++++++++++++- src/plugins/vcsbase/vcsbaseeditor.h | 25 +++++ src/plugins/vcsbase/vcsbaseplugin.cpp | 49 +++++++++ src/plugins/vcsbase/vcsbaseplugin.h | 4 + 10 files changed, 251 insertions(+), 21 deletions(-) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 3ab49446615..1ed8d8de635 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 b6aef5f2da8..c1a67c52e91 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 6cdeb8b0a71..1e6f0d13b61 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 c15f9cd96f3..e4a8cdd6b8c 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 &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 <email> alias <email></string> </property> <property name="text"> - <string>User/alias configuration file:</string> + <string>User/&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 <email> alias <email></string> <string>A simple file containing lines with field names like "Reviewed-By:" which will be added below the submit editor.</string> </property> <property name="text"> - <string>User fields configuration file:</string> + <string>User &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 <email> alias <email></string> </property> </spacer> </item> + <item row="7" column="0"> + <widget class="QLabel" name="patchCommandLabel"> + <property name="text"> + <string>&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 <email> alias <email></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>&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 fdb9ec82479..172af681f21 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 f7e8aef9337..8f182e27e7f 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 69b7b24a18a..4e5da7bf9d0 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 296c81ae6e9..8418a3a5794 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 359e02b8684..24f28b86510 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 8a396763e0f..f4fd165ace3 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. -- GitLab