QmlProjectExporter: Copy the qtquickdesigner-components into the project

This way git is not a requirement anymore to build a project
which was an issue for some users on some platforms.

Fixes: QDS-14168
Change-Id: Iabfa57d0a38ccd16ae044bb4556df978a71198f6
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Knud Dollereder
2024-11-21 13:19:35 +01:00
parent e9ae4d2110
commit 580164e6da
5 changed files with 112 additions and 22 deletions

View File

@@ -290,7 +290,7 @@ bool FileFilterItem::fileMatches(const QString &fileName) const
bool FileFilterItem::ignoreDirectory(const QFileInfo &file) const bool FileFilterItem::ignoreDirectory(const QFileInfo &file) const
{ {
static const QStringList blackList = { "CMakeCache.txt", "build.ninja" }; static const QStringList blackList = {"CMakeCache.txt", "build.ninja", "ignore-in-qds"};
return blackList.contains(file.fileName()); return blackList.contains(file.fileName());
} }

View File

@@ -169,7 +169,11 @@ bool CMakeGenerator::ignore(const Utils::FilePath &path) const
if (!m_root->dir.exists()) if (!m_root->dir.exists())
return true; return true;
static const QStringList fileNames = { "CMakeCache.txt", "build.ninja" }; static const QStringList dirNames = { DEPENDENCIES_DIR };
if (dirNames.contains(path.fileName()))
return true;
static const QStringList fileNames = {COMPONENTS_IGNORE_FILE, "CMakeCache.txt", "build.ninja"};
Utils::FilePath dir = path; Utils::FilePath dir = path;
while (dir.isChildOf(m_root->dir)) { while (dir.isChildOf(m_root->dir)) {

View File

@@ -40,9 +40,13 @@ CMakeWriter::Ptr CMakeWriter::create(CMakeGenerator *parent)
const QmlBuildSystem *buildSystem = parent->buildSystem(); const QmlBuildSystem *buildSystem = parent->buildSystem();
QTC_ASSERT(buildSystem, return {}); QTC_ASSERT(buildSystem, return {});
const QString versionString = buildSystem->versionDesignStudio(); auto [major, minor, patch] = versionFromString(buildSystem->versionDesignStudio());
bool ok = false;
if (float version = versionString.toFloat(&ok); ok && version > 4.4) bool useV1 = false;
if (major.has_value())
useV1 = minor.has_value() ? *major >= 4 && *minor >= 5 : *major >= 5;
if (useV1)
return std::make_unique<CMakeWriterV1>(parent); return std::make_unique<CMakeWriterV1>(parent);
CMakeGenerator::logIssue( CMakeGenerator::logIssue(
@@ -58,6 +62,37 @@ CMakeWriter::Ptr CMakeWriter::create(CMakeGenerator *parent)
return std::make_unique<CMakeWriterV0>(parent); return std::make_unique<CMakeWriterV0>(parent);
} }
CMakeWriter::Version CMakeWriter::versionFromString(const QString &versionString)
{
const QStringList versions = versionString.split('.', Qt::SkipEmptyParts);
auto checkComponent = [&versions](qsizetype idx) -> std::optional<int> {
if (versions.size() >= idx+1) {
bool ok = false;
if (int version = versions[idx].toInt(&ok); ok)
return version;
}
return std::nullopt;
};
return {checkComponent(0), checkComponent(1), checkComponent(2)};
}
CMakeWriter::Version CMakeWriter::versionFromIgnoreFile(const Utils::FilePath &path)
{
QString versionString;
QFile ignoreFile(path.toFSPathString());
if (ignoreFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream stream(&ignoreFile);
QString firstLine = stream.readLine();
ignoreFile.close();
QStringList parts = firstLine.split(' ');
QTC_ASSERT(parts.size()==3, return {});
return versionFromString(parts[2]);
}
return {};
}
QString CMakeWriter::readTemplate(const QString &templatePath) QString CMakeWriter::readTemplate(const QString &templatePath)
{ {
QFile templatefile(templatePath); QFile templatefile(templatePath);
@@ -174,18 +209,11 @@ QString CMakeWriter::makeFindPackageBlock(const NodePtr &node, const QmlBuildSys
tail.append(" Quick3D"); tail.append(" Quick3D");
tail.append(")\n"); tail.append(")\n");
const QStringList versions = buildSystem->versionQtQuick().split('.', Qt::SkipEmptyParts); auto [major, minor, patch] = versionFromString(buildSystem->versionQtQuick());
if (versions.size() < 2) if (!major.has_value() || !minor.has_value())
return head + tail; return head + tail;
bool majorOk = false; const QString from = QString::number(*major) + "." + QString::number(*minor);
bool minorOk = false;
int major = versions[0].toInt(&majorOk);
int minor = versions[1].toInt(&minorOk);
if (!majorOk || !minorOk)
return head + tail;
const QString from = versions[0] + "." + versions[1];
QString out = head + " " + from + tail; QString out = head + " " + from + tail;
if (major >= 6 && minor >= 3) if (major >= 6 && minor >= 3)
@@ -224,7 +252,7 @@ QString CMakeWriter::makeSingletonBlock(const NodePtr &node) const
return str; return str;
} }
QString CMakeWriter::makeSubdirectoriesBlock(const NodePtr &node) const QString CMakeWriter::makeSubdirectoriesBlock(const NodePtr &node, const QStringList &others) const
{ {
QTC_ASSERT(parent(), return {}); QTC_ASSERT(parent(), return {});
@@ -234,6 +262,10 @@ QString CMakeWriter::makeSubdirectoriesBlock(const NodePtr &node) const
|| n->type == Node::Type::App || parent()->hasChildModule(n)) || n->type == Node::Type::App || parent()->hasChildModule(n))
str.append(QString("add_subdirectory(%1)\n").arg(n->dir.fileName())); str.append(QString("add_subdirectory(%1)\n").arg(n->dir.fileName()));
} }
for (const QString &other : others)
str.append(QString("add_subdirectory(%1)\n").arg(other));
return str; return str;
} }

View File

@@ -42,6 +42,10 @@ using FileGetter = std::function<std::vector<Utils::FilePath>(const NodePtr &)>;
class CMakeGenerator; class CMakeGenerator;
const char DEPENDENCIES_DIR[] = "Dependencies";
const char COMPONENTS_DIR[] = "Components";
const char COMPONENTS_IGNORE_FILE[] = "ignore-in-qds";
const char ENV_VARIABLE_CONTROLCONF[] = const char ENV_VARIABLE_CONTROLCONF[] =
"QT_QUICK_CONTROLS_CONF"; "QT_QUICK_CONTROLS_CONF";
@@ -58,8 +62,11 @@ class CMakeWriter
{ {
public: public:
using Ptr = std::shared_ptr<CMakeWriter>; using Ptr = std::shared_ptr<CMakeWriter>;
using Version = std::tuple<std::optional<int>, std::optional<int>, std::optional<int>>;
static Ptr create(CMakeGenerator *parent); static Ptr create(CMakeGenerator *parent);
static Version versionFromString(const QString &versionString);
static Version versionFromIgnoreFile(const Utils::FilePath &path);
static QString readTemplate(const QString &templatePath); static QString readTemplate(const QString &templatePath);
static void writeFile(const Utils::FilePath &path, const QString &content); static void writeFile(const Utils::FilePath &path, const QString &content);
@@ -90,7 +97,7 @@ protected:
QString makeRelative(const NodePtr &node, const Utils::FilePath &path) const; QString makeRelative(const NodePtr &node, const Utils::FilePath &path) const;
QString makeQmlFilesBlock(const NodePtr &node) const; QString makeQmlFilesBlock(const NodePtr &node) const;
QString makeSingletonBlock(const NodePtr &node) const; QString makeSingletonBlock(const NodePtr &node) const;
QString makeSubdirectoriesBlock(const NodePtr &node) const; QString makeSubdirectoriesBlock(const NodePtr &node, const QStringList &others = {}) const;
QString makeSetEnvironmentFn() const; QString makeSetEnvironmentFn() const;
std::tuple<QString, QString> makeResourcesBlocksRoot(const NodePtr &node) const; std::tuple<QString, QString> makeResourcesBlocksRoot(const NodePtr &node) const;
std::tuple<QString, QString> makeResourcesBlocksModule(const NodePtr &node) const; std::tuple<QString, QString> makeResourcesBlocksModule(const NodePtr &node) const;

View File

@@ -5,6 +5,8 @@
#include "qmlprojectmanager/buildsystem/qmlbuildsystem.h" #include "qmlprojectmanager/buildsystem/qmlbuildsystem.h"
#include <coreplugin/icore.h>
namespace QmlProjectManager { namespace QmlProjectManager {
namespace QmlProjectExporter { namespace QmlProjectExporter {
@@ -19,6 +21,12 @@ target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Quick
Qt${QT_VERSION_MAJOR}::Qml))"; Qt${QT_VERSION_MAJOR}::Qml))";
const char TEMPLATE_DEPENDENCIES_CMAKELISTS[] = R"(
if (BUILD_QDS_COMPONENTS)
add_subdirectory(%1)
endif()
)";
CMakeWriterV1::CMakeWriterV1(CMakeGenerator *parent) CMakeWriterV1::CMakeWriterV1(CMakeGenerator *parent)
: CMakeWriter(parent) : CMakeWriter(parent)
{} {}
@@ -52,10 +60,49 @@ void CMakeWriterV1::writeRootCMakeFile(const NodePtr &node) const
writeFile(insightPath, insightTemplate); writeFile(insightPath, insightTemplate);
} }
const Utils::FilePath componentPath = cmakeFolderPath.pathAppended("qmlcomponents.cmake"); const Utils::FilePath dependenciesPath = node->dir.pathAppended(DEPENDENCIES_DIR);
if (!componentPath.exists()) { const Utils::FilePath componentsPath = dependenciesPath.pathAppended(COMPONENTS_DIR);
const QString compTemplate = readTemplate(":/templates/qmlcomponents"); const Utils::FilePath componentsIgnoreFile = componentsPath.pathAppended(COMPONENTS_IGNORE_FILE);
writeFile(componentPath, compTemplate);
bool copyComponents = false;
// Note: If dependencies directory exists but not the components directory, we assunme
// the user has intentionally deleted it because he has the components installed in Qt.
if (!dependenciesPath.exists()) {
dependenciesPath.createDir();
copyComponents = true;
} else if (componentsIgnoreFile.exists()) {
auto normalizeVersion = [](const auto &version) -> std::tuple<int, int, int> {
auto [major, minor, patch] = version;
return {major.value_or(0), minor.value_or(0), patch.value_or(0)};
};
auto *bs = parent()->buildSystem();
auto versionDS = normalizeVersion(versionFromString(bs->versionDesignStudio()));
auto versionIgnore = normalizeVersion(versionFromIgnoreFile(componentsIgnoreFile));
if (versionDS > versionIgnore) {
copyComponents = true;
if (componentsPath.exists())
componentsPath.removeRecursively();
}
}
if (copyComponents) {
if (!componentsPath.exists())
componentsPath.createDir();
const Utils::FilePath componentsSrc =
Core::ICore::resourcePath("qmldesigner/Dependencies/qtquickdesigner-components");
if (componentsSrc.exists()) {
auto cpyResult = componentsSrc.copyRecursively(componentsPath);
if (cpyResult) {
QString depsTemplate =
QString::fromUtf8(TEMPLATE_DEPENDENCIES_CMAKELISTS, -1).arg(COMPONENTS_DIR);
writeFile(dependenciesPath.pathAppended("CMakeLists.txt"), depsTemplate);
} else {
CMakeGenerator::logIssue(
ProjectExplorer::Task::Error, cpyResult.error(), componentsSrc);
}
}
} }
const Utils::FilePath sharedFile = node->dir.pathAppended("CMakeLists.txt.shared"); const Utils::FilePath sharedFile = node->dir.pathAppended("CMakeLists.txt.shared");
@@ -87,7 +134,7 @@ void CMakeWriterV1::writeModuleCMakeFile(const NodePtr &node, const NodePtr &) c
if (node->type == Node::Type::App) { if (node->type == Node::Type::App) {
const Utils::FilePath userFile = node->dir.pathAppended("qds.cmake"); const Utils::FilePath userFile = node->dir.pathAppended("qds.cmake");
QString userFileContent(DO_NOT_EDIT_FILE); QString userFileContent(DO_NOT_EDIT_FILE);
userFileContent.append(makeSubdirectoriesBlock(node)); userFileContent.append(makeSubdirectoriesBlock(node, {DEPENDENCIES_DIR}));
auto [resources, bigResources] = makeResourcesBlocksRoot(node); auto [resources, bigResources] = makeResourcesBlocksRoot(node);
if (!resources.isEmpty()) { if (!resources.isEmpty()) {