Use QtcProcess in MergeTool

Change-Id: I9d08c455404a75a29874883dbdc4855a183a58e3
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Jarek Kobus
2021-11-02 18:03:46 +01:00
parent 4d4abc8578
commit 50586c7bb8
4 changed files with 75 additions and 75 deletions

View File

@@ -1971,9 +1971,9 @@ void GitPlugin::emitFilesChanged(const QStringList &l)
emit dd->filesChanged(l); emit dd->filesChanged(l);
} }
void GitPlugin::emitRepositoryChanged(const QString &r) void GitPlugin::emitRepositoryChanged(const FilePath &r)
{ {
emit dd->repositoryChanged(FilePath::fromString(r)); emit dd->repositoryChanged(r);
} }
void GitPlugin::startRebaseFromCommit(const FilePath &workingDirectory, const QString &commit) void GitPlugin::startRebaseFromCommit(const FilePath &workingDirectory, const QString &commit)

View File

@@ -66,7 +66,7 @@ public:
static bool isCommitEditorOpen(); static bool isCommitEditorOpen();
static void emitFilesChanged(const QStringList &); static void emitFilesChanged(const QStringList &);
static void emitRepositoryChanged(const QString &); static void emitRepositoryChanged(const Utils::FilePath &);
static void startRebaseFromCommit(const Utils::FilePath &workingDirectory, const QString &commit); static void startRebaseFromCommit(const Utils::FilePath &workingDirectory, const QString &commit);
static void manageRemotes(); static void manageRemotes();
static void initRepository(); static void initRepository();

View File

@@ -29,11 +29,12 @@
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <vcsbase/vcsoutputwindow.h>
#include <coreplugin/messagebox.h> #include <coreplugin/messagebox.h>
#include <utils/commandline.h>
#include <utils/qtcprocess.h>
#include <vcsbase/vcsoutputwindow.h>
#include <QMessageBox> #include <QMessageBox>
#include <QProcess>
#include <QPushButton> #include <QPushButton>
using namespace Utils; using namespace Utils;
@@ -54,20 +55,21 @@ bool MergeTool::start(const FilePath &workingDirectory, const QStringList &files
{ {
QStringList arguments; QStringList arguments;
arguments << "mergetool" << "-y" << files; arguments << "mergetool" << "-y" << files;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); Environment env = Environment::systemEnvironment();
env.insert("LANG", "C"); env.set("LANG", "C");
env.insert("LANGUAGE", "C"); env.set("LANGUAGE", "C");
m_process = new QProcess(this); m_process = new QtcProcess(ProcessMode::Writer);
m_process->setWorkingDirectory(workingDirectory.toString()); m_process->setWorkingDirectory(workingDirectory.toString());
m_process->setProcessEnvironment(env); m_process->setEnvironment(env);
m_process->setProcessChannelMode(QProcess::MergedChannels); m_process->setProcessChannelMode(QProcess::MergedChannels);
const Utils::FilePath binary = GitClient::instance()->vcsBinary(); const Utils::FilePath binary = GitClient::instance()->vcsBinary();
VcsOutputWindow::appendCommand(workingDirectory, {binary, arguments}); const CommandLine cmd = {binary, arguments};
m_process->start(binary.toString(), arguments); VcsOutputWindow::appendCommand(workingDirectory, cmd);
m_process->setCommand(cmd);
m_process->start();
if (m_process->waitForStarted()) { if (m_process->waitForStarted()) {
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), connect(m_process, &QtcProcess::finished, this, &MergeTool::done);
this, &MergeTool::done); connect(m_process, &QtcProcess::readyReadStandardOutput, this, &MergeTool::readData);
connect(m_process, &QIODevice::readyRead, this, &MergeTool::readData);
} else { } else {
delete m_process; delete m_process;
m_process = nullptr; m_process = nullptr;
@@ -76,9 +78,9 @@ bool MergeTool::start(const FilePath &workingDirectory, const QStringList &files
return true; return true;
} }
MergeTool::FileState MergeTool::parseStatus(const QByteArray &line, QString &extraInfo) MergeTool::FileState MergeTool::parseStatus(const QString &line, QString &extraInfo)
{ {
QByteArray state = line.trimmed(); QString state = line.trimmed();
// " {local}: modified file" // " {local}: modified file"
// " {remote}: deleted" // " {remote}: deleted"
if (!state.isEmpty()) { if (!state.isEmpty()) {
@@ -89,16 +91,16 @@ MergeTool::FileState MergeTool::parseStatus(const QByteArray &line, QString &ext
return ModifiedState; return ModifiedState;
if (state.startsWith("created")) if (state.startsWith("created"))
return CreatedState; return CreatedState;
QByteArray submodulePrefix("submodule commit "); const QString submodulePrefix("submodule commit ");
// " {local}: submodule commit <hash>" // " {local}: submodule commit <hash>"
if (state.startsWith(submodulePrefix)) { if (state.startsWith(submodulePrefix)) {
extraInfo = QString::fromLocal8Bit(state.mid(submodulePrefix.size())); extraInfo = state.mid(submodulePrefix.size());
return SubmoduleState; return SubmoduleState;
} }
// " {local}: a symbolic link -> 'foo.cpp'" // " {local}: a symbolic link -> 'foo.cpp'"
QByteArray symlinkPrefix("a symbolic link -> '"); const QString symlinkPrefix("a symbolic link -> '");
if (state.startsWith(symlinkPrefix)) { if (state.startsWith(symlinkPrefix)) {
extraInfo = QString::fromLocal8Bit(state.mid(symlinkPrefix.size())); extraInfo = state.mid(symlinkPrefix.size());
extraInfo.chop(1); // remove last quote extraInfo.chop(1); // remove last quote
return SymbolicLinkState; return SymbolicLinkState;
} }
@@ -106,7 +108,7 @@ MergeTool::FileState MergeTool::parseStatus(const QByteArray &line, QString &ext
return UnknownState; return UnknownState;
} }
static MergeTool::MergeType mergeType(const QByteArray &type) static MergeTool::MergeType mergeType(const QString &type)
{ {
if (type == "Normal") if (type == "Normal")
return MergeTool::NormalMerge; return MergeTool::NormalMerge;
@@ -206,57 +208,52 @@ void MergeTool::prompt(const QString &title, const QString &question)
void MergeTool::readData() void MergeTool::readData()
{ {
bool waitForFurtherInput = false; QString newData = QString::fromLocal8Bit(m_process->readAllStandardOutput());
while (m_process->bytesAvailable()) { newData.remove('\r');
const bool hasLine = m_process->canReadLine(); VcsOutputWindow::append(newData);
const QByteArray line = hasLine ? m_process->readLine() : m_process->readAllStandardOutput(); QString data = m_unfinishedLine + newData;
VcsOutputWindow::append(QString::fromLocal8Bit(line)); m_unfinishedLine.clear();
m_line += line; while (const int index = data.indexOf('\n') != -1) {
// {Normal|Deleted|Submodule|Symbolic link} merge conflict for 'foo.cpp' const QString line = data.left(index + 1);
const int index = m_line.indexOf(" merge conflict for "); readLine(line);
if (index != -1) { data = data.mid(index + 1);
m_mergeType = mergeType(m_line.left(index)); }
int quote = m_line.indexOf('\''); if (data.startsWith("Was the merge successful")) {
m_fileName = QString::fromLocal8Bit(m_line.mid(quote + 1, m_line.lastIndexOf('\'') - quote - 1)); prompt(tr("Unchanged File"), tr("Was the merge successful?"));
m_line.clear(); } else if (data.startsWith("Continue merging")) {
} else if (m_line.startsWith(" {local}")) { prompt(tr("Continue Merging"), tr("Continue merging other unresolved paths?"));
waitForFurtherInput = !hasLine; } else if (data.startsWith("Hit return")) {
if (waitForFurtherInput) QMessageBox::warning(
continue; Core::ICore::dialogParent(), tr("Merge Tool"),
m_localState = parseStatus(m_line, m_localInfo); QString("<html><body><p>%1</p>\n<p>%2</p></body></html>").arg(
m_line.clear(); tr("Merge tool is not configured."),
} else if (m_line.startsWith(" {remote}")) { tr("Run git config --global merge.tool &lt;tool&gt; "
waitForFurtherInput = !hasLine; "to configure it, then try again.")));
if (waitForFurtherInput) m_process->kill();
continue; } else {
m_remoteState = parseStatus(m_line, m_remoteInfo); m_unfinishedLine = data;
m_line.clear(); }
chooseAction(); }
} else if (m_line.startsWith("Was the merge successful")) {
prompt(tr("Unchanged File"), tr("Was the merge successful?")); void MergeTool::readLine(const QString &line)
} else if (m_line.startsWith("Continue merging")) { {
prompt(tr("Continue Merging"), tr("Continue merging other unresolved paths?")); // {Normal|Deleted|Submodule|Symbolic link} merge conflict for 'foo.cpp'
} else if (m_line.startsWith("Hit return")) { const int index = line.indexOf(" merge conflict for ");
QMessageBox::warning( if (index != -1) {
Core::ICore::dialogParent(), tr("Merge Tool"), m_mergeType = mergeType(line.left(index));
QString("<html><body><p>%1</p>\n<p>%2</p></body></html>").arg( const int quote = line.indexOf('\'');
tr("Merge tool is not configured."), m_fileName = line.mid(quote + 1, line.lastIndexOf('\'') - quote - 1);
tr("Run git config --global merge.tool &lt;tool&gt; " } else if (line.startsWith(" {local}")) {
"to configure it, then try again."))); m_localState = parseStatus(line, m_localInfo);
m_process->kill(); } else if (line.startsWith(" {remote}")) {
} else if (m_line.endsWith('\n')) { m_remoteState = parseStatus(line, m_remoteInfo);
// Skip unidentified lines chooseAction();
m_line.clear();
}
} }
if (!waitForFurtherInput)
m_line.clear();
} }
void MergeTool::done() void MergeTool::done()
{ {
const QString workingDirectory = m_process->workingDirectory(); const FilePath workingDirectory = m_process->workingDirectory();
int exitCode = m_process->exitCode(); int exitCode = m_process->exitCode();
if (!exitCode) { if (!exitCode) {
VcsOutputWindow::appendMessage(tr("Merge tool process finished successfully.")); VcsOutputWindow::appendMessage(tr("Merge tool process finished successfully."));
@@ -264,7 +261,7 @@ void MergeTool::done()
VcsOutputWindow::appendError(tr("Merge tool process terminated with exit code %1") VcsOutputWindow::appendError(tr("Merge tool process terminated with exit code %1")
.arg(exitCode)); .arg(exitCode));
} }
GitClient::instance()->continueCommandIfNeeded(FilePath::fromString(workingDirectory), exitCode == 0); GitClient::instance()->continueCommandIfNeeded(workingDirectory, exitCode == 0);
GitPlugin::emitRepositoryChanged(workingDirectory); GitPlugin::emitRepositoryChanged(workingDirectory);
deleteLater(); deleteLater();
} }
@@ -272,7 +269,6 @@ void MergeTool::done()
void MergeTool::write(const QByteArray &bytes) void MergeTool::write(const QByteArray &bytes)
{ {
m_process->write(bytes); m_process->write(bytes);
m_process->waitForBytesWritten();
VcsOutputWindow::append(QString::fromLocal8Bit(bytes)); VcsOutputWindow::append(QString::fromLocal8Bit(bytes));
} }

View File

@@ -30,10 +30,13 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QMessageBox; class QMessageBox;
class QProcess;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace Utils { class FilePath; } namespace Utils
{
class FilePath;
class QtcProcess;
}
namespace Git { namespace Git {
namespace Internal { namespace Internal {
@@ -66,23 +69,24 @@ public:
private: private:
void prompt(const QString &title, const QString &question); void prompt(const QString &title, const QString &question);
void readData(); void readData();
void readLine(const QString &line);
void done(); void done();
void write(const QByteArray &bytes); void write(const QByteArray &bytes);
FileState parseStatus(const QByteArray &line, QString &extraInfo); FileState parseStatus(const QString &line, QString &extraInfo);
QString mergeTypeName(); QString mergeTypeName();
QString stateName(FileState state, const QString &extraInfo); QString stateName(FileState state, const QString &extraInfo);
void chooseAction(); void chooseAction();
void addButton(QMessageBox *msgBox, const QString &text, char key); void addButton(QMessageBox *msgBox, const QString &text, char key);
QProcess *m_process = nullptr; Utils::QtcProcess *m_process = nullptr;
MergeType m_mergeType = NormalMerge; MergeType m_mergeType = NormalMerge;
QString m_fileName; QString m_fileName;
FileState m_localState = UnknownState; FileState m_localState = UnknownState;
QString m_localInfo; QString m_localInfo;
FileState m_remoteState = UnknownState; FileState m_remoteState = UnknownState;
QString m_remoteInfo; QString m_remoteInfo;
QByteArray m_line; QString m_unfinishedLine;
bool m_merging = false; bool m_merging = false;
}; };