GitGrep: Do not access global state from non-main thread

- VcsCommand calls into VcsOutputWindow at construction, so we need to
  construct it in the main thread
- VcsCommand may not call into global settings from runCommand, so we
  need to store the ssh prompt command
- accessing the GitClient singleton in a non-main thread is not
  thread-safe

Change-Id: I3dcdff8091c2dcea1c165ce5b3eca5ef62d474fd
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Eike Ziller
2021-06-07 12:23:19 +02:00
parent 93fcf5c91f
commit ee61b09b21
3 changed files with 29 additions and 30 deletions

View File

@@ -71,17 +71,17 @@ namespace {
const char GitGrepRef[] = "GitGrepRef"; const char GitGrepRef[] = "GitGrepRef";
class GitGrepRunner : public QObject class GitGrepRunner
{ {
using FutureInterfaceType = QFutureInterface<FileSearchResultList>; using FutureInterfaceType = QFutureInterface<FileSearchResultList>;
public: public:
GitGrepRunner(FutureInterfaceType &fi, GitGrepRunner(const TextEditor::FileFindParameters &parameters)
const TextEditor::FileFindParameters &parameters) : : m_parameters(parameters)
m_fi(fi),
m_parameters(parameters)
{ {
m_directory = parameters.additionalParameters.toString(); m_directory = parameters.additionalParameters.toString();
m_command.reset(GitClient::instance()->createCommand(m_directory));
m_vcsBinary = GitClient::instance()->vcsBinary();
} }
struct Match struct Match
@@ -144,19 +144,20 @@ public:
} }
} }
void read(const QString &text) void read(FutureInterfaceType &fi, const QString &text)
{ {
FileSearchResultList resultList; FileSearchResultList resultList;
QString t = text; QString t = text;
QTextStream stream(&t); QTextStream stream(&t);
while (!stream.atEnd() && !m_fi.isCanceled()) while (!stream.atEnd() && !fi.isCanceled())
processLine(stream.readLine(), &resultList); processLine(stream.readLine(), &resultList);
if (!resultList.isEmpty()) if (!resultList.isEmpty())
m_fi.reportResult(resultList); fi.reportResult(resultList);
} }
void exec() void operator()(FutureInterfaceType &fi)
{ {
Core::ProgressTimer progress(fi, 5);
QStringList arguments = { QStringList arguments = {
"-c", "color.grep.match=bold red", "-c", "color.grep.match=bold red",
"-c", "color.grep=always", "-c", "color.grep=always",
@@ -186,22 +187,25 @@ public:
return QString(":!" + filter); return QString(":!" + filter);
}); });
arguments << "--" << filterArgs << exclusionArgs; arguments << "--" << filterArgs << exclusionArgs;
QScopedPointer<VcsCommand> command(GitClient::instance()->createCommand(m_directory)); m_command->addFlags(VcsCommand::SilentOutput | VcsCommand::SuppressFailMessage);
command->addFlags(VcsCommand::SilentOutput | VcsCommand::SuppressFailMessage); m_command->setProgressiveOutput(true);
command->setProgressiveOutput(true);
QFutureWatcher<FileSearchResultList> watcher; QFutureWatcher<FileSearchResultList> watcher;
connect(&watcher, &QFutureWatcher<FileSearchResultList>::canceled, QObject::connect(&watcher,
command.data(), &VcsCommand::cancel); &QFutureWatcher<FileSearchResultList>::canceled,
watcher.setFuture(m_fi.future()); m_command.get(),
connect(command.data(), &VcsCommand::stdOutText, this, &GitGrepRunner::read); &VcsCommand::cancel);
watcher.setFuture(fi.future());
QObject::connect(m_command.get(),
&VcsCommand::stdOutText,
[this, &fi](const QString &text) { read(fi, text); });
SynchronousProcess proc; SynchronousProcess proc;
proc.setTimeoutS(0); proc.setTimeoutS(0);
command->runCommand(proc, {GitClient::instance()->vcsBinary(), arguments}); m_command->runCommand(proc, {m_vcsBinary, arguments});
switch (proc.result()) { switch (proc.result()) {
case QtcProcess::TerminatedAbnormally: case QtcProcess::TerminatedAbnormally:
case QtcProcess::StartFailed: case QtcProcess::StartFailed:
case QtcProcess::Hang: case QtcProcess::Hang:
m_fi.reportCanceled(); fi.reportCanceled();
break; break;
case QtcProcess::FinishedWithSuccess: case QtcProcess::FinishedWithSuccess:
case QtcProcess::FinishedWithError: case QtcProcess::FinishedWithError:
@@ -211,19 +215,12 @@ public:
} }
} }
static void run(QFutureInterface<FileSearchResultList> &fi,
TextEditor::FileFindParameters parameters)
{
GitGrepRunner runner(fi, parameters);
Core::ProgressTimer progress(fi, 5);
runner.exec();
}
private: private:
FutureInterfaceType m_fi; FilePath m_vcsBinary;
QString m_directory; QString m_directory;
QString m_ref; QString m_ref;
const TextEditor::FileFindParameters &m_parameters; TextEditor::FileFindParameters m_parameters;
std::unique_ptr<VcsCommand> m_command;
}; };
} // namespace } // namespace
@@ -308,7 +305,7 @@ void GitGrep::writeSettings(QSettings *settings) const
QFuture<FileSearchResultList> GitGrep::executeSearch(const TextEditor::FileFindParameters &parameters, QFuture<FileSearchResultList> GitGrep::executeSearch(const TextEditor::FileFindParameters &parameters,
TextEditor::BaseFileFind * /*baseFileFind*/) TextEditor::BaseFileFind * /*baseFileFind*/)
{ {
auto future = Utils::runAsync(GitGrepRunner::run, parameters); auto future = Utils::runAsync(GitGrepRunner(parameters));
m_futureSynchronizer.addFuture(future); m_futureSynchronizer.addFuture(future);
return future; return future;
} }

View File

@@ -43,6 +43,7 @@ VcsCommand::VcsCommand(const QString &workingDirectory, const Environment &envir
VcsOutputWindow::setRepository(workingDirectory); VcsOutputWindow::setRepository(workingDirectory);
setDisableUnixTerminal(); setDisableUnixTerminal();
m_outputWindow = VcsOutputWindow::instance(); m_outputWindow = VcsOutputWindow::instance();
m_sshPrompt = VcsBase::sshPrompt();
connect(this, &VcsCommand::started, this, [this] { connect(this, &VcsCommand::started, this, [this] {
if (flags() & ExpectRepoChanges) if (flags() & ExpectRepoChanges)
@@ -57,7 +58,7 @@ VcsCommand::VcsCommand(const QString &workingDirectory, const Environment &envir
const Environment VcsCommand::processEnvironment() const const Environment VcsCommand::processEnvironment() const
{ {
Environment env = Core::ShellCommand::processEnvironment(); Environment env = Core::ShellCommand::processEnvironment();
VcsBase::setProcessEnvironment(&env, flags() & ForceCLocale, VcsBase::sshPrompt()); VcsBase::setProcessEnvironment(&env, flags() & ForceCLocale, m_sshPrompt);
return env; return env;
} }

View File

@@ -63,6 +63,7 @@ private:
void coreAboutToClose() override; void coreAboutToClose() override;
QString m_sshPrompt;
bool m_preventRepositoryChanged; bool m_preventRepositoryChanged;
VcsOutputWindow *m_outputWindow = nullptr; VcsOutputWindow *m_outputWindow = nullptr;
}; };