forked from qt-creator/qt-creator
QbsProjectManager: Build up the project tree in a dedicated thread
... and only switch the root node in the UI thread. Creating the project tree can take some time for larger projects; no need to block the UI for that. Task-number: QTCREATORBUG-18533 Change-Id: I093dc9fb8f3454011a3c64bcc0f785e8b7753b4e Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -194,32 +194,32 @@ static QStringList unreferencedBuildSystemFiles(const QJsonObject &project)
|
|||||||
return unreferenced;
|
return unreferenced;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<QbsProjectNode> QbsNodeTreeBuilder::buildTree(const QbsBuildSystem *buildSystem)
|
QbsProjectNode *QbsNodeTreeBuilder::buildTree(const QString &projectName,
|
||||||
|
const Utils::FilePath &projectFile,
|
||||||
|
const Utils::FilePath &projectDir,
|
||||||
|
const QJsonObject &projectData)
|
||||||
{
|
{
|
||||||
const Project * const project = buildSystem->project();
|
auto root = std::make_unique<QbsProjectNode>(projectData);
|
||||||
auto root = std::make_unique<QbsProjectNode>(buildSystem->projectData());
|
|
||||||
|
|
||||||
// If we have no project information at all (i.e. it could not be properly parsed),
|
// If we have no project information at all (i.e. it could not be properly parsed),
|
||||||
// create the main project file node "manually".
|
// create the main project file node "manually".
|
||||||
if (buildSystem->projectData().isEmpty()) {
|
if (projectData.isEmpty()) {
|
||||||
auto fileNode = std::make_unique<FileNode>(project->projectFilePath(), FileType::Project);
|
auto fileNode = std::make_unique<FileNode>(projectFile, FileType::Project);
|
||||||
root->addNode(std::move(fileNode));
|
root->addNode(std::move(fileNode));
|
||||||
} else {
|
} else {
|
||||||
setupProjectNode(root.get());
|
setupProjectNode(root.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root->displayName().isEmpty())
|
if (root->displayName().isEmpty())
|
||||||
root->setDisplayName(project->displayName());
|
root->setDisplayName(projectName);
|
||||||
if (root->displayName().isEmpty())
|
if (root->displayName().isEmpty())
|
||||||
root->setDisplayName(project->projectFilePath().toFileInfo().completeBaseName());
|
root->setDisplayName(projectFile.toFileInfo().completeBaseName());
|
||||||
|
|
||||||
auto buildSystemFiles = std::make_unique<FolderNode>(project->projectDirectory());
|
auto buildSystemFiles = std::make_unique<FolderNode>(projectDir);
|
||||||
buildSystemFiles->setDisplayName(QCoreApplication::translate("QbsProjectNode", "Qbs files"));
|
buildSystemFiles->setDisplayName(QCoreApplication::translate("QbsProjectNode", "Qbs files"));
|
||||||
|
|
||||||
const FilePath projectDir = project->projectDirectory();
|
const FilePath buildDir = FilePath::fromString(projectData.value("build-directory").toString());
|
||||||
const FilePath buildDir = FilePath::fromString(buildSystem->projectData()
|
const QStringList files = unreferencedBuildSystemFiles(projectData);
|
||||||
.value("build-directory").toString());
|
|
||||||
const QStringList files = unreferencedBuildSystemFiles(buildSystem->projectData());
|
|
||||||
for (const QString &f : files) {
|
for (const QString &f : files) {
|
||||||
const FilePath filePath = FilePath::fromString(f);
|
const FilePath filePath = FilePath::fromString(f);
|
||||||
if (filePath.isChildOf(projectDir)) {
|
if (filePath.isChildOf(projectDir)) {
|
||||||
@@ -230,7 +230,7 @@ std::unique_ptr<QbsProjectNode> QbsNodeTreeBuilder::buildTree(const QbsBuildSyst
|
|||||||
}
|
}
|
||||||
buildSystemFiles->compress();
|
buildSystemFiles->compress();
|
||||||
root->addNode(std::move(buildSystemFiles));
|
root->addNode(std::move(buildSystemFiles));
|
||||||
return root;
|
return root.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -25,18 +25,29 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QJsonObject;
|
||||||
|
class QString;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace Utils { class FilePath; }
|
||||||
|
|
||||||
namespace QbsProjectManager {
|
namespace QbsProjectManager {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class QbsBuildSystem;
|
|
||||||
class QbsProjectNode;
|
class QbsProjectNode;
|
||||||
|
|
||||||
class QbsNodeTreeBuilder
|
class QbsNodeTreeBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<QbsProjectNode> buildTree(const QbsBuildSystem *buildSystem);
|
static QbsProjectNode *buildTree(const QString &projectName,
|
||||||
|
const Utils::FilePath &projectFile,
|
||||||
|
const Utils::FilePath &projectDir,
|
||||||
|
const QJsonObject &projectData);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -67,6 +67,7 @@
|
|||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/runextensions.h>
|
||||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||||
#include <qmljstools/qmljsmodelmanager.h>
|
#include <qmljstools/qmljsmodelmanager.h>
|
||||||
#include <qtsupport/qtcppkitinfo.h>
|
#include <qtsupport/qtcppkitinfo.h>
|
||||||
@@ -214,8 +215,7 @@ QbsBuildSystem::QbsBuildSystem(QbsBuildConfiguration *bc)
|
|||||||
connect(&m_parsingDelay, &QTimer::timeout, this, &QbsBuildSystem::triggerParsing);
|
connect(&m_parsingDelay, &QTimer::timeout, this, &QbsBuildSystem::triggerParsing);
|
||||||
|
|
||||||
connect(bc->project(), &Project::projectFileIsDirty, this, &QbsBuildSystem::delayParsing);
|
connect(bc->project(), &Project::projectFileIsDirty, this, &QbsBuildSystem::delayParsing);
|
||||||
|
updateProjectNodes({});
|
||||||
rebuildProjectTree();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QbsBuildSystem::~QbsBuildSystem()
|
QbsBuildSystem::~QbsBuildSystem()
|
||||||
@@ -447,6 +447,7 @@ bool QbsBuildSystem::checkCancelStatus()
|
|||||||
qCDebug(qbsPmLog) << "Cancel request while parsing, starting re-parse";
|
qCDebug(qbsPmLog) << "Cancel request while parsing, starting re-parse";
|
||||||
m_qbsProjectParser->deleteLater();
|
m_qbsProjectParser->deleteLater();
|
||||||
m_qbsProjectParser = nullptr;
|
m_qbsProjectParser = nullptr;
|
||||||
|
m_treeCreationWatcher = nullptr;
|
||||||
m_guard = {};
|
m_guard = {};
|
||||||
parseCurrentBuildConfiguration();
|
parseCurrentBuildConfiguration();
|
||||||
return true;
|
return true;
|
||||||
@@ -456,7 +457,7 @@ void QbsBuildSystem::updateAfterParse()
|
|||||||
{
|
{
|
||||||
qCDebug(qbsPmLog) << "Updating data after parse";
|
qCDebug(qbsPmLog) << "Updating data after parse";
|
||||||
OpTimer opTimer("updateAfterParse");
|
OpTimer opTimer("updateAfterParse");
|
||||||
updateProjectNodes();
|
updateProjectNodes([this] {
|
||||||
updateDocuments();
|
updateDocuments();
|
||||||
updateBuildTargetData();
|
updateBuildTargetData();
|
||||||
updateCppCodeModel();
|
updateCppCodeModel();
|
||||||
@@ -464,7 +465,10 @@ void QbsBuildSystem::updateAfterParse()
|
|||||||
updateQmlJsCodeModel();
|
updateQmlJsCodeModel();
|
||||||
emit project()->fileListChanged();
|
emit project()->fileListChanged();
|
||||||
m_envCache.clear();
|
m_envCache.clear();
|
||||||
|
m_guard.markAsSuccess();
|
||||||
|
m_guard = {};
|
||||||
emitBuildSystemUpdated();
|
emitBuildSystemUpdated();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void QbsBuildSystem::delayedUpdateAfterParse()
|
void QbsBuildSystem::delayedUpdateAfterParse()
|
||||||
@@ -472,10 +476,32 @@ void QbsBuildSystem::delayedUpdateAfterParse()
|
|||||||
QTimer::singleShot(0, this, &QbsBuildSystem::updateAfterParse);
|
QTimer::singleShot(0, this, &QbsBuildSystem::updateAfterParse);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QbsBuildSystem::updateProjectNodes()
|
void QbsBuildSystem::updateProjectNodes(const std::function<void ()> &continuation)
|
||||||
{
|
{
|
||||||
OpTimer opTimer("updateProjectNodes");
|
m_treeCreationWatcher = new TreeCreationWatcher(this);
|
||||||
rebuildProjectTree();
|
connect(m_treeCreationWatcher, &TreeCreationWatcher::finished, this,
|
||||||
|
[this, watcher = m_treeCreationWatcher, continuation] {
|
||||||
|
std::unique_ptr<QbsProjectNode> rootNode(m_treeCreationWatcher->result());
|
||||||
|
if (watcher != m_treeCreationWatcher) {
|
||||||
|
watcher->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OpTimer("updateProjectNodes continuation");
|
||||||
|
m_treeCreationWatcher->deleteLater();
|
||||||
|
m_treeCreationWatcher = nullptr;
|
||||||
|
if (target() != project()->activeTarget()
|
||||||
|
|| target()->activeBuildConfiguration()->buildSystem() != this) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
project()->setDisplayName(rootNode->displayName());
|
||||||
|
setRootProjectNode(std::move(rootNode));
|
||||||
|
if (continuation)
|
||||||
|
continuation();
|
||||||
|
});
|
||||||
|
m_treeCreationWatcher->setFuture(runAsync(ProjectExplorerPlugin::sharedThreadPool(),
|
||||||
|
QThread::LowPriority, &QbsNodeTreeBuilder::buildTree,
|
||||||
|
project()->displayName(), project()->projectFilePath(), project()->projectDirectory(),
|
||||||
|
projectData()));
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath QbsBuildSystem::installRoot()
|
FilePath QbsBuildSystem::installRoot()
|
||||||
@@ -525,8 +551,10 @@ void QbsBuildSystem::handleQbsParsingDone(bool success)
|
|||||||
delete m_qbsUpdateFutureInterface;
|
delete m_qbsUpdateFutureInterface;
|
||||||
m_qbsUpdateFutureInterface = nullptr;
|
m_qbsUpdateFutureInterface = nullptr;
|
||||||
|
|
||||||
if (dataChanged)
|
if (dataChanged) {
|
||||||
updateAfterParse();
|
updateAfterParse();
|
||||||
|
return;
|
||||||
|
}
|
||||||
else if (envChanged)
|
else if (envChanged)
|
||||||
updateCppCodeModel();
|
updateCppCodeModel();
|
||||||
if (success)
|
if (success)
|
||||||
@@ -539,13 +567,6 @@ void QbsBuildSystem::handleQbsParsingDone(bool success)
|
|||||||
emitBuildSystemUpdated();
|
emitBuildSystemUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QbsBuildSystem::rebuildProjectTree()
|
|
||||||
{
|
|
||||||
std::unique_ptr<QbsProjectNode> newRoot = QbsNodeTreeBuilder::buildTree(this);
|
|
||||||
project()->setDisplayName(newRoot->displayName());
|
|
||||||
setRootProjectNode(std::move(newRoot));
|
|
||||||
}
|
|
||||||
|
|
||||||
void QbsBuildSystem::changeActiveTarget(Target *t)
|
void QbsBuildSystem::changeActiveTarget(Target *t)
|
||||||
{
|
{
|
||||||
if (t)
|
if (t)
|
||||||
@@ -609,6 +630,7 @@ void QbsBuildSystem::parseCurrentBuildConfiguration()
|
|||||||
|
|
||||||
QTC_ASSERT(!m_qbsProjectParser, return);
|
QTC_ASSERT(!m_qbsProjectParser, return);
|
||||||
m_qbsProjectParser = new QbsProjectParser(this, m_qbsUpdateFutureInterface);
|
m_qbsProjectParser = new QbsProjectParser(this, m_qbsUpdateFutureInterface);
|
||||||
|
m_treeCreationWatcher = nullptr;
|
||||||
connect(m_qbsProjectParser, &QbsProjectParser::done,
|
connect(m_qbsProjectParser, &QbsProjectParser::done,
|
||||||
this, &QbsBuildSystem::handleQbsParsingDone);
|
this, &QbsBuildSystem::handleQbsParsingDone);
|
||||||
|
|
||||||
@@ -636,10 +658,11 @@ void QbsBuildSystem::updateAfterBuild()
|
|||||||
}
|
}
|
||||||
qCDebug(qbsPmLog) << "Updating data after build";
|
qCDebug(qbsPmLog) << "Updating data after build";
|
||||||
m_projectData = projectData;
|
m_projectData = projectData;
|
||||||
updateProjectNodes();
|
updateProjectNodes([this] {
|
||||||
updateBuildTargetData();
|
updateBuildTargetData();
|
||||||
updateExtraCompilers();
|
updateExtraCompilers();
|
||||||
m_envCache.clear();
|
m_envCache.clear();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void QbsBuildSystem::generateErrors(const ErrorInfo &e)
|
void QbsBuildSystem::generateErrors(const ErrorInfo &e)
|
||||||
|
@@ -36,10 +36,13 @@
|
|||||||
|
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
|
|
||||||
|
#include <QFutureWatcher>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace CppTools { class CppProjectUpdater; }
|
namespace CppTools { class CppProjectUpdater; }
|
||||||
|
|
||||||
namespace QbsProjectManager {
|
namespace QbsProjectManager {
|
||||||
@@ -125,11 +128,7 @@ private:
|
|||||||
friend class QbsProject;
|
friend class QbsProject;
|
||||||
|
|
||||||
void handleQbsParsingDone(bool success);
|
void handleQbsParsingDone(bool success);
|
||||||
|
|
||||||
void rebuildProjectTree();
|
|
||||||
|
|
||||||
void changeActiveTarget(ProjectExplorer::Target *t);
|
void changeActiveTarget(ProjectExplorer::Target *t);
|
||||||
|
|
||||||
void prepareForParsing();
|
void prepareForParsing();
|
||||||
void updateDocuments();
|
void updateDocuments();
|
||||||
void updateCppCodeModel();
|
void updateCppCodeModel();
|
||||||
@@ -141,7 +140,7 @@ private:
|
|||||||
bool checkCancelStatus();
|
bool checkCancelStatus();
|
||||||
void updateAfterParse();
|
void updateAfterParse();
|
||||||
void delayedUpdateAfterParse();
|
void delayedUpdateAfterParse();
|
||||||
void updateProjectNodes();
|
void updateProjectNodes(const std::function<void()> &continuation);
|
||||||
Utils::FilePath installRoot();
|
Utils::FilePath installRoot();
|
||||||
|
|
||||||
static bool ensureWriteableQbsFile(const QString &file);
|
static bool ensureWriteableQbsFile(const QString &file);
|
||||||
@@ -153,6 +152,8 @@ private:
|
|||||||
QTimer m_parsingDelay;
|
QTimer m_parsingDelay;
|
||||||
QbsProjectParser *m_qbsProjectParser = nullptr;
|
QbsProjectParser *m_qbsProjectParser = nullptr;
|
||||||
QFutureInterface<bool> *m_qbsUpdateFutureInterface = nullptr;
|
QFutureInterface<bool> *m_qbsUpdateFutureInterface = nullptr;
|
||||||
|
using TreeCreationWatcher = QFutureWatcher<QbsProjectNode *>;
|
||||||
|
TreeCreationWatcher *m_treeCreationWatcher = nullptr;
|
||||||
Utils::Environment m_lastParseEnv;
|
Utils::Environment m_lastParseEnv;
|
||||||
bool m_parsingScheduled = false;
|
bool m_parsingScheduled = false;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user