forked from qt-creator/qt-creator
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:
@@ -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 ¶meters)
|
||||||
const TextEditor::FileFindParameters ¶meters) :
|
: 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 ¶meters,
|
QFuture<FileSearchResultList> GitGrep::executeSearch(const TextEditor::FileFindParameters ¶meters,
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user