Git: Do not run 'git --version' synchronously at startup

We can easily delay this, and if git acts up for some reason, we don't
have to block startup.

Task-number: QTCREATORBUG-27765
Change-Id: I25aa6f8d04d1fd4b9d87f8ccf7ffd591f7bbe519
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
Eike Ziller
2022-06-29 10:21:12 +02:00
parent 70fb66f9ee
commit f4c60fdf58
4 changed files with 62 additions and 48 deletions

View File

@@ -648,7 +648,7 @@ public:
static bool gitHasRgbColors() static bool gitHasRgbColors()
{ {
const unsigned gitVersion = GitClient::instance()->gitVersion(); const unsigned gitVersion = GitClient::instance()->gitVersion().result();
return gitVersion >= 0x020300U; return gitVersion >= 0x020300U;
} }
@@ -3611,36 +3611,10 @@ QString GitClient::readOneLine(const FilePath &workingDirectory, const QStringLi
return proc.cleanedStdOut().trimmed(); return proc.cleanedStdOut().trimmed();
} }
// determine version as '(major << 16) + (minor << 8) + patch' or 0. static unsigned parseGitVersion(const QString &output)
unsigned GitClient::gitVersion(QString *errorMessage) const
{ {
const FilePath newGitBinary = vcsBinary();
if (m_gitVersionForBinary != newGitBinary && !newGitBinary.isEmpty()) {
// Do not execute repeatedly if that fails (due to git
// not being installed) until settings are changed.
m_cachedGitVersion = synchronousGitVersion(errorMessage);
m_gitVersionForBinary = newGitBinary;
}
return m_cachedGitVersion;
}
// determine version as '(major << 16) + (minor << 8) + patch' or 0.
unsigned GitClient::synchronousGitVersion(QString *errorMessage) const
{
if (vcsBinary().isEmpty())
return 0;
// run git --version
QtcProcess proc;
vcsSynchronousExec(proc, {}, {"--version"}, silentFlags);
if (proc.result() != ProcessResult::FinishedWithSuccess) {
msgCannotRun(tr("Cannot determine Git version: %1").arg(proc.cleanedStdErr()), errorMessage);
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 = proc.cleanedStdOut();
const QRegularExpression versionPattern("^[^\\d]+(\\d+)\\.(\\d+)\\.(\\d+|rc\\d).*$"); const QRegularExpression versionPattern("^[^\\d]+(\\d+)\\.(\\d+)\\.(\\d+|rc\\d).*$");
QTC_ASSERT(versionPattern.isValid(), return 0); QTC_ASSERT(versionPattern.isValid(), return 0);
const QRegularExpressionMatch match = versionPattern.match(output); const QRegularExpressionMatch match = versionPattern.match(output);
@@ -3651,6 +3625,41 @@ unsigned GitClient::synchronousGitVersion(QString *errorMessage) const
return version(majorV, minorV, patchV); return version(majorV, minorV, patchV);
} }
// determine version as '(major << 16) + (minor << 8) + patch' or 0.
QFuture<unsigned> GitClient::gitVersion() const
{
QFutureInterface<unsigned> fi;
fi.reportStarted();
// Do not execute repeatedly if that fails (due to git
// not being installed) until settings are changed.
const FilePath newGitBinary = vcsBinary();
const bool needToRunGit = m_gitVersionForBinary != newGitBinary && !newGitBinary.isEmpty();
if (needToRunGit) {
auto proc = new QtcProcess(const_cast<GitClient *>(this));
connect(proc, &QtcProcess::done, this, [this, proc, fi, newGitBinary]() mutable {
if (proc->result() == ProcessResult::FinishedWithSuccess) {
m_cachedGitVersion = parseGitVersion(proc->cleanedStdOut());
m_gitVersionForBinary = newGitBinary;
fi.reportResult(m_cachedGitVersion);
fi.reportFinished();
}
proc->deleteLater();
});
proc->setTimeoutS(vcsTimeoutS());
proc->setEnvironment(processEnvironment());
proc->setCommand({newGitBinary, {"--version"}});
proc->start();
} else {
// already cached
fi.reportResult(m_cachedGitVersion);
fi.reportFinished();
}
return fi.future();
}
bool GitClient::StashInfo::init(const FilePath &workingDirectory, const QString &command, bool GitClient::StashInfo::init(const FilePath &workingDirectory, const QString &command,
StashFlag flag, PushAction pushAction) StashFlag flag, PushAction pushAction)
{ {

View File

@@ -145,7 +145,7 @@ public:
static GitSettings &settings(); static GitSettings &settings();
Utils::FilePath vcsBinary() const override; Utils::FilePath vcsBinary() const override;
unsigned gitVersion(QString *errorMessage = nullptr) const; QFuture<unsigned> gitVersion() const;
VcsBase::VcsCommand *vcsExecAbortable(const Utils::FilePath &workingDirectory, VcsBase::VcsCommand *vcsExecAbortable(const Utils::FilePath &workingDirectory,
const QStringList &arguments, const QStringList &arguments,
@@ -387,9 +387,6 @@ private:
const Utils::FilePath &workingDirectory, const Utils::FilePath &workingDirectory,
std::function<GitBaseDiffEditorController *(Core::IDocument *)> factory) const; std::function<GitBaseDiffEditorController *(Core::IDocument *)> factory) const;
// determine version as '(major << 16) + (minor << 8) + patch' or 0.
unsigned synchronousGitVersion(QString *errorMessage = nullptr) const;
QString readOneLine(const Utils::FilePath &workingDirectory, const QStringList &arguments) const; QString readOneLine(const Utils::FilePath &workingDirectory, const QStringList &arguments) const;
enum RevertResult { RevertOk, RevertUnchanged, RevertCanceled, RevertFailed }; enum RevertResult { RevertOk, RevertUnchanged, RevertCanceled, RevertFailed };

View File

@@ -247,10 +247,15 @@ GitGrep::GitGrep(GitClient *client)
const QRegularExpression refExpression("[\\S]*"); const QRegularExpression refExpression("[\\S]*");
m_treeLineEdit->setValidator(new QRegularExpressionValidator(refExpression, this)); m_treeLineEdit->setValidator(new QRegularExpressionValidator(refExpression, this));
layout->addWidget(m_treeLineEdit); layout->addWidget(m_treeLineEdit);
if (client->gitVersion() >= 0x021300) { // asynchronously check git version, add "recurse submodules" option if available
m_recurseSubmodules = new QCheckBox(tr("Recurse submodules")); Utils::onResultReady(client->gitVersion(),
layout->addWidget(m_recurseSubmodules); this,
} [this, pLayout = QPointer<QHBoxLayout>(layout)](unsigned version) {
if (version >= 0x021300 && pLayout) {
m_recurseSubmodules = new QCheckBox(tr("Recurse submodules"));
pLayout->addWidget(m_recurseSubmodules);
}
});
TextEditor::FindInFiles *findInFiles = TextEditor::FindInFiles::instance(); TextEditor::FindInFiles *findInFiles = TextEditor::FindInFiles::instance();
QTC_ASSERT(findInFiles, return); QTC_ASSERT(findInFiles, return);
connect(findInFiles, &TextEditor::FindInFiles::pathChanged, connect(findInFiles, &TextEditor::FindInFiles::pathChanged,

View File

@@ -66,6 +66,7 @@
#include <utils/parameteraction.h> #include <utils/parameteraction.h>
#include <utils/pathchooser.h> #include <utils/pathchooser.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <utils/stringutils.h> #include <utils/stringutils.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
@@ -1367,20 +1368,22 @@ void GitPluginPrivate::startCommit(CommitType commitType)
void GitPluginPrivate::updateVersionWarning() void GitPluginPrivate::updateVersionWarning()
{ {
unsigned version = m_gitClient.gitVersion(); QPointer<IDocument> curDocument = EditorManager::currentDocument();
if (!version || version >= minimumRequiredVersion)
return;
IDocument *curDocument = EditorManager::currentDocument();
if (!curDocument) if (!curDocument)
return; return;
InfoBar *infoBar = curDocument->infoBar(); Utils::onResultReady(m_gitClient.gitVersion(), this, [curDocument](unsigned version) {
Id gitVersionWarning("GitVersionWarning"); if (!curDocument || !version || version >= minimumRequiredVersion)
if (!infoBar->canInfoBeAdded(gitVersionWarning)) return;
return; InfoBar *infoBar = curDocument->infoBar();
infoBar->addInfo(InfoBarEntry(gitVersionWarning, Id gitVersionWarning("GitVersionWarning");
tr("Unsupported version of Git found. Git %1 or later required.") if (!infoBar->canInfoBeAdded(gitVersionWarning))
.arg(versionString(minimumRequiredVersion)), return;
InfoBarEntry::GlobalSuppression::Enabled)); infoBar->addInfo(
InfoBarEntry(gitVersionWarning,
tr("Unsupported version of Git found. Git %1 or later required.")
.arg(versionString(minimumRequiredVersion)),
InfoBarEntry::GlobalSuppression::Enabled));
});
} }
IEditor *GitPluginPrivate::openSubmitEditor(const QString &fileName, const CommitData &cd) IEditor *GitPluginPrivate::openSubmitEditor(const QString &fileName, const CommitData &cd)