VCS: VcsBaseClient::vcsFullySynchronousExec returns a SynchronousProcessResponse

Change-Id: Ic155da2ed1fd36f1f91327ac90f34a5cad3c210e
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Tobias Hunger
2016-07-05 10:34:41 +02:00
parent 5efd82468b
commit ca7a924a06
7 changed files with 320 additions and 343 deletions

View File

@@ -110,8 +110,8 @@ bool BazaarClient::synchronousSetUserId()
args << QLatin1String("whoami") args << QLatin1String("whoami")
<< (settings().stringValue(BazaarSettings::userNameKey) + QLatin1String(" <") << (settings().stringValue(BazaarSettings::userNameKey) + QLatin1String(" <")
+ settings().stringValue(BazaarSettings::userEmailKey) + QLatin1Char('>')); + settings().stringValue(BazaarSettings::userEmailKey) + QLatin1Char('>'));
QByteArray stdOut; return vcsFullySynchronousExec(QDir::currentPath(), args).result
return vcsFullySynchronousExec(QDir::currentPath(), args, &stdOut); == SynchronousProcessResponse::Finished;
} }
BranchInfo BazaarClient::synchronousBranchQuery(const QString &repositoryRoot) const BranchInfo BazaarClient::synchronousBranchQuery(const QString &repositoryRoot) const
@@ -150,11 +150,10 @@ bool BazaarClient::synchronousUncommit(const QString &workingDir,
<< QLatin1String("--verbose") // Will print out what is being removed << QLatin1String("--verbose") // Will print out what is being removed
<< revisionSpec(revision) << revisionSpec(revision)
<< extraOptions; << extraOptions;
QByteArray stdOut;
const bool success = vcsFullySynchronousExec(workingDir, args, &stdOut); const SynchronousProcessResponse result = vcsFullySynchronousExec(workingDir, args);
if (!stdOut.isEmpty()) VcsOutputWindow::append(result.stdOut());
VcsOutputWindow::append(QString::fromUtf8(stdOut)); return result.result == SynchronousProcessResponse::Finished;
return success;
} }
void BazaarClient::commit(const QString &repositoryRoot, const QStringList &files, void BazaarClient::commit(const QString &repositoryRoot, const QStringList &files,
@@ -187,10 +186,11 @@ bool BazaarClient::managesFile(const QString &workingDirectory, const QString &f
{ {
QStringList args(QLatin1String("status")); QStringList args(QLatin1String("status"));
args << fileName; args << fileName;
QByteArray stdOut;
if (!vcsFullySynchronousExec(workingDirectory, args, &stdOut)) const SynchronousProcessResponse result = vcsFullySynchronousExec(workingDirectory, args);
if (result.result != SynchronousProcessResponse::Finished)
return false; return false;
return !stdOut.startsWith("unknown"); return result.rawStdOut.startsWith("unknown");
} }
void BazaarClient::view(const QString &source, const QString &id, const QStringList &extraOptions) void BazaarClient::view(const QString &source, const QString &id, const QStringList &extraOptions)

View File

@@ -103,7 +103,8 @@ static unsigned diffExecutionFlags()
} }
const unsigned silentFlags = unsigned(VcsCommand::SuppressCommandLogging const unsigned silentFlags = unsigned(VcsCommand::SuppressCommandLogging
| VcsCommand::SuppressStdErr); | VcsCommand::SuppressStdErr
| VcsCommand::SuppressFailMessage);
///////////////////////////////////// /////////////////////////////////////
@@ -567,12 +568,12 @@ static inline void msgCannotRun(const QString &message, QString *errorMessage)
} }
static inline void msgCannotRun(const QStringList &args, const QString &workingDirectory, static inline void msgCannotRun(const QStringList &args, const QString &workingDirectory,
const QByteArray &error, QString *errorMessage) const QString &error, QString *errorMessage)
{ {
const QString message = GitClient::tr("Cannot run \"%1\" in \"%2\": %3") const QString message = GitClient::tr("Cannot run \"%1\" in \"%2\": %3")
.arg("git " + args.join(' '), .arg("git " + args.join(' '),
QDir::toNativeSeparators(workingDirectory), QDir::toNativeSeparators(workingDirectory),
GitClient::commandOutputFromLocal8Bit(error)); error);
msgCannotRun(message, errorMessage); msgCannotRun(message, errorMessage);
} }
@@ -625,9 +626,8 @@ QString GitClient::findGitDirForRepository(const QString &repositoryDir) const
bool GitClient::managesFile(const QString &workingDirectory, const QString &fileName) const bool GitClient::managesFile(const QString &workingDirectory, const QString &fileName) const
{ {
QByteArray output; return vcsFullySynchronousExec(workingDirectory, { "ls-files", "--error-unmatch", fileName }).result
const QStringList arguments = { "ls-files", "--error-unmatch", fileName }; == SynchronousProcessResponse::Finished;
return vcsFullySynchronousExec(workingDirectory, arguments, &output, 0, silentFlags);
} }
QTextCodec *GitClient::codecFor(GitClient::CodecType codecType, const QString &source) const QTextCodec *GitClient::codecFor(GitClient::CodecType codecType, const QString &source) const
@@ -938,17 +938,17 @@ bool GitClient::synchronousCheckout(const QString &workingDirectory,
const QString &ref, const QString &ref,
QString *errorMessage) QString *errorMessage)
{ {
QByteArray outputText;
QByteArray errorText;
QStringList arguments = setupCheckoutArguments(workingDirectory, ref); QStringList arguments = setupCheckoutArguments(workingDirectory, ref);
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputText, 0, const SynchronousProcessResponse resp = vcsFullySynchronousExec(
VcsCommand::ExpectRepoChanges); workingDirectory, arguments, VcsCommand::ExpectRepoChanges);
VcsOutputWindow::append(commandOutputFromLocal8Bit(outputText)); VcsOutputWindow::append(resp.stdOut());
if (rc) if (resp.result == SynchronousProcessResponse::Finished) {
updateSubmodulesIfNeeded(workingDirectory, true); updateSubmodulesIfNeeded(workingDirectory, true);
else return true;
msgCannotRun(arguments, workingDirectory, errorText, errorMessage); } else {
return rc; msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
return false;
}
} }
/* 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 */
@@ -1044,76 +1044,72 @@ void GitClient::addFile(const QString &workingDirectory, const QString &fileName
bool GitClient::synchronousLog(const QString &workingDirectory, const QStringList &arguments, bool GitClient::synchronousLog(const QString &workingDirectory, const QStringList &arguments,
QString *output, QString *errorMessageIn, unsigned flags) QString *output, QString *errorMessageIn, unsigned flags)
{ {
QByteArray outputData;
QByteArray errorData;
QStringList allArguments = { "log", noColorOption }; QStringList allArguments = { "log", noColorOption };
allArguments.append(arguments); allArguments.append(arguments);
const bool rc = vcsFullySynchronousExec(workingDirectory, allArguments, &outputData, &errorData, flags);
if (rc) { const SynchronousProcessResponse resp = vcsFullySynchronousExec(
if (QTextCodec *codec = encoding(workingDirectory, "i18n.logOutputEncoding")) workingDirectory, allArguments, flags, vcsTimeoutS(),
*output = codec->toUnicode(outputData); encoding(workingDirectory, "i18n.logOutputEncoding"));
else if (resp.result == SynchronousProcessResponse::Finished) {
*output = commandOutputFromLocal8Bit(outputData); *output = resp.stdOut();
return true;
} else { } else {
msgCannotRun(tr("Cannot obtain log of \"%1\": %2") msgCannotRun(tr("Cannot obtain log of \"%1\": %2")
.arg(QDir::toNativeSeparators(workingDirectory), .arg(QDir::toNativeSeparators(workingDirectory), resp.stdErr()), errorMessageIn);
commandOutputFromLocal8Bit(errorData)), errorMessageIn); return false;
} }
return rc;
} }
bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringList &files) bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringList &files)
{ {
QByteArray outputText; return vcsFullySynchronousExec(workingDirectory, QStringList({ "add" }) + files).result
return vcsFullySynchronousExec(workingDirectory, QStringList({ "add" }) + files, &outputText); == SynchronousProcessResponse::Finished;
} }
bool GitClient::synchronousDelete(const QString &workingDirectory, bool GitClient::synchronousDelete(const QString &workingDirectory,
bool force, bool force,
const QStringList &files) const QStringList &files)
{ {
QByteArray outputText;
QStringList arguments = { "rm" }; QStringList arguments = { "rm" };
if (force) if (force)
arguments << "--force"; arguments << "--force";
arguments.append(files); arguments.append(files);
return vcsFullySynchronousExec(workingDirectory, arguments, &outputText); return vcsFullySynchronousExec(workingDirectory, arguments).result
== SynchronousProcessResponse::Finished;
} }
bool GitClient::synchronousMove(const QString &workingDirectory, bool GitClient::synchronousMove(const QString &workingDirectory,
const QString &from, const QString &from,
const QString &to) const QString &to)
{ {
QByteArray outputText; return vcsFullySynchronousExec(workingDirectory, { "mv", from, to }).result
return vcsFullySynchronousExec(workingDirectory, { "mv", from, to }, &outputText); == SynchronousProcessResponse::Finished;
} }
bool GitClient::synchronousReset(const QString &workingDirectory, bool GitClient::synchronousReset(const QString &workingDirectory,
const QStringList &files, const QStringList &files,
QString *errorMessage) QString *errorMessage)
{ {
QByteArray outputText;
QByteArray errorText;
QStringList arguments = { "reset" }; QStringList arguments = { "reset" };
if (files.isEmpty()) if (files.isEmpty())
arguments << "--hard"; arguments << "--hard";
else else
arguments << HEAD << "--" << files; arguments << HEAD << "--" << files;
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputText, &errorText);
const QString output = commandOutputFromLocal8Bit(outputText); const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments);
VcsOutputWindow::append(output); const QString stdOut = resp.stdOut();
VcsOutputWindow::append(stdOut);
// Note that git exits with 1 even if the operation is successful // Note that git exits with 1 even if the operation is successful
// Assume real failure if the output does not contain "foo.cpp modified" // Assume real failure if the output does not contain "foo.cpp modified"
// or "Unstaged changes after reset" (git 1.7.0). // or "Unstaged changes after reset" (git 1.7.0).
if (!rc && (!output.contains("modified") && !output.contains("Unstaged changes after reset"))) { if (resp.result == SynchronousProcessResponse::Finished
&& (!stdOut.contains("modified") && !stdOut.contains("Unstaged changes after reset"))) {
if (files.isEmpty()) { if (files.isEmpty()) {
msgCannotRun(arguments, workingDirectory, errorText, errorMessage); msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
} else { } else {
msgCannotRun(tr("Cannot reset %n file(s) in \"%1\": %2", 0, files.size()) msgCannotRun(tr("Cannot reset %n file(s) in \"%1\": %2", 0, files.size())
.arg(QDir::toNativeSeparators(workingDirectory), .arg(QDir::toNativeSeparators(workingDirectory), resp.stdErr()),
commandOutputFromLocal8Bit(errorText)),
errorMessage); errorMessage);
} }
return false; return false;
@@ -1124,13 +1120,15 @@ bool GitClient::synchronousReset(const QString &workingDirectory,
// Initialize repository // Initialize repository
bool GitClient::synchronousInit(const QString &workingDirectory) bool GitClient::synchronousInit(const QString &workingDirectory)
{ {
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, { "init" });
const bool rc = vcsFullySynchronousExec(workingDirectory, { "init" }, &outputText);
// '[Re]Initialized...' // '[Re]Initialized...'
VcsOutputWindow::append(commandOutputFromLocal8Bit(outputText)); VcsOutputWindow::append(resp.stdOut());
if (rc) if (resp.result == SynchronousProcessResponse::Finished) {
resetCachedVcsInfo(workingDirectory); resetCachedVcsInfo(workingDirectory);
return rc; return true;
} else {
return false;
}
} }
/* Checkout, supports: /* Checkout, supports:
@@ -1145,21 +1143,18 @@ bool GitClient::synchronousCheckoutFiles(const QString &workingDirectory, QStrin
revision = HEAD; revision = HEAD;
if (files.isEmpty()) if (files.isEmpty())
files = QStringList("."); files = QStringList(".");
QByteArray outputText;
QByteArray errorText;
QStringList arguments = { "checkout" }; QStringList arguments = { "checkout" };
if (revertStaging) if (revertStaging)
arguments << revision; arguments << revision;
arguments << "--" << files; arguments << "--" << files;
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputText, &errorText, const SynchronousProcessResponse resp = vcsFullySynchronousExec(
VcsCommand::ExpectRepoChanges); workingDirectory, arguments, VcsCommand::ExpectRepoChanges);
if (!rc) { if (resp.result != SynchronousProcessResponse::Finished) {
const QString fileArg = files.join(", "); const QString fileArg = files.join(", ");
//: Meaning of the arguments: %1: revision, %2: files, %3: repository, //: Meaning of the arguments: %1: revision, %2: files, %3: repository,
//: %4: Error message //: %4: Error message
msgCannotRun(tr("Cannot checkout \"%1\" of %2 in \"%3\": %4") msgCannotRun(tr("Cannot checkout \"%1\" of %2 in \"%3\": %4")
.arg(revision, fileArg, workingDirectory, .arg(revision, fileArg, workingDirectory, resp.stdErr()),
commandOutputFromLocal8Bit(errorText)),
errorMessage); errorMessage);
return false; return false;
} }
@@ -1212,16 +1207,14 @@ static inline bool splitCommitParents(const QString &line,
bool GitClient::synchronousRevListCmd(const QString &workingDirectory, const QStringList &extraArguments, bool GitClient::synchronousRevListCmd(const QString &workingDirectory, const QStringList &extraArguments,
QString *output, QString *errorMessage) const QString *output, QString *errorMessage) const
{ {
QByteArray outputTextData;
QByteArray errorText;
const QStringList arguments = QStringList({ "rev-list", noColorOption }) + extraArguments; const QStringList arguments = QStringList({ "rev-list", noColorOption }) + extraArguments;
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputTextData, const SynchronousProcessResponse resp = vcsFullySynchronousExec(
&errorText, silentFlags); workingDirectory, arguments, silentFlags);
if (!rc) { if (resp.result != SynchronousProcessResponse::Finished) {
msgCannotRun(arguments, workingDirectory, errorText, errorMessage); msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
return false; return false;
} }
*output = commandOutputFromLocal8Bit(outputTextData); *output = resp.stdOut();
return true; return true;
} }
@@ -1273,11 +1266,11 @@ QString GitClient::synchronousShortDescription(const QString &workingDirectory,
QString GitClient::synchronousCurrentLocalBranch(const QString &workingDirectory) const QString GitClient::synchronousCurrentLocalBranch(const QString &workingDirectory) const
{ {
QByteArray outputTextData;
QString branch; QString branch;
if (vcsFullySynchronousExec(workingDirectory, { "symbolic-ref", HEAD }, &outputTextData, 0, const SynchronousProcessResponse resp = vcsFullySynchronousExec(
silentFlags)) { workingDirectory, { "symbolic-ref", HEAD }, silentFlags);
branch = commandOutputFromLocal8Bit(outputTextData.trimmed()); if (resp.result == SynchronousProcessResponse::Finished) {
branch = resp.stdOut().trimmed();
} else { } else {
const QString gitDir = findGitDirForRepository(workingDirectory); const QString gitDir = findGitDirForRepository(workingDirectory);
const QString rebaseHead = gitDir + "/rebase-merge/head-name"; const QString rebaseHead = gitDir + "/rebase-merge/head-name";
@@ -1299,27 +1292,25 @@ bool GitClient::synchronousHeadRefs(const QString &workingDirectory, QStringList
QString *errorMessage) const QString *errorMessage) const
{ {
const QStringList arguments = { "show-ref", "--head", "--abbrev=10", "--dereference" }; const QStringList arguments = { "show-ref", "--head", "--abbrev=10", "--dereference" };
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(
QByteArray errorText; workingDirectory, arguments, silentFlags);
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputText, &errorText, if (resp.result != SynchronousProcessResponse::Finished) {
silentFlags); msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
if (!rc) {
msgCannotRun(arguments, workingDirectory, errorText, errorMessage);
return false; return false;
} }
QByteArray headSha = outputText.left(10); const QString stdOut = resp.stdOut();
QByteArray newLine("\n"); const QString headSha = stdOut.left(10);
const QChar newLine('\n');
int currentIndex = 15; int currentIndex = 15;
while (true) { while (true) {
currentIndex = outputText.indexOf(headSha, currentIndex); currentIndex = stdOut.indexOf(headSha, currentIndex);
if (currentIndex < 0) if (currentIndex < 0)
break; break;
currentIndex += 11; currentIndex += 11;
output->append(QString::fromLocal8Bit(outputText.mid(currentIndex, output->append(stdOut.mid(currentIndex, stdOut.indexOf(newLine, currentIndex) - currentIndex));
outputText.indexOf(newLine, currentIndex) - currentIndex)));
} }
return true; return true;
@@ -1356,11 +1347,12 @@ QString GitClient::synchronousTopic(const QString &workingDirectory) const
return remoteBranch; return remoteBranch;
// No tag or remote branch - try git describe // No tag or remote branch - try git describe
QByteArray output; const SynchronousProcessResponse resp =
if (vcsFullySynchronousExec(workingDirectory, { "describe" }, &output, 0, VcsCommand::NoOutput)) { vcsFullySynchronousExec(workingDirectory, { "describe" }, VcsCommand::NoOutput);
const QString describeOutput = commandOutputFromLocal8Bit(output.trimmed()); if (resp.result == SynchronousProcessResponse::Finished) {
if (!describeOutput.isEmpty()) const QString stdOut = resp.stdOut().trimmed();
return describeOutput; if (!stdOut.isEmpty())
return stdOut;
} }
return tr("Detached HEAD"); return tr("Detached HEAD");
} }
@@ -1369,15 +1361,15 @@ bool GitClient::synchronousRevParseCmd(const QString &workingDirectory, const QS
QString *output, QString *errorMessage) const QString *output, QString *errorMessage) const
{ {
const QStringList arguments = { "rev-parse", ref }; const QStringList arguments = { "rev-parse", ref };
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(
QByteArray errorText; workingDirectory, arguments, silentFlags);
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputText, &errorText, *output = resp.stdOut().trimmed();
silentFlags); if (resp.result != SynchronousProcessResponse::Finished) {
*output = commandOutputFromLocal8Bit(outputText.trimmed()); msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
if (!rc) return false;
msgCannotRun(arguments, workingDirectory, errorText, errorMessage); }
return rc; return true;
} }
// Retrieve head revision // Retrieve head revision
@@ -1393,28 +1385,27 @@ QString GitClient::synchronousTopRevision(const QString &workingDirectory, QStri
void GitClient::synchronousTagsForCommit(const QString &workingDirectory, const QString &revision, void GitClient::synchronousTagsForCommit(const QString &workingDirectory, const QString &revision,
QString &precedes, QString &follows) const QString &precedes, QString &follows) const
{ {
QByteArray pr; const SynchronousProcessResponse resp1 = vcsFullySynchronousExec(
vcsFullySynchronousExec(workingDirectory, { "describe", "--contains", revision }, workingDirectory, { "describe", "--contains", revision }, silentFlags);
&pr, 0, silentFlags); precedes = resp1.stdOut();
int tilde = pr.indexOf('~'); int tilde = precedes.indexOf('~');
if (tilde != -1) if (tilde != -1)
pr.truncate(tilde); precedes.truncate(tilde);
else else
pr = pr.trimmed(); precedes = precedes.trimmed();
precedes = QString::fromLocal8Bit(pr);
QStringList parents; QStringList parents;
QString errorMessage; QString errorMessage;
synchronousParentRevisions(workingDirectory, revision, &parents, &errorMessage); synchronousParentRevisions(workingDirectory, revision, &parents, &errorMessage);
foreach (const QString &p, parents) { foreach (const QString &p, parents) {
QByteArray pf; const SynchronousProcessResponse resp2 = vcsFullySynchronousExec(
vcsFullySynchronousExec(workingDirectory, { "describe", "--tags", "--abbrev=0", p }, workingDirectory, { "describe", "--tags", "--abbrev=0", p }, silentFlags);
&pf, 0, silentFlags); QString pf = resp2.stdOut();
pf.truncate(pf.lastIndexOf('\n')); pf.truncate(pf.lastIndexOf('\n'));
if (!pf.isEmpty()) { if (!pf.isEmpty()) {
if (!follows.isEmpty()) if (!follows.isEmpty())
follows += ", "; follows += ", ";
follows += QString::fromLocal8Bit(pf); follows += pf;
} }
} }
} }
@@ -1432,41 +1423,31 @@ void GitClient::branchesForCommit(const QString &revision)
bool GitClient::isRemoteCommit(const QString &workingDirectory, const QString &commit) bool GitClient::isRemoteCommit(const QString &workingDirectory, const QString &commit)
{ {
QByteArray outputText; return !vcsFullySynchronousExec(
vcsFullySynchronousExec(workingDirectory, { "branch", "-r", "--contains", commit }, workingDirectory, { "branch", "-r", "--contains", commit }, silentFlags).rawStdOut.isEmpty();
&outputText, 0, silentFlags);
return !outputText.isEmpty();
} }
bool GitClient::isFastForwardMerge(const QString &workingDirectory, const QString &branch) bool GitClient::isFastForwardMerge(const QString &workingDirectory, const QString &branch)
{ {
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(
vcsFullySynchronousExec(workingDirectory, { "merge-base", HEAD, branch }, workingDirectory, { "merge-base", HEAD, branch }, silentFlags);
&outputText, 0, silentFlags); return resp.stdOut().trimmed() == synchronousTopRevision(workingDirectory);
return commandOutputFromLocal8Bit(outputText).trimmed()
== synchronousTopRevision(workingDirectory);
} }
// Format an entry in a one-liner for selection list using git log. // Format an entry in a one-liner for selection list using git log.
QString GitClient::synchronousShortDescription(const QString &workingDirectory, const QString &revision, QString GitClient::synchronousShortDescription(const QString &workingDirectory, const QString &revision,
const QString &format) const const QString &format) const
{ {
QString description;
QByteArray outputTextData;
QByteArray errorText;
const QStringList arguments = { "log", noColorOption, ("--pretty=format:" + format), const QStringList arguments = { "log", noColorOption, ("--pretty=format:" + format),
"--max-count=1", revision }; "--max-count=1", revision };
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputTextData, &errorText, const SynchronousProcessResponse resp = vcsFullySynchronousExec(
silentFlags); workingDirectory, arguments, silentFlags);
if (!rc) { if (resp.result != SynchronousProcessResponse::Finished) {
VcsOutputWindow::appendSilently(tr("Cannot describe revision \"%1\" in \"%2\": %3") VcsOutputWindow::appendSilently(tr("Cannot describe revision \"%1\" in \"%2\": %3")
.arg(revision, workingDirectory, commandOutputFromLocal8Bit(errorText))); .arg(revision, workingDirectory, resp.stdErr()));
return revision; return revision;
} }
description = commandOutputFromLocal8Bit(outputTextData); return stripLastNewline(resp.stdOut());
if (description.endsWith('\n'))
description.truncate(description.size() - 1);
return description;
} }
// Create a default message to be used for describing stashes // Create a default message to be used for describing stashes
@@ -1540,12 +1521,13 @@ bool GitClient::executeSynchronousStash(const QString &workingDirectory,
const unsigned flags = VcsCommand::ShowStdOut const unsigned flags = VcsCommand::ShowStdOut
| VcsCommand::ExpectRepoChanges | VcsCommand::ExpectRepoChanges
| VcsCommand::ShowSuccessMessage; | VcsCommand::ShowSuccessMessage;
const SynchronousProcessResponse response = vcsSynchronousExec(workingDirectory, arguments, flags); const SynchronousProcessResponse resp = vcsSynchronousExec(workingDirectory, arguments, flags);
const bool rc = response.result == SynchronousProcessResponse::Finished; if (resp.result != SynchronousProcessResponse::Finished) {
if (!rc) msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
msgCannotRun(arguments, workingDirectory, response.rawStdErr, errorMessage); return false;
}
return rc; return true;
} }
// Resolve a stash name from message // Resolve a stash name from message
@@ -1578,43 +1560,40 @@ bool GitClient::synchronousBranchCmd(const QString &workingDirectory, QStringLis
QString *output, QString *errorMessage) const QString *output, QString *errorMessage) const
{ {
branchArgs.push_front("branch"); branchArgs.push_front("branch");
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, branchArgs);
QByteArray errorText; *output = resp.stdOut();
const bool rc = vcsFullySynchronousExec(workingDirectory, branchArgs, &outputText, &errorText); if (resp.result != SynchronousProcessResponse::Finished) {
*output = commandOutputFromLocal8Bit(outputText); msgCannotRun(branchArgs, workingDirectory, resp.stdErr(), errorMessage);
if (!rc) return false;
msgCannotRun(branchArgs, workingDirectory, errorText, errorMessage); }
return true;
return rc;
} }
bool GitClient::synchronousTagCmd(const QString &workingDirectory, QStringList tagArgs, bool GitClient::synchronousTagCmd(const QString &workingDirectory, QStringList tagArgs,
QString *output, QString *errorMessage) const QString *output, QString *errorMessage) const
{ {
tagArgs.push_front("tag"); tagArgs.push_front("tag");
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, tagArgs);
QByteArray errorText; *output = resp.stdOut();
const bool rc = vcsFullySynchronousExec(workingDirectory, tagArgs, &outputText, &errorText); if (resp.result != SynchronousProcessResponse::Finished) {
*output = commandOutputFromLocal8Bit(outputText); msgCannotRun(tagArgs, workingDirectory, resp.stdErr(), errorMessage);
if (!rc) return false;
msgCannotRun(tagArgs, workingDirectory, errorText, errorMessage); }
return true;
return rc;
} }
bool GitClient::synchronousForEachRefCmd(const QString &workingDirectory, QStringList args, bool GitClient::synchronousForEachRefCmd(const QString &workingDirectory, QStringList args,
QString *output, QString *errorMessage) const QString *output, QString *errorMessage) const
{ {
args.push_front("for-each-ref"); args.push_front("for-each-ref");
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, args,
QByteArray errorText;
const bool rc = vcsFullySynchronousExec(workingDirectory, args, &outputText, &errorText,
silentFlags); silentFlags);
*output = SynchronousProcess::normalizeNewlines(QString::fromUtf8(outputText)); *output = resp.stdOut();
if (!rc) if (resp.result != SynchronousProcessResponse::Finished) {
msgCannotRun(args, workingDirectory, errorText, errorMessage); msgCannotRun(args, workingDirectory, resp.stdErr(), errorMessage);
return false;
return rc; }
return true;
} }
VcsCommand *GitClient::asyncForEachRefCmd(const QString &workingDirectory, QStringList args) const VcsCommand *GitClient::asyncForEachRefCmd(const QString &workingDirectory, QStringList args) const
@@ -1627,15 +1606,17 @@ bool GitClient::synchronousRemoteCmd(const QString &workingDirectory, QStringLis
QString *output, QString *errorMessage, bool silent) const QString *output, QString *errorMessage, bool silent) const
{ {
remoteArgs.push_front("remote"); remoteArgs.push_front("remote");
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, remoteArgs,
QByteArray errorText; silent ? silentFlags : 0);
if (!vcsFullySynchronousExec(workingDirectory, remoteArgs, &outputText, &errorText,
silent ? silentFlags : 0)) { const QString stdErr = resp.stdErr();
msgCannotRun(remoteArgs, workingDirectory, errorText, errorMessage); *errorMessage = stdErr;
*output = resp.stdOut();
if (resp.result != SynchronousProcessResponse::Finished) {
msgCannotRun(remoteArgs, workingDirectory, stdErr, errorMessage);
return false; return false;
} }
if (output)
*output = commandOutputFromLocal8Bit(outputText);
return true; return true;
} }
@@ -1643,6 +1624,7 @@ QMap<QString,QString> GitClient::synchronousRemotesList(const QString &workingDi
QString *errorMessage) const QString *errorMessage) const
{ {
QMap<QString,QString> result; QMap<QString,QString> result;
QString output; QString output;
QString error; QString error;
if (!synchronousRemoteCmd(workingDirectory, { "-v" }, &output, &error, true)) { if (!synchronousRemoteCmd(workingDirectory, { "-v" }, &output, &error, true)) {
@@ -1658,7 +1640,7 @@ QMap<QString,QString> GitClient::synchronousRemotesList(const QString &workingDi
const int tabIndex = remote.indexOf('\t'); const int tabIndex = remote.indexOf('\t');
if (tabIndex == -1) if (tabIndex == -1)
continue; continue;
QString url = remote.mid(tabIndex + 1, remote.length() - tabIndex - 8); const QString url = remote.mid(tabIndex + 1, remote.length() - tabIndex - 8);
result.insert(remote.left(tabIndex), url); result.insert(remote.left(tabIndex), url);
} }
return result; return result;
@@ -1667,17 +1649,16 @@ QMap<QString,QString> GitClient::synchronousRemotesList(const QString &workingDi
QStringList GitClient::synchronousSubmoduleStatus(const QString &workingDirectory, QStringList GitClient::synchronousSubmoduleStatus(const QString &workingDirectory,
QString *errorMessage) const QString *errorMessage) const
{ {
QByteArray outputTextData;
QByteArray errorText;
// get submodule status // get submodule status
if (!vcsFullySynchronousExec(workingDirectory, { "submodule", "status" }, const SynchronousProcessResponse resp =
&outputTextData, &errorText, silentFlags)) { vcsFullySynchronousExec(workingDirectory, { "submodule", "status" }, silentFlags);
if (resp.result != SynchronousProcessResponse::Finished) {
msgCannotRun(tr("Cannot retrieve submodule status of \"%1\": %2") msgCannotRun(tr("Cannot retrieve submodule status of \"%1\": %2")
.arg(QDir::toNativeSeparators(workingDirectory), .arg(QDir::toNativeSeparators(workingDirectory), resp.stdErr()), errorMessage);
commandOutputFromLocal8Bit(errorText)), errorMessage);
return QStringList(); return QStringList();
} }
return commandOutputLinesFromLocal8Bit(outputTextData); return splitLines(resp.stdOut());
} }
SubmoduleDataMap GitClient::submoduleList(const QString &workingDirectory) const SubmoduleDataMap GitClient::submoduleList(const QString &workingDirectory) const
@@ -1750,11 +1731,13 @@ bool GitClient::synchronousShow(const QString &workingDirectory, const QString &
return false; return false;
} }
const QStringList arguments = { "show", decorateOption, noColorOption, id }; const QStringList arguments = { "show", decorateOption, noColorOption, id };
QByteArray errorText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments);
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, output, &errorText); if (resp.result != SynchronousProcessResponse::Finished) {
if (!rc) msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
msgCannotRun(arguments, workingDirectory, errorText, errorMessage); return false;
return rc; }
*output = resp.rawStdOut;
return true;
} }
// Retrieve list of files to be cleaned // Retrieve list of files to be cleaned
@@ -1763,17 +1746,17 @@ bool GitClient::cleanList(const QString &workingDirectory, const QString &module
{ {
const QString directory = workingDirectory + '/' + modulePath; const QString directory = workingDirectory + '/' + modulePath;
const QStringList arguments = { "clean", "--dry-run", flag }; const QStringList arguments = { "clean", "--dry-run", flag };
QByteArray outputText;
QByteArray errorText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(directory, arguments);
const bool rc = vcsFullySynchronousExec(directory, arguments, &outputText, &errorText); if (resp.result != SynchronousProcessResponse::Finished) {
if (!rc) { msgCannotRun(arguments, directory, resp.stdErr(), errorMessage);
msgCannotRun(arguments, directory, errorText, errorMessage);
return false; return false;
} }
// Filter files that git would remove // Filter files that git would remove
const QString relativeBase = modulePath.isEmpty() ? QString() : modulePath + '/'; const QString relativeBase = modulePath.isEmpty() ? QString() : modulePath + '/';
const QString prefix = "Would remove "; const QString prefix = "Would remove ";
foreach (const QString &line, commandOutputLinesFromLocal8Bit(outputText)) { foreach (const QString &line, resp.stdOut()) {
if (line.startsWith(prefix)) if (line.startsWith(prefix))
files->push_back(relativeBase + line.mid(prefix.size())); files->push_back(relativeBase + line.mid(prefix.size()));
} }
@@ -1806,19 +1789,19 @@ bool GitClient::synchronousApplyPatch(const QString &workingDirectory,
{ {
QStringList arguments = { "apply", "--whitespace=fix" }; QStringList arguments = { "apply", "--whitespace=fix" };
arguments << extraArguments << file; arguments << extraArguments << file;
QByteArray outputText;
QByteArray errorText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments);
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputText, &errorText); const QString stdErr = resp.stdErr();
if (rc) { if (resp.result == SynchronousProcessResponse::Finished) {
if (!errorText.isEmpty()) if (!stdErr.isEmpty())
*errorMessage = tr("There were warnings while applying \"%1\" to \"%2\":\n%3") *errorMessage = tr("There were warnings while applying \"%1\" to \"%2\":\n%3")
.arg(file, workingDirectory, commandOutputFromLocal8Bit(errorText)); .arg(file, workingDirectory, stdErr);
return true;
} else { } else {
*errorMessage = tr("Cannot apply patch \"%1\" to \"%2\": %3") *errorMessage = tr("Cannot apply patch \"%1\" to \"%2\": %3")
.arg(file, workingDirectory, commandOutputFromLocal8Bit(errorText)); .arg(QDir::toNativeSeparators(file), workingDirectory, stdErr);
return false; return false;
} }
return true;
} }
QProcessEnvironment GitClient::processEnvironment() const QProcessEnvironment GitClient::processEnvironment() const
@@ -1932,8 +1915,6 @@ GitClient::StatusResult GitClient::gitStatus(const QString &workingDirectory, St
QString *output, QString *errorMessage) const QString *output, QString *errorMessage) const
{ {
// Run 'status'. Note that git returns exitcode 1 if there are no added files. // Run 'status'. Note that git returns exitcode 1 if there are no added files.
QByteArray outputText;
QByteArray errorText;
QStringList arguments = { "status" }; QStringList arguments = { "status" };
if (mode & NoUntracked) if (mode & NoUntracked)
arguments << "--untracked-files=no"; arguments << "--untracked-files=no";
@@ -1943,27 +1924,28 @@ GitClient::StatusResult GitClient::gitStatus(const QString &workingDirectory, St
arguments << "--ignore-submodules=all"; arguments << "--ignore-submodules=all";
arguments << "--porcelain" << "-b"; arguments << "--porcelain" << "-b";
const bool statusRc = vcsFullySynchronousExec(workingDirectory, arguments, const SynchronousProcessResponse resp = vcsFullySynchronousExec(
&outputText, &errorText, silentFlags); workingDirectory, arguments, silentFlags);
const QString stdOut = resp.stdOut();
if (output) if (output)
*output = commandOutputFromLocal8Bit(outputText); *output = stdOut;
static const char * NO_BRANCH = "## HEAD (no branch)\n"; const bool statusRc = resp.result == SynchronousProcessResponse::Finished;
const bool branchKnown = !stdOut.startsWith("## HEAD (no branch)\n");
const bool branchKnown = !outputText.startsWith(NO_BRANCH);
// Is it something really fatal? // Is it something really fatal?
if (!statusRc && !branchKnown) { if (!statusRc && !branchKnown) {
if (errorMessage) { if (errorMessage) {
const QString error = commandOutputFromLocal8Bit(errorText); *errorMessage = tr("Cannot obtain status: %1").arg(resp.stdErr());
*errorMessage = tr("Cannot obtain status: %1").arg(error);
} }
return StatusFailed; return StatusFailed;
} }
// Unchanged (output text depending on whether -u was passed) // Unchanged (output text depending on whether -u was passed)
QList<QByteArray> lines = outputText.split('\n'); QList<QString> lines = resp.stdOut().split('\n');
foreach (const QByteArray &line, lines) foreach (const QString &line, lines) {
if (!line.isEmpty() && !line.startsWith('#')) if (!line.isEmpty() && !line.startsWith('#'))
return StatusChanged; return StatusChanged;
}
return StatusUnchanged; return StatusUnchanged;
} }
@@ -2291,20 +2273,25 @@ bool GitClient::readDataFromCommit(const QString &repoDirectory, const QString &
{ {
// Get commit data as "SHA1<lf>author<lf>email<lf>message". // Get commit data as "SHA1<lf>author<lf>email<lf>message".
const QStringList arguments = { "log", "--max-count=1", "--pretty=format:%h\n%an\n%ae\n%B", commit }; const QStringList arguments = { "log", "--max-count=1", "--pretty=format:%h\n%an\n%ae\n%B", commit };
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(repoDirectory, arguments, silentFlags);
if (!vcsFullySynchronousExec(repoDirectory, arguments, &outputText, 0, silentFlags)) {
if (errorMessage) if (resp.result != SynchronousProcessResponse::Finished) {
*errorMessage = tr("Cannot retrieve last commit data of repository \"%1\".").arg(repoDirectory); if (errorMessage) {
*errorMessage = tr("Cannot retrieve last commit data of repository \"%1\".")
.arg(QDir::toNativeSeparators(repoDirectory));
}
return false; return false;
} }
QTextCodec *authorCodec = HostOsInfo::isWindowsHost() QTextCodec *authorCodec = HostOsInfo::isWindowsHost()
? QTextCodec::codecForName("UTF-8") ? QTextCodec::codecForName("UTF-8")
: commitData.commitEncoding; : commitData.commitEncoding;
commitData.amendSHA1 = QLatin1String(shiftLogLine(outputText)); QByteArray stdOut = resp.rawStdOut;
commitData.panelData.author = authorCodec->toUnicode(shiftLogLine(outputText)); commitData.amendSHA1 = QLatin1String(shiftLogLine(stdOut));
commitData.panelData.email = authorCodec->toUnicode(shiftLogLine(outputText)); commitData.panelData.author = authorCodec->toUnicode(shiftLogLine(stdOut));
commitData.panelData.email = authorCodec->toUnicode(shiftLogLine(stdOut));
if (commitTemplate) if (commitTemplate)
*commitTemplate = commitData.commitEncoding->toUnicode(outputText); *commitTemplate = commitData.commitEncoding->toUnicode(stdOut);
return true; return true;
} }
@@ -2539,19 +2526,16 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory,
arguments << "--no-verify"; arguments << "--no-verify";
} }
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(repositoryDirectory, arguments);
QByteArray errorText; const QString stdErr = resp.stdErr();
if (resp.result == SynchronousProcessResponse::Finished) {
const bool rc = vcsFullySynchronousExec(repositoryDirectory, arguments, &outputText, &errorText);
const QString stdErr = commandOutputFromLocal8Bit(errorText);
if (rc) {
VcsOutputWindow::appendMessage(msgCommitted(amendSHA1, commitCount)); VcsOutputWindow::appendMessage(msgCommitted(amendSHA1, commitCount));
VcsOutputWindow::appendError(stdErr); VcsOutputWindow::appendError(stdErr);
return true;
} else { } else {
VcsOutputWindow::appendError(tr("Cannot commit %n file(s): %1\n", 0, commitCount).arg(stdErr)); VcsOutputWindow::appendError(tr("Cannot commit %n file(s): %1\n", 0, commitCount).arg(stdErr));
return false;
} }
return rc;
} }
/* Revert: This function can be called with a file list (to revert single /* Revert: This function can be called with a file list (to revert single
@@ -2715,10 +2699,10 @@ void GitClient::synchronousAbortCommand(const QString &workingDir, const QString
QStringList(), QString(), nullptr, false); QStringList(), QString(), nullptr, false);
return; return;
} }
QByteArray stdOut;
vcsFullySynchronousExec(workingDir, { abortCommand, "--abort" }, &stdOut, nullptr, const SynchronousProcessResponse resp = vcsFullySynchronousExec(
VcsCommand::ExpectRepoChanges); workingDir, { abortCommand, "--abort" }, VcsCommand::ExpectRepoChanges);
VcsOutputWindow::append(commandOutputFromLocal8Bit(stdOut)); VcsOutputWindow::append(resp.stdOut());
} }
QString GitClient::synchronousTrackingBranch(const QString &workingDirectory, const QString &branch) QString GitClient::synchronousTrackingBranch(const QString &workingDirectory, const QString &branch)
@@ -2741,9 +2725,9 @@ QString GitClient::synchronousTrackingBranch(const QString &workingDirectory, co
bool GitClient::synchronousSetTrackingBranch(const QString &workingDirectory, bool GitClient::synchronousSetTrackingBranch(const QString &workingDirectory,
const QString &branch, const QString &tracking) const QString &branch, const QString &tracking)
{ {
QByteArray outputText;
return vcsFullySynchronousExec( return vcsFullySynchronousExec(
workingDirectory, { "branch", "--set-upstream-to=" + tracking, branch }, &outputText); workingDirectory, { "branch", "--set-upstream-to=" + tracking, branch }).result
== SynchronousProcessResponse::Finished;
} }
void GitClient::handleMergeConflicts(const QString &workingDir, const QString &commit, void GitClient::handleMergeConflicts(const QString &workingDir, const QString &commit,
@@ -2962,35 +2946,35 @@ bool GitClient::synchronousStashRemove(const QString &workingDirectory, const QS
arguments << "clear"; arguments << "clear";
else else
arguments << "drop" << stash; arguments << "drop" << stash;
QByteArray outputText;
QByteArray errorText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments);
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputText, &errorText); if (resp.result == SynchronousProcessResponse::Finished) {
if (rc) { const QString output = resp.stdOut();
const QString output = commandOutputFromLocal8Bit(outputText);
if (!output.isEmpty()) if (!output.isEmpty())
VcsOutputWindow::append(output); VcsOutputWindow::append(output);
return true;
} else { } else {
msgCannotRun(arguments, workingDirectory, errorText, errorMessage); msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
return false;
} }
return rc;
} }
bool GitClient::synchronousStashList(const QString &workingDirectory, QList<Stash> *stashes, bool GitClient::synchronousStashList(const QString &workingDirectory, QList<Stash> *stashes,
QString *errorMessage) const QString *errorMessage) const
{ {
stashes->clear(); stashes->clear();
QByteArray outputText;
QByteArray errorText;
const QStringList arguments = { "stash", "list", noColorOption }; const QStringList arguments = { "stash", "list", noColorOption };
const bool rc = vcsFullySynchronousExec(workingDirectory, arguments, &outputText, &errorText); const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments);
if (!rc) { if (resp.result != SynchronousProcessResponse::Finished) {
msgCannotRun(arguments, workingDirectory, errorText, errorMessage); msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage);
return false; return false;
} }
Stash stash; Stash stash;
foreach (const QString &line, commandOutputLinesFromLocal8Bit(outputText)) foreach (const QString &line, splitLines(resp.stdOut())) {
if (stash.parseStashLine(line)) if (stash.parseStashLine(line))
stashes->push_back(stash); stashes->push_back(stash);
}
return true; return true;
} }
@@ -3013,13 +2997,11 @@ QString GitClient::readOneLine(const QString &workingDirectory, const QStringLis
? QTextCodec::codecForName("UTF-8") ? QTextCodec::codecForName("UTF-8")
: QTextCodec::codecForLocale(); : QTextCodec::codecForLocale();
QByteArray outputText; const SynchronousProcessResponse resp = vcsFullySynchronousExec(
if (!vcsFullySynchronousExec(workingDirectory, arguments, &outputText, 0, silentFlags)) workingDirectory, arguments, silentFlags, vcsTimeoutS(), codec);
if (resp.result != SynchronousProcessResponse::Finished)
return QString(); return QString();
if (HostOsInfo::isWindowsHost()) return resp.stdOut().trimmed();
outputText.replace("\r\n", "\n");
return SynchronousProcess::normalizeNewlines(codec->toUnicode(outputText.trimmed()));
} }
bool GitClient::cloneRepository(const QString &directory,const QByteArray &url) bool GitClient::cloneRepository(const QString &directory,const QByteArray &url)
@@ -3032,27 +3014,25 @@ bool GitClient::cloneRepository(const QString &directory,const QByteArray &url)
if (!synchronousInit(workingDirectory.path())) if (!synchronousInit(workingDirectory.path()))
return false; return false;
if (!vcsFullySynchronousExec(workingDirectory.path(), const SynchronousProcessResponse resp = vcsFullySynchronousExec(
{ "remote", "add", "origin", QString::fromUtf8(url) }, nullptr)) { workingDirectory.path(), { "remote", "add", "origin", QString::fromUtf8(url) });
return false;
}
const SynchronousProcessResponse resp
= vcsSynchronousExec(workingDirectory.path(), { "fetch" }, flags);
if (resp.result != SynchronousProcessResponse::Finished) if (resp.result != SynchronousProcessResponse::Finished)
return false; return false;
if (!vcsFullySynchronousExec(workingDirectory.path(), const SynchronousProcessResponse resp1 = vcsSynchronousExec(
{ "config", "branch.master.remote", "origin" }, nullptr)) { workingDirectory.path(), { "fetch" }, flags);
if (resp1.result != SynchronousProcessResponse::Finished)
return false; return false;
}
if (!vcsFullySynchronousExec(workingDirectory.path(), const SynchronousProcessResponse resp2 = vcsSynchronousExec(
{ "config", "branch.master.merge", "refs/heads/master" }, nullptr)) { workingDirectory.path(), { "config", "branch.master.remote", "origin" }, flags);
if (resp2.result != SynchronousProcessResponse::Finished)
return false; return false;
}
return true; const SynchronousProcessResponse resp3 = vcsSynchronousExec(
workingDirectory.path(),
{ "config", "branch.master.merge", "refs/heads/master" }, flags);
return resp3.result == SynchronousProcessResponse::Finished;
} else { } else {
workingDirectory.cdUp(); workingDirectory.cdUp();
const SynchronousProcessResponse resp = vcsSynchronousExec( const SynchronousProcessResponse resp = vcsSynchronousExec(
@@ -3083,19 +3063,16 @@ unsigned GitClient::synchronousGitVersion(QString *errorMessage) const
return 0; return 0;
// run git --version // run git --version
QByteArray outputText; const SynchronousProcessResponse resp = vcsSynchronousExec(
QByteArray errorText; QString(), { "--version" }, silentFlags);
const bool rc = vcsFullySynchronousExec(QString(), { "--version" }, if (resp.result != SynchronousProcessResponse::Finished) {
&outputText, &errorText, silentFlags); msgCannotRun(tr("Cannot determine Git version: %1").arg(resp.stdErr()), errorMessage);
if (!rc) {
msgCannotRun(tr("Cannot determine Git version: %1")
.arg(commandOutputFromLocal8Bit(errorText)),
errorMessage);
return 0; return 0;
} }
// cut 'git version 1.6.5.1.sha' // cut 'git version 1.6.5.1.sha'
// another form: 'git version 1.9.rc1' // another form: 'git version 1.9.rc1'
const QString output = commandOutputFromLocal8Bit(outputText); const QString output = resp.stdOut();
QRegExp versionPattern("^[^\\d]+(\\d+)\\.(\\d+)\\.(\\d+|rc\\d).*$"); QRegExp versionPattern("^[^\\d]+(\\d+)\\.(\\d+)\\.(\\d+|rc\\d).*$");
QTC_ASSERT(versionPattern.isValid(), return 0); QTC_ASSERT(versionPattern.isValid(), return 0);
QTC_ASSERT(versionPattern.exactMatch(output), return 0); QTC_ASSERT(versionPattern.exactMatch(output), return 0);

View File

@@ -73,12 +73,12 @@ bool MercurialClient::manifestSync(const QString &repository, const QString &rel
// This only works when called from the repo and outputs paths relative to it. // This only works when called from the repo and outputs paths relative to it.
const QStringList args(QLatin1String("manifest")); const QStringList args(QLatin1String("manifest"));
QByteArray output; const SynchronousProcessResponse result = vcsFullySynchronousExec(repository, args);
vcsFullySynchronousExec(repository, args, &output);
const QDir repositoryDir(repository); const QDir repositoryDir(repository);
const QFileInfo needle = QFileInfo(repositoryDir, relativeFilename); const QFileInfo needle = QFileInfo(repositoryDir, relativeFilename);
const QStringList files = QString::fromLocal8Bit(output).split(QLatin1Char('\n')); const QStringList files = result.stdOut().split(QLatin1Char('\n'));
foreach (const QString &fileName, files) { foreach (const QString &fileName, files) {
const QFileInfo managedFile(repositoryDir, fileName); const QFileInfo managedFile(repositoryDir, fileName);
if (needle == managedFile) if (needle == managedFile)
@@ -96,7 +96,6 @@ bool MercurialClient::synchronousClone(const QString &workingDir,
Q_UNUSED(workingDir); Q_UNUSED(workingDir);
Q_UNUSED(extraOptions); Q_UNUSED(extraOptions);
QDir workingDirectory(srcLocation); QDir workingDirectory(srcLocation);
QByteArray output;
const unsigned flags = VcsCommand::SshPasswordPrompt | const unsigned flags = VcsCommand::SshPasswordPrompt |
VcsCommand::ShowStdOut | VcsCommand::ShowStdOut |
VcsCommand::ShowSuccessMessage; VcsCommand::ShowSuccessMessage;
@@ -104,14 +103,16 @@ bool MercurialClient::synchronousClone(const QString &workingDir,
if (workingDirectory.exists()) { if (workingDirectory.exists()) {
// Let's make first init // Let's make first init
QStringList arguments(QLatin1String("init")); QStringList arguments(QLatin1String("init"));
if (!vcsFullySynchronousExec(workingDirectory.path(), arguments, &output)) const SynchronousProcessResponse resp = vcsFullySynchronousExec(
workingDirectory.path(), arguments);
if (resp.result != SynchronousProcessResponse::Finished)
return false; return false;
// Then pull remote repository // Then pull remote repository
arguments.clear(); arguments.clear();
arguments << QLatin1String("pull") << dstLocation; arguments << QLatin1String("pull") << dstLocation;
const SynchronousProcessResponse resp1 = const SynchronousProcessResponse resp1 = vcsSynchronousExec(
vcsSynchronousExec(workingDirectory.path(), arguments, flags); workingDirectory.path(), arguments, flags);
if (resp1.result != SynchronousProcessResponse::Finished) if (resp1.result != SynchronousProcessResponse::Finished)
return false; return false;
@@ -127,15 +128,15 @@ bool MercurialClient::synchronousClone(const QString &workingDir,
// And last update repository // And last update repository
arguments.clear(); arguments.clear();
arguments << QLatin1String("update"); arguments << QLatin1String("update");
const SynchronousProcessResponse resp2 = const SynchronousProcessResponse resp2 = vcsSynchronousExec(
vcsSynchronousExec(workingDirectory.path(), arguments, flags); workingDirectory.path(), arguments, flags);
return resp2.result == SynchronousProcessResponse::Finished; return resp2.result == SynchronousProcessResponse::Finished;
} else { } else {
QStringList arguments(QLatin1String("clone")); QStringList arguments(QLatin1String("clone"));
arguments << dstLocation << workingDirectory.dirName(); arguments << dstLocation << workingDirectory.dirName();
workingDirectory.cdUp(); workingDirectory.cdUp();
const SynchronousProcessResponse resp = const SynchronousProcessResponse resp = vcsSynchronousExec(
vcsSynchronousExec(workingDirectory.path(), arguments, flags); workingDirectory.path(), arguments, flags);
return resp.result == SynchronousProcessResponse::Finished; return resp.result == SynchronousProcessResponse::Finished;
} }
} }
@@ -194,24 +195,22 @@ QStringList MercurialClient::parentRevisionsSync(const QString &workingDirectory
args << QLatin1String("parents") << QLatin1String("-r") <<revision; args << QLatin1String("parents") << QLatin1String("-r") <<revision;
if (!file.isEmpty()) if (!file.isEmpty())
args << file; args << file;
QByteArray outputData; const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, args);
if (!vcsFullySynchronousExec(workingDirectory, args, &outputData)) if (resp.result != SynchronousProcessResponse::Finished)
return QStringList(); return QStringList();
const QString output = SynchronousProcess::normalizeNewlines(
QString::fromLocal8Bit(outputData));
/* Looks like: \code /* Looks like: \code
changeset: 0:031a48610fba changeset: 0:031a48610fba
user: ... user: ...
\endcode */ \endcode */
// Obtain first line and split by blank-delimited tokens // Obtain first line and split by blank-delimited tokens
const QStringList lines = output.split(QLatin1Char('\n')); const QStringList lines = resp.stdOut().split(QLatin1Char('\n'));
if (lines.size() < 1) { if (lines.size() < 1) {
VcsOutputWindow::appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(output))); VcsOutputWindow::appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(resp.stdOut())));
return QStringList(); return QStringList();
} }
QStringList changeSets = lines.front().simplified().split(QLatin1Char(' ')); QStringList changeSets = lines.front().simplified().split(QLatin1Char(' '));
if (changeSets.size() < 2) { if (changeSets.size() < 2) {
VcsOutputWindow::appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(output))); VcsOutputWindow::appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(resp.stdOut())));
return QStringList(); return QStringList();
} }
// Remove revision numbers // Remove revision numbers
@@ -231,18 +230,15 @@ QString MercurialClient::shortDescriptionSync(const QString &workingDirectory,
const QString &revision, const QString &revision,
const QString &format) const QString &format)
{ {
QString description;
QStringList args; QStringList args;
args << QLatin1String("log") << QLatin1String("-r") <<revision; args << QLatin1String("log") << QLatin1String("-r") <<revision;
if (!format.isEmpty()) if (!format.isEmpty())
args << QLatin1String("--template") << format; args << QLatin1String("--template") << format;
QByteArray outputData;
if (!vcsFullySynchronousExec(workingDirectory, args, &outputData)) const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, args);
if (resp.result != SynchronousProcessResponse::Finished)
return revision; return revision;
description = commandOutputFromLocal8Bit(outputData); return stripLastNewline(resp.stdOut());
if (description.endsWith(QLatin1Char('\n')))
description.truncate(description.size() - 1);
return description;
} }
// Default format: "SHA1 (author summmary)" // Default format: "SHA1 (author summmary)"
@@ -258,9 +254,7 @@ bool MercurialClient::managesFile(const QString &workingDirectory, const QString
{ {
QStringList args; QStringList args;
args << QLatin1String("status") << QLatin1String("--unknown") << fileName; args << QLatin1String("status") << QLatin1String("--unknown") << fileName;
QByteArray output; return vcsFullySynchronousExec(workingDirectory, args).stdOut().isEmpty();
vcsFullySynchronousExec(workingDirectory, args, &output);
return output.isEmpty();
} }
void MercurialClient::incoming(const QString &repositoryRoot, const QString &repository) void MercurialClient::incoming(const QString &repositoryRoot, const QString &repository)

View File

@@ -138,14 +138,13 @@ QString SubversionClient::synchronousTopic(const QString &repository)
QStringList args; QStringList args;
args << QLatin1String("info"); args << QLatin1String("info");
QByteArray stdOut; const SynchronousProcessResponse result = vcsFullySynchronousExec(repository, args);
if (!vcsFullySynchronousExec(repository, args, &stdOut)) if (result.result != SynchronousProcessResponse::Finished)
return QString(); return QString();
const QString revisionString = QLatin1String("Revision: "); const QString revisionString = QLatin1String("Revision: ");
// stdOut is ASCII only (at least in those areas we care about). // stdOut is ASCII only (at least in those areas we care about).
QString output = commandOutputFromLocal8Bit(stdOut); foreach (const QString &line, result.stdOut().split(QLatin1Char('\n'))) {
foreach (const QString &line, output.split(QLatin1Char('\n'))) {
if (line.startsWith(revisionString)) if (line.startsWith(revisionString))
return QString::fromLatin1("r") + line.mid(revisionString.count()); return QString::fromLatin1("r") + line.mid(revisionString.count());
} }

View File

@@ -877,21 +877,19 @@ SubversionResponse SubversionPlugin::runSvn(const QString &workingDir,
int timeOutS, unsigned flags, int timeOutS, unsigned flags,
QTextCodec *outputCodec) const QTextCodec *outputCodec) const
{ {
const FileName executable = client()->vcsBinary();
SubversionResponse response; SubversionResponse response;
if (executable.isEmpty()) { if (client()->vcsBinary().isEmpty()) {
response.error = true; response.error = true;
response.message =tr("No subversion executable specified."); response.message =tr("No subversion executable specified.");
return response; return response;
} }
const SynchronousProcessResponse sp_resp = const SynchronousProcessResponse sp_resp
VcsBasePlugin::runVcs(workingDir, executable, arguments, timeOutS, = client()->vcsFullySynchronousExec(workingDir, arguments, flags, timeOutS, outputCodec);
flags, outputCodec);
response.error = sp_resp.result != SynchronousProcessResponse::Finished; response.error = sp_resp.result != SynchronousProcessResponse::Finished;
if (response.error) if (response.error)
response.message = sp_resp.exitMessage(executable.toString(), timeOutS); response.message = sp_resp.exitMessage(client()->vcsBinary().toString(), timeOutS);
response.stdErr = sp_resp.stdErr(); response.stdErr = sp_resp.stdErr();
response.stdOut = sp_resp.stdOut(); response.stdOut = sp_resp.stdOut();
return response; return response;

View File

@@ -155,8 +155,13 @@ QString VcsBaseClientImpl::commandOutputFromLocal8Bit(const QByteArray &a)
QStringList VcsBaseClientImpl::commandOutputLinesFromLocal8Bit(const QByteArray &a) QStringList VcsBaseClientImpl::commandOutputLinesFromLocal8Bit(const QByteArray &a)
{ {
QString output = commandOutputFromLocal8Bit(a); return splitLines(commandOutputFromLocal8Bit(a));
}
QStringList VcsBaseClientImpl::splitLines(const QString &s)
{
const QChar newLine = QLatin1Char('\n'); const QChar newLine = QLatin1Char('\n');
QString output = s;
if (output.endsWith(newLine)) if (output.endsWith(newLine))
output.truncate(output.size() - 1); output.truncate(output.size() - 1);
if (output.isEmpty()) if (output.isEmpty())
@@ -164,6 +169,13 @@ QStringList VcsBaseClientImpl::commandOutputLinesFromLocal8Bit(const QByteArray
return output.split(newLine); return output.split(newLine);
} }
QString VcsBaseClientImpl::stripLastNewline(const QString &in)
{
if (in.endsWith('\n'))
return in.left(in.count() - 1);
return in;
}
void VcsBaseClientImpl::resetCachedVcsInfo(const QString &workingDir) void VcsBaseClientImpl::resetCachedVcsInfo(const QString &workingDir)
{ {
Core::VcsManager::resetVersionControlForDirectory(workingDir); Core::VcsManager::resetVersionControlForDirectory(workingDir);
@@ -182,18 +194,15 @@ void VcsBaseClientImpl::annotateRevisionRequested(const QString &workingDirector
annotate(workingDirectory, file, changeCopy, line); annotate(workingDirectory, file, changeCopy, line);
} }
bool VcsBaseClientImpl::vcsFullySynchronousExec(const QString &workingDir, const QStringList &args, Utils::SynchronousProcessResponse
QByteArray *outputData, QByteArray *errorData, VcsBaseClientImpl::vcsFullySynchronousExec(const QString &workingDir, const QStringList &args,
unsigned flags) const unsigned flags, int timeoutS, QTextCodec *codec) const
{ {
QByteArray internalErrorData; VcsCommand command(workingDir, processEnvironment());
QScopedPointer<VcsCommand> command(createCommand(workingDir)); command.addFlags(flags);
command->addFlags(flags); if (codec)
bool result = command->runFullySynchronous(vcsBinary(), args, vcsTimeoutS(), outputData, command.setCodec(codec);
errorData ? errorData : &internalErrorData); return command.runCommand(vcsBinary(), args, (timeoutS > 0) ? timeoutS : vcsTimeoutS());
if (!internalErrorData.isEmpty() && !(flags & VcsCommand::SuppressStdErr))
VcsOutputWindow::appendError(commandOutputFromLocal8Bit(internalErrorData));
return result;
} }
VcsCommand *VcsBaseClientImpl::vcsExec(const QString &workingDirectory, const QStringList &arguments, VcsCommand *VcsBaseClientImpl::vcsExec(const QString &workingDirectory, const QStringList &arguments,
@@ -300,10 +309,10 @@ bool VcsBaseClient::synchronousCreateRepository(const QString &workingDirectory,
{ {
QStringList args(vcsCommandString(CreateRepositoryCommand)); QStringList args(vcsCommandString(CreateRepositoryCommand));
args << extraOptions; args << extraOptions;
QByteArray outputData; Utils::SynchronousProcessResponse result = vcsFullySynchronousExec(workingDirectory, args);
if (!vcsFullySynchronousExec(workingDirectory, args, &outputData)) if (result.result != Utils::SynchronousProcessResponse::Finished)
return false; return false;
VcsOutputWindow::append(commandOutputFromLocal8Bit(outputData)); VcsOutputWindow::append(result.stdOut());
resetCachedVcsInfo(workingDirectory); resetCachedVcsInfo(workingDirectory);
@@ -318,10 +327,10 @@ bool VcsBaseClient::synchronousClone(const QString &workingDir,
QStringList args; QStringList args;
args << vcsCommandString(CloneCommand) args << vcsCommandString(CloneCommand)
<< extraOptions << srcLocation << dstLocation; << extraOptions << srcLocation << dstLocation;
QByteArray stdOut;
const bool cloneOk = vcsFullySynchronousExec(workingDir, args, &stdOut); Utils::SynchronousProcessResponse result = vcsFullySynchronousExec(workingDir, args);
resetCachedVcsInfo(workingDir); resetCachedVcsInfo(workingDir);
return cloneOk; return result.result == Utils::SynchronousProcessResponse::Finished;
} }
bool VcsBaseClient::synchronousAdd(const QString &workingDir, const QString &filename, bool VcsBaseClient::synchronousAdd(const QString &workingDir, const QString &filename,
@@ -329,8 +338,7 @@ bool VcsBaseClient::synchronousAdd(const QString &workingDir, const QString &fil
{ {
QStringList args; QStringList args;
args << vcsCommandString(AddCommand) << extraOptions << filename; args << vcsCommandString(AddCommand) << extraOptions << filename;
QByteArray stdOut; return vcsFullySynchronousExec(workingDir, args).result == Utils::SynchronousProcessResponse::Finished;
return vcsFullySynchronousExec(workingDir, args, &stdOut);
} }
bool VcsBaseClient::synchronousRemove(const QString &workingDir, const QString &filename, bool VcsBaseClient::synchronousRemove(const QString &workingDir, const QString &filename,
@@ -338,8 +346,7 @@ bool VcsBaseClient::synchronousRemove(const QString &workingDir, const QString &
{ {
QStringList args; QStringList args;
args << vcsCommandString(RemoveCommand) << extraOptions << filename; args << vcsCommandString(RemoveCommand) << extraOptions << filename;
QByteArray stdOut; return vcsFullySynchronousExec(workingDir, args).result == Utils::SynchronousProcessResponse::Finished;
return vcsFullySynchronousExec(workingDir, args, &stdOut);
} }
bool VcsBaseClient::synchronousMove(const QString &workingDir, bool VcsBaseClient::synchronousMove(const QString &workingDir,
@@ -348,8 +355,7 @@ bool VcsBaseClient::synchronousMove(const QString &workingDir,
{ {
QStringList args; QStringList args;
args << vcsCommandString(MoveCommand) << extraOptions << from << to; args << vcsCommandString(MoveCommand) << extraOptions << from << to;
QByteArray stdOut; return vcsFullySynchronousExec(workingDir, args).result == Utils::SynchronousProcessResponse::Finished;
return vcsFullySynchronousExec(workingDir, args, &stdOut);
} }
bool VcsBaseClient::synchronousPull(const QString &workingDir, bool VcsBaseClient::synchronousPull(const QString &workingDir,

View File

@@ -95,28 +95,31 @@ public:
static QString commandOutputFromLocal8Bit(const QByteArray &a); static QString commandOutputFromLocal8Bit(const QByteArray &a);
// Return converted command output split into lines // Return converted command output split into lines
static QStringList commandOutputLinesFromLocal8Bit(const QByteArray &a); static QStringList commandOutputLinesFromLocal8Bit(const QByteArray &a);
static QStringList splitLines(const QString &s);
static QString stripLastNewline(const QString &in);
// Fully synchronous VCS execution (QProcess-based)
Utils::SynchronousProcessResponse
vcsFullySynchronousExec(const QString &workingDir, const QStringList &args,
unsigned flags = 0, int timeoutS = -1, QTextCodec *codec = nullptr) const;
// Simple helper to execute a single command using createCommand and enqueueJob.
VcsCommand *vcsExec(const QString &workingDirectory, const QStringList &arguments,
VcsBaseEditorWidget *editor = nullptr, bool useOutputToWindow = false,
unsigned additionalFlags = 0, const QVariant &cookie = QVariant()) const;
protected: protected:
void resetCachedVcsInfo(const QString &workingDir); void resetCachedVcsInfo(const QString &workingDir);
virtual void annotateRevisionRequested(const QString &workingDirectory, const QString &file, virtual void annotateRevisionRequested(const QString &workingDirectory, const QString &file,
const QString &change, int line); const QString &change, int line);
// Fully synchronous VCS execution (QProcess-based)
bool vcsFullySynchronousExec(const QString &workingDir, const QStringList &args,
QByteArray *outputData, QByteArray *errorData = 0,
unsigned flags = 0) const;
// Simple helper to execute a single command using createCommand and enqueueJob.
VcsCommand *vcsExec(const QString &workingDirectory, const QStringList &arguments,
VcsBaseEditorWidget *editor = 0, bool useOutputToWindow = false,
unsigned additionalFlags = 0, const QVariant &cookie = QVariant()) const;
// Synchronous VCS execution using Utils::SynchronousProcess, with // Synchronous VCS execution using Utils::SynchronousProcess, with
// log windows updating (using VcsBasePlugin::runVcs with flags) // log windows updating (using VcsBasePlugin::runVcs with flags)
Utils::SynchronousProcessResponse vcsSynchronousExec(const QString &workingDir, Utils::SynchronousProcessResponse vcsSynchronousExec(const QString &workingDir,
const QStringList &args, const QStringList &args,
unsigned flags = 0, unsigned flags = 0,
QTextCodec *outputCodec = 0) const; QTextCodec *outputCodec = nullptr) const;
private: private:
void saveSettings(); void saveSettings();