Commit 48aefde7 authored by jkobus's avatar jkobus Committed by Jarek Kobus

Move patch command out of VcsPlugin

It will be needed soon inside DiffEditor plugin.
Move "Patch command" setting out of Version Control | General
into Environment | General | System.

Introduce PatchTool class, which hold the patch command
setting and a method for applying patches (runPatch() - moved
from VcsBasePlugin).

Change-Id: I9de94358ccd5c6e31ac2beefc27305c5111d67bb
Reviewed-by: default avatarJarek Kobus <jaroslaw.kobus@digia.com>
parent ba29d9f9
......@@ -97,7 +97,8 @@ SOURCES += mainwindow.cpp \
iversioncontrol.cpp \
dialogs/addtovcsdialog.cpp \
icorelistener.cpp \
ioutputpane.cpp
ioutputpane.cpp \
patchtool.cpp
HEADERS += mainwindow.h \
editmode.h \
......@@ -194,7 +195,8 @@ HEADERS += mainwindow.h \
textdocument.h \
documentmanager.h \
removefiledialog.h \
dialogs/addtovcsdialog.h
dialogs/addtovcsdialog.h \
patchtool.h
FORMS += dialogs/newdialog.ui \
dialogs/saveitemsdialog.ui \
......
......@@ -75,6 +75,7 @@ QtcPlugin {
"outputpane.cpp", "outputpane.h",
"outputpanemanager.cpp", "outputpanemanager.h",
"outputwindow.cpp", "outputwindow.h",
"patchtool.cpp" "patchtool.h"
"plugindialog.cpp", "plugindialog.h",
"removefiledialog.cpp", "removefiledialog.h", "removefiledialog.ui",
"rightpane.cpp", "rightpane.h",
......
......@@ -31,6 +31,8 @@
#include "coreconstants.h"
#include "icore.h"
#include "infobar.h"
#include "patchtool.h"
#include "vcsmanager.h"
#include "editormanager/editormanager.h"
#include <utils/checkablemessagebox.h>
......@@ -38,6 +40,7 @@
#include <utils/hostosinfo.h>
#include <utils/stylehelper.h>
#include <utils/unixutils.h>
#include <utils/environment.h>
#include <QMessageBox>
......@@ -136,6 +139,12 @@ QWidget *GeneralSettings::widget()
m_page->helpExternalFileBrowserButton->hide();
}
const QString patchToolTip = tr("Command used for reverting diff chunks.");
m_page->patchCommandLabel->setToolTip(patchToolTip);
m_page->patchChooser->setToolTip(patchToolTip);
m_page->patchChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_page->patchChooser->setHistoryCompleter(QLatin1String("General.PatchCommand.History"));
m_page->patchChooser->setPath(Core::PatchTool::patchCommand());
m_page->autoSaveCheckBox->setChecked(EditorManager::autoSaveEnabled());
m_page->autoSaveInterval->setValue(EditorManager::autoSaveInterval());
m_page->resetWarningsButton->setEnabled(Core::InfoBar::anyGloballySuppressed()
......@@ -153,6 +162,11 @@ QWidget *GeneralSettings::widget()
this, SLOT(showHelpForFileBrowser()));
}
}
updatePath();
connect(Core::VcsManager::instance(), SIGNAL(configurationChanged(const IVersionControl*)),
this, SLOT(updatePath()));
}
return m_widget;
}
......@@ -174,6 +188,7 @@ void GeneralSettings::apply()
m_page->externalFileBrowserEdit->text());
}
}
Core::PatchTool::setPatchCommand(m_page->patchChooser->path());
EditorManager::setAutoSaveEnabled(m_page->autoSaveCheckBox->isChecked());
EditorManager::setAutoSaveInterval(m_page->autoSaveInterval->value());
}
......@@ -211,6 +226,13 @@ void GeneralSettings::resetFileBrowser()
m_page->externalFileBrowserEdit->setText(UnixUtils::defaultFileBrowser());
}
void GeneralSettings::updatePath()
{
Utils::Environment env = Utils::Environment::systemEnvironment();
QStringList toAdd = Core::VcsManager::additionalToolsPath();
env.appendOrSetPath(toAdd.join(QString(Utils::HostOsInfo::pathListSeparator())));
m_page->patchChooser->setEnvironment(env);
}
void GeneralSettings::variableHelpDialogCreator(const QString &helpText)
{
......
......@@ -60,6 +60,7 @@ private slots:
void showHelpForFileBrowser();
void resetFileBrowser();
void resetTerminal();
void updatePath();
private:
void variableHelpDialogCreator(const QString &helpText);
......
......@@ -181,7 +181,17 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<item row="2" column="0">
<widget class="QLabel" name="patchCommandLabel">
<property name="text">
<string>Patch command:</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="Utils::PathChooser" name="patchChooser" native="true"/>
</item>
<item row="3" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="modifiedLabel">
......@@ -227,7 +237,7 @@
</item>
</layout>
</item>
<item row="3" column="0" colspan="4">
<item row="4" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QCheckBox" name="autoSaveCheckBox">
......@@ -314,6 +324,16 @@
<extends>QToolButton</extends>
<header location="global">utils/qtcolorbutton.h</header>
</customwidget>
<customwidget>
<class>Utils::PathChooser</class>
<extends>QWidget</extends>
<header location="global">utils/pathchooser.h</header>
<container>1</container>
<slots>
<signal>editingFinished()</signal>
<signal>browsingFinished()</signal>
</slots>
</customwidget>
</customwidgets>
<resources>
<include location="core.qrc"/>
......
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "patchtool.h"
#include "messagemanager.h"
#include "icore.h"
#include <utils/synchronousprocess.h>
#include <QProcess>
#include <QDir>
#include <QApplication>
static const char settingsGroupC[] = "General";
static const char legacySettingsGroupC[] = "VCS";
static const char patchCommandKeyC[] = "PatchCommand";
static const char patchCommandDefaultC[] = "patch";
namespace Core {
static QString readLegacyCommand()
{
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(legacySettingsGroupC));
const bool legacyExists = s->contains(QLatin1String(patchCommandKeyC));
const QString legacyCommand = s->value(QLatin1String(patchCommandKeyC), QLatin1String(patchCommandDefaultC)).toString();
if (legacyExists)
s->remove(QLatin1String(patchCommandKeyC));
s->endGroup();
if (legacyExists && legacyCommand != QLatin1String(patchCommandDefaultC))
PatchTool::setPatchCommand(legacyCommand);
return legacyCommand;
}
QString PatchTool::patchCommand()
{
QSettings *s = Core::ICore::settings();
const QString defaultCommand = readLegacyCommand(); // replace it with QLatin1String(patchCommandDefaultC) when dropping legacy stuff
s->beginGroup(QLatin1String(settingsGroupC));
const QString command = s->value(QLatin1String(patchCommandKeyC), defaultCommand).toString();
s->endGroup();
return command;
}
void PatchTool::setPatchCommand(const QString &newCommand)
{
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(patchCommandKeyC), newCommand);
s->endGroup();
}
bool PatchTool::runPatch(const QByteArray &input, const QString &workingDirectory,
int strip, bool reverse)
{
const QString patch = patchCommand();
if (patch.isEmpty()) {
MessageManager::write(QApplication::translate("Core::PatchTool", "There is no patch-command configured in the general \"Environment\" settings."));
return false;
}
QProcess patchProcess;
if (!workingDirectory.isEmpty())
patchProcess.setWorkingDirectory(workingDirectory);
QStringList args(QLatin1String("-p") + QString::number(strip));
if (reverse)
args << QLatin1String("-R");
MessageManager::write(QApplication::translate("Core::PatchTool", "Executing in %1: %2 %3").
arg(QDir::toNativeSeparators(workingDirectory),
QDir::toNativeSeparators(patch), args.join(QLatin1String(" "))));
patchProcess.start(patch, args);
if (!patchProcess.waitForStarted()) {
MessageManager::write(QApplication::translate("Core::PatchTool", "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);
MessageManager::write(QApplication::translate("Core::PatchTool", "A timeout occurred running \"%1\"").arg(patch));
return false;
}
if (!stdOut.isEmpty())
MessageManager::write(QString::fromLocal8Bit(stdOut));
if (!stdErr.isEmpty())
MessageManager::write(QString::fromLocal8Bit(stdErr));
if (patchProcess.exitStatus() != QProcess::NormalExit) {
MessageManager::write(QApplication::translate("Core::PatchTool", "\"%1\" crashed.").arg(patch));
return false;
}
if (patchProcess.exitCode() != 0) {
MessageManager::write(QApplication::translate("Core::PatchTool", "\"%1\" failed (exit code %2).").arg(patch).arg(patchProcess.exitCode()));
return false;
}
return true;
}
} // namespace Core
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CORE_PATCHTOOL_H
#define CORE_PATCHTOOL_H
#include "coreplugin/core_global.h"
#include <QString>
namespace Core {
class CORE_EXPORT PatchTool
{
public:
static QString patchCommand();
static void setPatchCommand(const QString &newCommand);
// Utility to run the 'patch' command
static bool runPatch(const QByteArray &input, const QString &workingDirectory = QString(),
int strip = 0, bool reverse = false);
};
} // namespace Core
#endif // CORE_PATCHTOOL_H
......@@ -58,11 +58,6 @@ CommonSettingsWidget::CommonSettingsWidget(QWidget *parent) :
m_ui->nickNameMailMapChooser->setHistoryCompleter(QLatin1String("Vcs.NickMap.History"));
m_ui->sshPromptChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_ui->sshPromptChooser->setHistoryCompleter(QLatin1String("Vcs.SshPrompt.History"));
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);
m_ui->patchChooser->setHistoryCompleter(QLatin1String("Vcs.PatchCommand.History"));
updatePath();
......@@ -84,7 +79,6 @@ 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;
}
......@@ -96,21 +90,6 @@ 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
{
const QChar blank = QLatin1Char(' ');
QString rc = m_ui->lineWrapCheckBox->text()
+ blank + m_ui->submitMessageCheckScriptLabel->text()
+ blank + m_ui->nickNameMailMapLabel->text()
+ blank + m_ui->nickNameFieldsFileLabel->text()
+ blank + m_ui->sshPromptLabel->text()
+ blank + m_ui->patchCommandLabel->text()
;
rc.remove(QLatin1Char('&')); // Strip buddy markers.
return rc;
}
void CommonSettingsWidget::updatePath()
......@@ -118,7 +97,6 @@ void CommonSettingsWidget::updatePath()
Utils::Environment env = Utils::Environment::systemEnvironment();
QStringList toAdd = Core::VcsManager::additionalToolsPath();
env.appendOrSetPath(toAdd.join(QString(Utils::HostOsInfo::pathListSeparator())));
m_ui->patchChooser->setEnvironment(env);
m_ui->sshPromptChooser->setEnvironment(env);
}
......
......@@ -53,8 +53,6 @@ public:
CommonVcsSettings settings() const;
void setSettings(const CommonVcsSettings &s);
QString searchKeyWordMatchString() const;
private slots:
void updatePath();
......
......@@ -119,19 +119,6 @@ should a repository require SSH-authentication (see documentation on SSH and the
<item row="5" column="1">
<widget class="Utils::PathChooser" name="sshPromptChooser" native="true"/>
</item>
<item row="6" 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="6" column="1">
<widget class="Utils::PathChooser" name="patchChooser" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
......
......@@ -41,8 +41,6 @@ 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;
......@@ -63,7 +61,6 @@ namespace Internal {
CommonVcsSettings::CommonVcsSettings() :
sshPasswordPrompt(sshPasswordPromptDefault()),
patchCommand(QLatin1String(patchCommandDefaultC)),
lineWrap(lineWrapDefault),
lineWrapWidth(lineWrapWidthDefault)
{
......@@ -77,7 +74,6 @@ 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);
......@@ -95,7 +91,6 @@ 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,8 +101,7 @@ bool CommonVcsSettings::equals(const CommonVcsSettings &rhs) const
&& nickNameMailMap == rhs.nickNameMailMap
&& nickNameFieldListFile == rhs.nickNameFieldListFile
&& submitMessageCheckScript == rhs.submitMessageCheckScript
&& sshPasswordPrompt == rhs.sshPasswordPrompt
&& patchCommand == rhs.patchCommand;
&& sshPasswordPrompt == rhs.sshPasswordPrompt;
}
QDebug operator<<(QDebug d,const CommonVcsSettings& s)
......@@ -118,7 +112,6 @@ QDebug operator<<(QDebug d,const CommonVcsSettings& s)
<< "' nickNameFieldListFile='" << s.nickNameFieldListFile
<< "'submitMessageCheckScript='" << s.submitMessageCheckScript
<< "'sshPasswordPrompt='" << s.sshPasswordPrompt
<< "'patchCommand='" << s.patchCommand
<< "'\n";
return d;
}
......
......@@ -54,8 +54,6 @@ public:
// Executable run to graphically prompt for a SSH-password.
QString sshPasswordPrompt;
QString patchCommand;
bool lineWrap;
int lineWrapWidth;
......
......@@ -36,6 +36,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/patchtool.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/editorconfiguration.h>
#include <projectexplorer/projectexplorer.h>
......@@ -1449,7 +1450,7 @@ bool VcsBaseEditorWidget::canApplyDiffChunk(const DiffChunk &dc) const
// (passing '-R' for revert), assuming we got absolute paths from the VCS plugins.
bool VcsBaseEditorWidget::applyDiffChunk(const DiffChunk &dc, bool revert) const
{
return VcsBasePlugin::runPatch(dc.asPatch(d->m_workingDirectory),
return Core::PatchTool::runPatch(dc.asPatch(d->m_workingDirectory),
d->m_workingDirectory, 0, revert);
}
......
......@@ -784,54 +784,6 @@ SynchronousProcessResponse VcsBasePlugin::runVcs(const QString &workingDir,
return command.runVcs(arguments, timeOutMS);
}
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 common '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(workingDirectory, 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 (!SynchronousProcess::readDataFromProcess(patchProcess, 30000, &stdOut, &stdErr, true)) {
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->appendError(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(patch).arg(patchProcess.exitCode()));
return false;
}
return true;
}
} // namespace VcsBase
#include "vcsbaseplugin.moc"
......@@ -187,10 +187,6 @@ public:
QTextCodec *outputCodec = 0,
const QProcessEnvironment &env = QProcessEnvironment());
// 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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment