forked from qt-creator/qt-creator
VcsBase: Introduce vcsExecWithHandler()
Before, vcsExec() returned already started VcsCommand. Later, callers of vcsExec() were establishing connections to the retured VcsCommand::done() signal. However, when process fails to start (e.g. because of non-existing executable), the done() signal may be emitted synchonously from inside VcsCommand::start(). In this scenario callers of VcsCommand could miss the emission of done() signal and connect to already finished command. Instead, provide a vcsExecWithHandler() function which takes a handler to be called when command finished. In addition it takes the context object, too. Don't return VcsCommand from vcsExec() anymore. Change-Id: I2fb5fbe5d27632ea039c650d37e5d7d1b60cebc0 Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
@@ -593,15 +593,17 @@ void BranchModel::removeTag(const QModelIndex &idx)
|
|||||||
removeNode(idx);
|
removeNode(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
VcsCommand *BranchModel::checkoutBranch(const QModelIndex &idx)
|
void BranchModel::checkoutBranch(const QModelIndex &idx, const QObject *context,
|
||||||
|
const CommandHandler &handler)
|
||||||
{
|
{
|
||||||
QString branch = fullName(idx, !isLocal(idx));
|
const QString branch = fullName(idx, !isLocal(idx));
|
||||||
if (branch.isEmpty())
|
if (branch.isEmpty())
|
||||||
return nullptr;
|
return;
|
||||||
|
|
||||||
// No StashGuard since this function for now is only used with clean working dir.
|
// No StashGuard since this function for now is only used with clean working dir.
|
||||||
// If it is ever used from another place, please add StashGuard here
|
// If it is ever used from another place, please add StashGuard here
|
||||||
return d->client->checkout(d->workingDirectory, branch, GitClient::StashMode::NoStash);
|
d->client->checkout(d->workingDirectory, branch, GitClient::StashMode::NoStash,
|
||||||
|
context, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BranchModel::branchIsMerged(const QModelIndex &idx)
|
bool BranchModel::branchIsMerged(const QModelIndex &idx)
|
||||||
|
@@ -9,7 +9,9 @@
|
|||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace VcsBase { class VcsCommand; }
|
namespace VcsBase {
|
||||||
|
class CommandResult;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Git::Internal {
|
namespace Git::Internal {
|
||||||
|
|
||||||
@@ -51,7 +53,8 @@ public:
|
|||||||
|
|
||||||
void removeBranch(const QModelIndex &idx);
|
void removeBranch(const QModelIndex &idx);
|
||||||
void removeTag(const QModelIndex &idx);
|
void removeTag(const QModelIndex &idx);
|
||||||
VcsBase::VcsCommand *checkoutBranch(const QModelIndex &idx);
|
void checkoutBranch(const QModelIndex &idx, const QObject *context = nullptr,
|
||||||
|
const std::function<void(const VcsBase::CommandResult &)> &handler = {});
|
||||||
bool branchIsMerged(const QModelIndex &idx);
|
bool branchIsMerged(const QModelIndex &idx);
|
||||||
QModelIndex addBranch(const QString &name, bool track, const QModelIndex &trackedBranch);
|
QModelIndex addBranch(const QString &name, bool track, const QModelIndex &trackedBranch);
|
||||||
void setRemoteTracking(const QModelIndex &trackingIndex);
|
void setRemoteTracking(const QModelIndex &trackingIndex);
|
||||||
|
@@ -416,12 +416,9 @@ bool BranchView::checkout()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
VcsCommand *command = m_model->checkoutBranch(selected);
|
|
||||||
const bool moveChanges = branchCheckoutDialog.moveLocalChangesToNextBranch();
|
const bool moveChanges = branchCheckoutDialog.moveLocalChangesToNextBranch();
|
||||||
const bool popStash = branchCheckoutDialog.popStashOfNextBranch();
|
const bool popStash = branchCheckoutDialog.popStashOfNextBranch();
|
||||||
if (command && (moveChanges || popStash)) {
|
const auto commandHandler = [=](const CommandResult &) {
|
||||||
connect(command, &VcsCommand::done,
|
|
||||||
this, [this, client, popMessageStart, moveChanges, popStash] {
|
|
||||||
if (moveChanges) {
|
if (moveChanges) {
|
||||||
client->endStashScope(m_repository);
|
client->endStashScope(m_repository);
|
||||||
} else if (popStash) {
|
} else if (popStash) {
|
||||||
@@ -436,8 +433,8 @@ bool BranchView::checkout()
|
|||||||
}
|
}
|
||||||
client->synchronousStashRestore(m_repository, stashName, true);
|
client->synchronousStashRestore(m_repository, stashName, true);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
m_model->checkoutBranch(selected, this, commandHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (QTC_GUARD(m_branchView))
|
if (QTC_GUARD(m_branchView))
|
||||||
|
@@ -317,9 +317,7 @@ void GitBaseDiffEditorController::updateBranchList()
|
|||||||
if (revision.isEmpty())
|
if (revision.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VcsCommand *command = m_instance->vcsExec(baseDirectory(),
|
const auto commandHandler = [this](const CommandResult &result) {
|
||||||
{"branch", noColorOption, "-a", "--contains", revision});
|
|
||||||
connect(command, &VcsCommand::done, this, [this, command] {
|
|
||||||
const QString remotePrefix = "remotes/";
|
const QString remotePrefix = "remotes/";
|
||||||
const QString localPrefix = "<Local>";
|
const QString localPrefix = "<Local>";
|
||||||
const int prefixLength = remotePrefix.length();
|
const int prefixLength = remotePrefix.length();
|
||||||
@@ -327,7 +325,7 @@ void GitBaseDiffEditorController::updateBranchList()
|
|||||||
QStringList branches;
|
QStringList branches;
|
||||||
QString previousRemote = localPrefix;
|
QString previousRemote = localPrefix;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (const QString &branch : command->cleanedStdOut().split('\n')) {
|
for (const QString &branch : result.cleanedStdOut().split('\n')) {
|
||||||
const QString b = branch.mid(2).trimmed();
|
const QString b = branch.mid(2).trimmed();
|
||||||
if (b.isEmpty())
|
if (b.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
@@ -356,7 +354,10 @@ void GitBaseDiffEditorController::updateBranchList()
|
|||||||
QString newDescription = description();
|
QString newDescription = description();
|
||||||
newDescription.replace(Constants::EXPAND_BRANCHES, branchList);
|
newDescription.replace(Constants::EXPAND_BRANCHES, branchList);
|
||||||
setDescription(newDescription);
|
setDescription(newDescription);
|
||||||
});
|
};
|
||||||
|
m_instance->vcsExecWithHandler(baseDirectory(),
|
||||||
|
{"branch", noColorOption, "-a", "--contains", revision},
|
||||||
|
this, commandHandler, RunFlags::None, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
@@ -734,7 +735,7 @@ public:
|
|||||||
|
|
||||||
static void handleResponse(const VcsBase::CommandResult &result,
|
static void handleResponse(const VcsBase::CommandResult &result,
|
||||||
const FilePath &workingDirectory,
|
const FilePath &workingDirectory,
|
||||||
const QString &abortCommand)
|
const QString &abortCommand = {})
|
||||||
{
|
{
|
||||||
const bool success = result.result() == ProcessResult::FinishedWithSuccess;
|
const bool success = result.result() == ProcessResult::FinishedWithSuccess;
|
||||||
const QString stdOutData = success ? QString() : result.cleanedStdOut();
|
const QString stdOutData = success ? QString() : result.cleanedStdOut();
|
||||||
@@ -1107,9 +1108,9 @@ void GitClient::merge(const FilePath &workingDirectory, const QStringList &unmer
|
|||||||
void GitClient::status(const FilePath &workingDirectory) const
|
void GitClient::status(const FilePath &workingDirectory) const
|
||||||
{
|
{
|
||||||
VcsOutputWindow::setRepository(workingDirectory);
|
VcsOutputWindow::setRepository(workingDirectory);
|
||||||
VcsCommand *command = vcsExec(workingDirectory, {"status", "-u"}, nullptr, true);
|
vcsExecWithHandler(workingDirectory, {"status", "-u"}, this, [](const CommandResult &) {
|
||||||
connect(command, &VcsCommand::done,
|
VcsOutputWindow::instance()->clearRepository();
|
||||||
VcsOutputWindow::instance(), &VcsOutputWindow::clearRepository);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static QStringList normalLogArguments()
|
static QStringList normalLogArguments()
|
||||||
@@ -1345,22 +1346,23 @@ VcsBaseEditorWidget *GitClient::annotate(
|
|||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
VcsCommand *GitClient::checkout(const FilePath &workingDirectory, const QString &ref,
|
void GitClient::checkout(const FilePath &workingDirectory, const QString &ref, StashMode stashMode,
|
||||||
StashMode stashMode)
|
const QObject *context, const VcsBase::CommandHandler &handler)
|
||||||
{
|
{
|
||||||
if (stashMode == StashMode::TryStash && !beginStashScope(workingDirectory, "Checkout"))
|
if (stashMode == StashMode::TryStash && !beginStashScope(workingDirectory, "Checkout"))
|
||||||
return nullptr;
|
return;
|
||||||
QStringList arguments = setupCheckoutArguments(workingDirectory, ref);
|
|
||||||
VcsCommand *command = vcsExec(
|
const QStringList arguments = setupCheckoutArguments(workingDirectory, ref);
|
||||||
workingDirectory, arguments, nullptr, true,
|
const auto commandHandler = [=](const CommandResult &result) {
|
||||||
RunFlags::ExpectRepoChanges | RunFlags::ShowSuccessMessage);
|
|
||||||
connect(command, &VcsCommand::done, this, [this, workingDirectory, stashMode, command] {
|
|
||||||
if (stashMode == StashMode::TryStash)
|
if (stashMode == StashMode::TryStash)
|
||||||
endStashScope(workingDirectory);
|
endStashScope(workingDirectory);
|
||||||
if (command->result() == ProcessResult::FinishedWithSuccess)
|
if (result.result() == ProcessResult::FinishedWithSuccess)
|
||||||
updateSubmodulesIfNeeded(workingDirectory, true);
|
updateSubmodulesIfNeeded(workingDirectory, true);
|
||||||
});
|
if (handler)
|
||||||
return command;
|
handler(result);
|
||||||
|
};
|
||||||
|
vcsExecWithHandler(workingDirectory, arguments, context, commandHandler,
|
||||||
|
RunFlags::ExpectRepoChanges | RunFlags::ShowSuccessMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* method used to setup arguments for checkout, in case user wants to create local branch */
|
/* method used to setup arguments for checkout, in case user wants to create local branch */
|
||||||
@@ -1461,14 +1463,12 @@ void GitClient::reset(const FilePath &workingDirectory, const QString &argument,
|
|||||||
void GitClient::removeStaleRemoteBranches(const FilePath &workingDirectory, const QString &remote)
|
void GitClient::removeStaleRemoteBranches(const FilePath &workingDirectory, const QString &remote)
|
||||||
{
|
{
|
||||||
const QStringList arguments = {"remote", "prune", remote};
|
const QStringList arguments = {"remote", "prune", remote};
|
||||||
|
const auto commandHandler = [workingDirectory](const CommandResult &result) {
|
||||||
VcsCommand *command = vcsExec(workingDirectory, arguments, nullptr, true,
|
if (result.result() == ProcessResult::FinishedWithSuccess)
|
||||||
RunFlags::ShowSuccessMessage);
|
|
||||||
|
|
||||||
connect(command, &VcsCommand::done, this, [workingDirectory, command] {
|
|
||||||
if (command->result() == ProcessResult::FinishedWithSuccess)
|
|
||||||
GitPlugin::updateBranches(workingDirectory);
|
GitPlugin::updateBranches(workingDirectory);
|
||||||
});
|
};
|
||||||
|
vcsExecWithHandler(workingDirectory, arguments, this, commandHandler,
|
||||||
|
RunFlags::ShowSuccessMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GitClient::recoverDeletedFiles(const FilePath &workingDirectory)
|
void GitClient::recoverDeletedFiles(const FilePath &workingDirectory)
|
||||||
@@ -2295,9 +2295,9 @@ void GitClient::updateSubmodulesIfNeeded(const FilePath &workingDirectory, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VcsCommand *cmd = vcsExec(workingDirectory, {"submodule", "update"}, nullptr, true,
|
vcsExecWithHandler(workingDirectory, {"submodule", "update"},
|
||||||
|
this, [this](const CommandResult &) { finishSubmoduleUpdate(); },
|
||||||
RunFlags::ExpectRepoChanges);
|
RunFlags::ExpectRepoChanges);
|
||||||
connect(cmd, &VcsCommand::done, this, &GitClient::finishSubmoduleUpdate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GitClient::finishSubmoduleUpdate()
|
void GitClient::finishSubmoduleUpdate()
|
||||||
@@ -3077,12 +3077,12 @@ void GitClient::revertFiles(const QStringList &files, bool revertStaging)
|
|||||||
void GitClient::fetch(const FilePath &workingDirectory, const QString &remote)
|
void GitClient::fetch(const FilePath &workingDirectory, const QString &remote)
|
||||||
{
|
{
|
||||||
QStringList const arguments = {"fetch", (remote.isEmpty() ? "--all" : remote)};
|
QStringList const arguments = {"fetch", (remote.isEmpty() ? "--all" : remote)};
|
||||||
VcsCommand *command = vcsExec(workingDirectory, arguments, nullptr, true,
|
const auto commandHandler = [workingDirectory](const CommandResult &result) {
|
||||||
RunFlags::ShowSuccessMessage);
|
if (result.result() == ProcessResult::FinishedWithSuccess)
|
||||||
connect(command, &VcsCommand::done, this, [workingDirectory, command] {
|
|
||||||
if (command->result() == ProcessResult::FinishedWithSuccess)
|
|
||||||
GitPlugin::updateBranches(workingDirectory);
|
GitPlugin::updateBranches(workingDirectory);
|
||||||
});
|
};
|
||||||
|
vcsExecWithHandler(workingDirectory, arguments, this, commandHandler,
|
||||||
|
RunFlags::ShowSuccessMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GitClient::executeAndHandleConflicts(const FilePath &workingDirectory,
|
bool GitClient::executeAndHandleConflicts(const FilePath &workingDirectory,
|
||||||
@@ -3237,75 +3237,12 @@ void GitClient::subversionDeltaCommit(const FilePath &workingDirectory) const
|
|||||||
vcsExec(workingDirectory, {"svn", "dcommit"}, nullptr, true, RunFlags::ShowSuccessMessage);
|
vcsExec(workingDirectory, {"svn", "dcommit"}, nullptr, true, RunFlags::ShowSuccessMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PushHandler : public QObject
|
enum class PushFailure { Unknown, NonFastForward, NoRemoteBranch };
|
||||||
{
|
|
||||||
public:
|
|
||||||
PushHandler(GitClient *gitClient, const FilePath &workingDir, const QStringList &pushArgs)
|
|
||||||
: m_gitClient(gitClient)
|
|
||||||
{
|
|
||||||
VcsCommand *command = gitClient->vcsExec(workingDir, QStringList({"push"}) + pushArgs,
|
|
||||||
nullptr, true, RunFlags::ShowSuccessMessage);
|
|
||||||
// Make command a parent of this in order to delete this when command is deleted
|
|
||||||
setParent(command);
|
|
||||||
connect(command, &VcsCommand::done, this, [=] {
|
|
||||||
QString pushFallbackCommand;
|
|
||||||
const PushFailure pushFailure = handleError(command->cleanedStdErr(),
|
|
||||||
&pushFallbackCommand);
|
|
||||||
if (command->result() == ProcessResult::FinishedWithSuccess) {
|
|
||||||
GitPlugin::updateCurrentBranch();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (pushFailure == Unknown || !m_gitClient)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pushFailure == NonFastForward) {
|
static PushFailure handleError(const QString &text, QString *pushFallbackCommand)
|
||||||
const QColor warnColor = Utils::creatorTheme()->color(Theme::TextColorError);
|
{
|
||||||
if (QMessageBox::question(
|
|
||||||
Core::ICore::dialogParent(), Tr::tr("Force Push"),
|
|
||||||
Tr::tr("Push failed. Would you like to force-push <span style=\"color:#%1\">"
|
|
||||||
"(rewrites remote history)</span>?")
|
|
||||||
.arg(QString::number(warnColor.rgba(), 16)),
|
|
||||||
QMessageBox::Yes | QMessageBox::No,
|
|
||||||
QMessageBox::No) != QMessageBox::Yes) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
VcsCommand *rePushCommand = m_gitClient->vcsExec(workingDir,
|
|
||||||
QStringList({"push", "--force-with-lease"}) + pushArgs,
|
|
||||||
nullptr, true, RunFlags::ShowSuccessMessage);
|
|
||||||
connect(rePushCommand, &VcsCommand::done, this, [rePushCommand] {
|
|
||||||
if (rePushCommand->result() == ProcessResult::FinishedWithSuccess)
|
|
||||||
GitPlugin::updateCurrentBranch();
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// NoRemoteBranch case
|
|
||||||
if (QMessageBox::question(
|
|
||||||
Core::ICore::dialogParent(), Tr::tr("No Upstream Branch"),
|
|
||||||
Tr::tr("Push failed because the local branch \"%1\" "
|
|
||||||
"does not have an upstream branch on the remote.\n\n"
|
|
||||||
"Would you like to create the branch \"%1\" on the "
|
|
||||||
"remote and set it as upstream?")
|
|
||||||
.arg(m_gitClient->synchronousCurrentLocalBranch(workingDir)),
|
|
||||||
QMessageBox::Yes | QMessageBox::No,
|
|
||||||
QMessageBox::No) != QMessageBox::Yes) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const QStringList fallbackCommandParts =
|
|
||||||
pushFallbackCommand.split(' ', Qt::SkipEmptyParts);
|
|
||||||
VcsCommand *rePushCommand = m_gitClient->vcsExec(workingDir,
|
|
||||||
fallbackCommandParts.mid(1), nullptr, true, RunFlags::ShowSuccessMessage);
|
|
||||||
connect(rePushCommand, &VcsCommand::done, this, [workingDir, rePushCommand] {
|
|
||||||
if (rePushCommand->result() == ProcessResult::FinishedWithSuccess)
|
|
||||||
GitPlugin::updateBranches(workingDir);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
enum PushFailure { Unknown, NonFastForward, NoRemoteBranch };
|
|
||||||
|
|
||||||
PushFailure handleError(const QString &text, QString *pushFallbackCommand) const {
|
|
||||||
if (text.contains("non-fast-forward"))
|
if (text.contains("non-fast-forward"))
|
||||||
return NonFastForward;
|
return PushFailure::NonFastForward;
|
||||||
|
|
||||||
if (text.contains("has no upstream branch")) {
|
if (text.contains("has no upstream branch")) {
|
||||||
const QStringList lines = text.split('\n', Qt::SkipEmptyParts);
|
const QStringList lines = text.split('\n', Qt::SkipEmptyParts);
|
||||||
@@ -3321,17 +3258,64 @@ private:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NoRemoteBranch;
|
return PushFailure::NoRemoteBranch;
|
||||||
}
|
}
|
||||||
return Unknown;
|
return PushFailure::Unknown;
|
||||||
};
|
|
||||||
|
|
||||||
QPointer<GitClient> m_gitClient;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void GitClient::push(const FilePath &workingDirectory, const QStringList &pushArgs)
|
void GitClient::push(const FilePath &workingDirectory, const QStringList &pushArgs)
|
||||||
{
|
{
|
||||||
new PushHandler(this, workingDirectory, pushArgs);
|
const auto commandHandler = [=](const CommandResult &result) {
|
||||||
|
QString pushFallbackCommand;
|
||||||
|
const PushFailure pushFailure = handleError(result.cleanedStdErr(),
|
||||||
|
&pushFallbackCommand);
|
||||||
|
if (result.result() == ProcessResult::FinishedWithSuccess) {
|
||||||
|
GitPlugin::updateCurrentBranch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pushFailure == PushFailure::Unknown)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pushFailure == PushFailure::NonFastForward) {
|
||||||
|
const QColor warnColor = Utils::creatorTheme()->color(Theme::TextColorError);
|
||||||
|
if (QMessageBox::question(
|
||||||
|
Core::ICore::dialogParent(), Tr::tr("Force Push"),
|
||||||
|
Tr::tr("Push failed. Would you like to force-push <span style=\"color:#%1\">"
|
||||||
|
"(rewrites remote history)</span>?")
|
||||||
|
.arg(QString::number(warnColor.rgba(), 16)),
|
||||||
|
QMessageBox::Yes | QMessageBox::No,
|
||||||
|
QMessageBox::No) != QMessageBox::Yes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto commandHandler = [](const CommandResult &result) {
|
||||||
|
if (result.result() == ProcessResult::FinishedWithSuccess)
|
||||||
|
GitPlugin::updateCurrentBranch();
|
||||||
|
};
|
||||||
|
vcsExecWithHandler(workingDirectory, QStringList{"push", "--force-with-lease"} + pushArgs,
|
||||||
|
this, commandHandler, RunFlags::ShowSuccessMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// NoRemoteBranch case
|
||||||
|
if (QMessageBox::question(
|
||||||
|
Core::ICore::dialogParent(), Tr::tr("No Upstream Branch"),
|
||||||
|
Tr::tr("Push failed because the local branch \"%1\" "
|
||||||
|
"does not have an upstream branch on the remote.\n\n"
|
||||||
|
"Would you like to create the branch \"%1\" on the "
|
||||||
|
"remote and set it as upstream?")
|
||||||
|
.arg(synchronousCurrentLocalBranch(workingDirectory)),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QStringList fallbackCommandParts = pushFallbackCommand.split(' ', Qt::SkipEmptyParts);
|
||||||
|
const auto commandHandler = [workingDirectory](const CommandResult &result) {
|
||||||
|
if (result.result() == ProcessResult::FinishedWithSuccess)
|
||||||
|
GitPlugin::updateBranches(workingDirectory);
|
||||||
|
};
|
||||||
|
vcsExecWithHandler(workingDirectory, fallbackCommandParts.mid(1),
|
||||||
|
this, commandHandler, RunFlags::ShowSuccessMessage);
|
||||||
|
};
|
||||||
|
vcsExecWithHandler(workingDirectory, QStringList({"push"}) + pushArgs, this, commandHandler,
|
||||||
|
RunFlags::ShowSuccessMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GitClient::synchronousMerge(const FilePath &workingDirectory, const QString &branch,
|
bool GitClient::synchronousMerge(const FilePath &workingDirectory, const QString &branch,
|
||||||
@@ -3393,7 +3377,7 @@ VcsCommand *GitClient::vcsExecAbortable(const FilePath &workingDirectory,
|
|||||||
if (isRebase)
|
if (isRebase)
|
||||||
command->setProgressParser(GitProgressParser());
|
command->setProgressParser(GitProgressParser());
|
||||||
command->start();
|
command->start();
|
||||||
|
// TODO: Don't return command, take handler arg
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3450,9 +3434,11 @@ void GitClient::stashPop(const FilePath &workingDirectory, const QString &stash)
|
|||||||
QStringList arguments = {"stash", "pop"};
|
QStringList arguments = {"stash", "pop"};
|
||||||
if (!stash.isEmpty())
|
if (!stash.isEmpty())
|
||||||
arguments << stash;
|
arguments << stash;
|
||||||
VcsCommand *cmd = vcsExec(workingDirectory, arguments, nullptr, true,
|
const auto commandHandler = [workingDirectory](const CommandResult &result) {
|
||||||
|
ConflictHandler::handleResponse(result, workingDirectory);
|
||||||
|
};
|
||||||
|
vcsExecWithHandler(workingDirectory, arguments, this, commandHandler,
|
||||||
RunFlags::ExpectRepoChanges);
|
RunFlags::ExpectRepoChanges);
|
||||||
ConflictHandler::attachToCommand(cmd, workingDirectory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GitClient::synchronousStashRestore(const FilePath &workingDirectory,
|
bool GitClient::synchronousStashRestore(const FilePath &workingDirectory,
|
||||||
|
@@ -181,8 +181,9 @@ public:
|
|||||||
QString revision = {}, QString *errorMessage = nullptr,
|
QString revision = {}, QString *errorMessage = nullptr,
|
||||||
bool revertStaging = true);
|
bool revertStaging = true);
|
||||||
enum class StashMode { NoStash, TryStash };
|
enum class StashMode { NoStash, TryStash };
|
||||||
VcsBase::VcsCommand *checkout(const Utils::FilePath &workingDirectory, const QString &ref,
|
void checkout(const Utils::FilePath &workingDirectory, const QString &ref,
|
||||||
StashMode stashMode = StashMode::TryStash);
|
StashMode stashMode = StashMode::TryStash, const QObject *context = nullptr,
|
||||||
|
const VcsBase::CommandHandler &handler = {});
|
||||||
|
|
||||||
QStringList setupCheckoutArguments(const Utils::FilePath &workingDirectory, const QString &ref);
|
QStringList setupCheckoutArguments(const Utils::FilePath &workingDirectory, const QString &ref);
|
||||||
void updateSubmodulesIfNeeded(const Utils::FilePath &workingDirectory, bool prompt);
|
void updateSubmodulesIfNeeded(const Utils::FilePath &workingDirectory, bool prompt);
|
||||||
|
@@ -1572,19 +1572,19 @@ void GitPluginPrivate::instantBlame()
|
|||||||
const QFileInfo fi(filePath.toString());
|
const QFileInfo fi(filePath.toString());
|
||||||
const Utils::FilePath workingDirectory = Utils::FilePath::fromString(fi.path());
|
const Utils::FilePath workingDirectory = Utils::FilePath::fromString(fi.path());
|
||||||
const QString lineString = QString("%1,%1").arg(line);
|
const QString lineString = QString("%1,%1").arg(line);
|
||||||
const VcsCommand *command = GitClient::instance()->vcsExec(
|
const auto commandHandler = [this, filePath, line](const CommandResult &result) {
|
||||||
workingDirectory, {"blame", "-p", "-L", lineString, "--", filePath.toString()},
|
if (result.result() == ProcessResult::FinishedWithError &&
|
||||||
nullptr, false, RunFlags::NoOutput);
|
result.cleanedStdErr().contains("no such path")) {
|
||||||
connect(command, &VcsCommand::done, this, [command, filePath, line, this] {
|
|
||||||
if (command->result() == ProcessResult::FinishedWithError &&
|
|
||||||
command->cleanedStdErr().contains("no such path")) {
|
|
||||||
disconnect(m_blameCursorPosConn);
|
disconnect(m_blameCursorPosConn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const QString output = command->cleanedStdOut();
|
const QString output = result.cleanedStdOut();
|
||||||
const CommitInfo info = parseBlameOutput(output.split('\n'), filePath, m_author);
|
const CommitInfo info = parseBlameOutput(output.split('\n'), filePath, m_author);
|
||||||
m_blameMark.reset(new BlameMark(filePath, line, info));
|
m_blameMark.reset(new BlameMark(filePath, line, info));
|
||||||
});
|
};
|
||||||
|
GitClient::instance()->vcsExecWithHandler(workingDirectory,
|
||||||
|
{"blame", "-p", "-L", lineString, "--", filePath.toString()},
|
||||||
|
this, commandHandler, RunFlags::NoOutput, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GitPluginPrivate::stopInstantBlame()
|
void GitPluginPrivate::stopInstantBlame()
|
||||||
|
@@ -203,6 +203,7 @@ void GitSubmitEditor::updateFileModel()
|
|||||||
if (w->updateInProgress() || m_workingDirectory.isEmpty())
|
if (w->updateInProgress() || m_workingDirectory.isEmpty())
|
||||||
return;
|
return;
|
||||||
w->setUpdateInProgress(true);
|
w->setUpdateInProgress(true);
|
||||||
|
// TODO: Check if fetch works OK from separate thread, refactor otherwise
|
||||||
m_fetchWatcher.setFuture(Utils::runAsync(&CommitDataFetchResult::fetch,
|
m_fetchWatcher.setFuture(Utils::runAsync(&CommitDataFetchResult::fetch,
|
||||||
m_commitType, m_workingDirectory));
|
m_commitType, m_workingDirectory));
|
||||||
Core::ProgressManager::addTask(m_fetchWatcher.future(), Tr::tr("Refreshing Commit Data"),
|
Core::ProgressManager::addTask(m_fetchWatcher.future(), Tr::tr("Refreshing Commit Data"),
|
||||||
|
@@ -159,7 +159,26 @@ void VcsBaseClientImpl::annotateRevisionRequested(const FilePath &workingDirecto
|
|||||||
annotate(workingDirectory, file, changeCopy, line);
|
annotate(workingDirectory, file, changeCopy, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
VcsCommand *VcsBaseClientImpl::vcsExec(const FilePath &workingDirectory,
|
void VcsBaseClientImpl::vcsExecWithHandler(const FilePath &workingDirectory,
|
||||||
|
const QStringList &arguments,
|
||||||
|
const QObject *context,
|
||||||
|
const CommandHandler &handler,
|
||||||
|
RunFlags additionalFlags,
|
||||||
|
bool useOutputToWindow) const
|
||||||
|
{
|
||||||
|
VcsCommand *command = createCommand(workingDirectory, nullptr,
|
||||||
|
useOutputToWindow ? VcsWindowOutputBind : NoOutputBind);
|
||||||
|
command->addFlags(additionalFlags);
|
||||||
|
command->addJob({vcsBinary(), arguments}, vcsTimeoutS());
|
||||||
|
if (handler) {
|
||||||
|
connect(command, &VcsCommand::done, context, [command, handler] {
|
||||||
|
handler(CommandResult(*command));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
command->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VcsBaseClientImpl::vcsExec(const FilePath &workingDirectory,
|
||||||
const QStringList &arguments,
|
const QStringList &arguments,
|
||||||
VcsBaseEditorWidget *editor, bool useOutputToWindow,
|
VcsBaseEditorWidget *editor, bool useOutputToWindow,
|
||||||
RunFlags additionalFlags) const
|
RunFlags additionalFlags) const
|
||||||
@@ -169,8 +188,8 @@ VcsCommand *VcsBaseClientImpl::vcsExec(const FilePath &workingDirectory,
|
|||||||
command->addFlags(additionalFlags);
|
command->addFlags(additionalFlags);
|
||||||
if (editor)
|
if (editor)
|
||||||
command->setCodec(editor->codec());
|
command->setCodec(editor->codec());
|
||||||
enqueueJob(command, arguments);
|
command->addJob({vcsBinary(), arguments}, vcsTimeoutS());
|
||||||
return command;
|
command->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
int VcsBaseClientImpl::vcsTimeoutS() const
|
int VcsBaseClientImpl::vcsTimeoutS() const
|
||||||
|
@@ -30,6 +30,8 @@ class VcsBaseEditorConfig;
|
|||||||
class VcsBaseEditorWidget;
|
class VcsBaseEditorWidget;
|
||||||
class VcsCommand;
|
class VcsCommand;
|
||||||
|
|
||||||
|
using CommandHandler = std::function<void(const CommandResult &)>;
|
||||||
|
|
||||||
class VCSBASE_EXPORT VcsBaseClientImpl : public QObject
|
class VCSBASE_EXPORT VcsBaseClientImpl : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -85,8 +87,14 @@ public:
|
|||||||
RunFlags flags = RunFlags::None,
|
RunFlags flags = RunFlags::None,
|
||||||
int timeoutS = -1, QTextCodec *codec = nullptr) const;
|
int timeoutS = -1, QTextCodec *codec = nullptr) const;
|
||||||
|
|
||||||
|
void vcsExecWithHandler(const Utils::FilePath &workingDirectory,
|
||||||
|
const QStringList &arguments,
|
||||||
|
const QObject *context,
|
||||||
|
const CommandHandler &handler,
|
||||||
|
RunFlags additionalFlags = RunFlags::None,
|
||||||
|
bool useOutputToWindow = true) const;
|
||||||
// Simple helper to execute a single command using createCommand and enqueueJob.
|
// Simple helper to execute a single command using createCommand and enqueueJob.
|
||||||
VcsCommand *vcsExec(const Utils::FilePath &workingDirectory,
|
void vcsExec(const Utils::FilePath &workingDirectory,
|
||||||
const QStringList &arguments,
|
const QStringList &arguments,
|
||||||
VcsBaseEditorWidget *editor = nullptr,
|
VcsBaseEditorWidget *editor = nullptr,
|
||||||
bool useOutputToWindow = false,
|
bool useOutputToWindow = false,
|
||||||
|
@@ -333,4 +333,10 @@ CommandResult::CommandResult(const QtcProcess &process)
|
|||||||
, m_rawStdOut(process.rawStdOut())
|
, m_rawStdOut(process.rawStdOut())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
CommandResult::CommandResult(const VcsCommand &command)
|
||||||
|
: m_result(command.result())
|
||||||
|
, m_cleanedStdOut(command.cleanedStdOut())
|
||||||
|
, m_cleanedStdErr(command.cleanedStdErr())
|
||||||
|
{}
|
||||||
|
|
||||||
} // namespace VcsBase
|
} // namespace VcsBase
|
||||||
|
@@ -27,11 +27,14 @@ namespace VcsBase {
|
|||||||
|
|
||||||
namespace Internal { class VcsCommandPrivate; }
|
namespace Internal { class VcsCommandPrivate; }
|
||||||
|
|
||||||
|
class VcsCommand;
|
||||||
|
|
||||||
class VCSBASE_EXPORT CommandResult
|
class VCSBASE_EXPORT CommandResult
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CommandResult() = default;
|
CommandResult() = default;
|
||||||
CommandResult(const Utils::QtcProcess &process);
|
CommandResult(const Utils::QtcProcess &process);
|
||||||
|
CommandResult(const VcsCommand &command);
|
||||||
CommandResult(Utils::ProcessResult result, const QString &exitMessage)
|
CommandResult(Utils::ProcessResult result, const QString &exitMessage)
|
||||||
: m_result(result), m_exitMessage(exitMessage) {}
|
: m_result(result), m_exitMessage(exitMessage) {}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user