From bc22de5f0ae7795561673bf91e9bd5f532e7f4b0 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 19 Jun 2017 16:07:25 +0200 Subject: [PATCH] ProjectExplorer: Do not use version manager cache in threads Do not use VcsManager's cache of version control systems from different threads. Iterate over all IVersionControls instead of getting the specific version control for a directory. This is less exact, but will probably not hurt users. Task-number: QTCREATORBUG-18258 Change-Id: Iae2be5735a0d7ecc8d774904f6681963fca1d114 Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/treescanner.cpp | 20 +++++++++----- src/plugins/cmakeprojectmanager/treescanner.h | 6 ++++- src/plugins/coreplugin/iversioncontrol.h | 2 ++ src/plugins/nim/project/nimproject.cpp | 9 +++++-- src/plugins/projectexplorer/projectnodes.cpp | 27 +++++++++++++------ src/plugins/projectexplorer/projectnodes.h | 8 ++++++ 6 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/treescanner.cpp b/src/plugins/cmakeprojectmanager/treescanner.cpp index 6951221dd89..83fae4070eb 100644 --- a/src/plugins/cmakeprojectmanager/treescanner.cpp +++ b/src/plugins/cmakeprojectmanager/treescanner.cpp @@ -25,6 +25,8 @@ #include "treescanner.h" +#include +#include #include #include @@ -67,7 +69,10 @@ bool TreeScanner::asyncScanForFiles(const Utils::FileName &directory) m_scanFuture = fi->future(); m_futureWatcher.setFuture(m_scanFuture); - Utils::runAsync([this, fi, directory]() { TreeScanner::scanForFiles(fi, directory, m_filter, m_factory); }); + if (m_versionControls.isEmpty()) + m_versionControls = Core::VcsManager::versionControls(); + + Utils::runAsync([this, fi, directory]() { TreeScanner::scanForFiles(fi, directory, m_filter, m_factory, m_versionControls); }); return true; } @@ -144,13 +149,17 @@ FileType TreeScanner::genericFileType(const Utils::MimeType &mimeType, const Uti return Node::fileTypeForMimeType(mimeType); } -void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& directory, const FileFilter &filter, const FileTypeFactory &factory) +void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& directory, + const FileFilter &filter, const FileTypeFactory &factory, + QList &versionControls) { std::unique_ptr fip(fi); fip->reportStarted(); - Result nodes = FileNode::scanForFiles(directory, - [&filter, &factory](const Utils::FileName &fn) -> FileNode * { + Result nodes + = FileNode::scanForFilesWithVersionControls( + directory, + [&filter, &factory](const Utils::FileName &fn) -> FileNode * { QTC_ASSERT(!fn.isEmpty(), return nullptr); const Utils::MimeType mimeType = Utils::mimeTypeForFile(fn.toString()); @@ -166,8 +175,7 @@ void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& direc type = factory(mimeType, fn); return new FileNode(fn, type, false); - }, - fip.get()); + }, versionControls, fip.get()); // Clean up nodes and keep it sorted Result tmp = Utils::filtered(nodes, [](const FileNode *fn) -> bool { diff --git a/src/plugins/cmakeprojectmanager/treescanner.h b/src/plugins/cmakeprojectmanager/treescanner.h index 33b4522a204..146076f1f2a 100644 --- a/src/plugins/cmakeprojectmanager/treescanner.h +++ b/src/plugins/cmakeprojectmanager/treescanner.h @@ -36,6 +36,8 @@ #include +namespace Core { class IVersionControl; } + namespace CMakeProjectManager { namespace Internal { @@ -86,7 +88,8 @@ signals: private: static void scanForFiles(FutureInterface *fi, const Utils::FileName &directory, - const FileFilter &filter, const FileTypeFactory &factory); + const FileFilter &filter, const FileTypeFactory &factory, + QList &versionControls); private: FileFilter m_filter; @@ -94,6 +97,7 @@ private: FutureWatcher m_futureWatcher; Future m_scanFuture; + QList m_versionControls; }; } // namespace Internal diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index eb880e7c70f..eddcee4ff37 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -100,6 +100,8 @@ public: * * It will return true only for exact matches of the name, not for e.g. files in a * directory owned by the version control system (e.g. .git/control). + * + * This method needs to be thread safe! */ virtual bool isVcsFileOrDirectory(const Utils::FileName &fileName) const = 0; diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp index 5db9fd554a3..8910bd42af6 100644 --- a/src/plugins/nim/project/nimproject.cpp +++ b/src/plugins/nim/project/nimproject.cpp @@ -31,6 +31,8 @@ #include "../nimconstants.h" #include +#include +#include #include #include #include @@ -113,8 +115,11 @@ void NimProject::collectProjectFiles() m_lastProjectScan.start(); QTC_ASSERT(!m_futureWatcher.future().isRunning(), return); FileName prjDir = projectDirectory(); - QFuture> future = Utils::runAsync([prjDir] { - return FileNode::scanForFiles(prjDir, [](const FileName &fn) { return new FileNode(fn, FileType::Source, false); }); + const QList versionControls = Core::VcsManager::versionControls(); + QFuture> future = Utils::runAsync([prjDir, versionControls] { + return FileNode::scanForFilesWithVersionControls( + prjDir, [](const FileName &fn) { return new FileNode(fn, FileType::Source, false); }, + versionControls); }); m_futureWatcher.setFuture(future); Core::ProgressManager::addTask(future, tr("Scanning for Nim files"), "Nim.Project.Scan"); diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index aa619aa4263..741dc394e71 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -339,7 +339,8 @@ FileType FileNode::fileType() const static QList scanForFilesRecursively(const Utils::FileName &directory, const std::function factory, QSet &visited, QFutureInterface> *future, - double progressStart, double progressRange) + double progressStart, double progressRange, + const QList &versionControls) { QList result; @@ -351,8 +352,6 @@ static QList scanForFilesRecursively(const Utils::FileName &director if (visitedCount == visited.count()) return result; - const Core::IVersionControl *vcsControl - = Core::VcsManager::findVersionControlForDirectory(baseDir.absolutePath(), nullptr); const QList entries = baseDir.entryInfoList(QStringList(), QDir::AllEntries|QDir::NoDotAndDotDot); double progress = 0; const double progressIncrement = progressRange / static_cast(entries.count()); @@ -362,9 +361,11 @@ static QList scanForFilesRecursively(const Utils::FileName &director return result; const Utils::FileName entryName = Utils::FileName::fromString(entry.absoluteFilePath()); - if (!vcsControl || !vcsControl->isVcsFileOrDirectory(entryName)) { + if (!Utils::contains(versionControls, [&entryName](const Core::IVersionControl *vc) { + return vc->isVcsFileOrDirectory(entryName); + })) { if (entry.isDir()) - result.append(scanForFilesRecursively(entryName, factory, visited, future, progress, progressIncrement)); + result.append(scanForFilesRecursively(entryName, factory, visited, future, progress, progressIncrement, versionControls)); else if (FileNode *node = factory(entryName)) result.append(node); } @@ -382,14 +383,24 @@ static QList scanForFilesRecursively(const Utils::FileName &director return result; } + QList FileNode::scanForFiles(const Utils::FileName &directory, - const std::function factory, - QFutureInterface> *future) + const std::function factory, + QFutureInterface > *future) +{ + return FileNode::scanForFilesWithVersionControls(directory, factory, QList(), future); +} + +QList +FileNode::scanForFilesWithVersionControls(const Utils::FileName &directory, + const std::function factory, + const QList &versionControls, + QFutureInterface> *future) { QSet visited; if (future) future->setProgressRange(0, 1000000); - return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0); + return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0, versionControls); } bool FileNode::supportsAction(ProjectAction action, Node *node) const diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 7c440b73559..746f7437b44 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -37,6 +37,7 @@ #include namespace Utils { class MimeType; } +namespace Core { class IVersionControl; } namespace ProjectExplorer { @@ -188,9 +189,16 @@ public: FileNode *asFileNode() final { return this; } const FileNode *asFileNode() const final { return this; } + // For ABI compatibility, remove in QtC 4.4: static QList scanForFiles(const Utils::FileName &directory, const std::function factory, QFutureInterface> *future = nullptr); + + static QList + scanForFilesWithVersionControls(const Utils::FileName &directory, + const std::function factory, + const QList &versionControls, + QFutureInterface> *future = nullptr); bool supportsAction(ProjectAction action, Node *node) const override; private: