QmlDesigner: Add generated components when exporting a bundle

When exporting a bundle of a component that has a dependency on another
component loaded via a lib import from the Generated folder, those
dependency components get properly added to the exported bundle. Also
the generated imports are removed from the main component as they are
not valid anymore.

Task-number: QDS-13746
Change-Id: Ic3370fc62baa6b2a7cbbef432b1c2a3853170250
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Mahmoud Badri
2024-10-21 16:34:51 +03:00
parent 82150e2cee
commit 82f990558b
2 changed files with 70 additions and 12 deletions

View File

@@ -231,7 +231,16 @@ void BundleHelper::exportComponent(const ModelNode &node)
QStringList filesList; QStringList filesList;
for (const AssetPath &asset : compDependencies) { for (const AssetPath &asset : compDependencies) {
Utils::FilePath assetAbsPath = asset.absFilPath(); Utils::FilePath assetAbsPath = asset.absFilPath();
m_zipWriter->addFile(asset.relativePath, assetAbsPath.fileContents().value_or("")); QByteArray assetContent = assetAbsPath.fileContents().value_or("");
// remove imports of sub components
for (const QString &import : std::as_const(asset.importsToRemove)) {
int removeIdx = assetContent.indexOf(QByteArray("import " + import.toLatin1()));
int removeLen = assetContent.indexOf('\n', removeIdx) - removeIdx;
assetContent.remove(removeIdx, removeLen);
}
m_zipWriter->addFile(asset.relativePath, assetContent);
if (assetAbsPath.fileName() != compFileName) // skip component file (only collect dependencies) if (assetAbsPath.fileName() != compFileName) // skip component file (only collect dependencies)
filesList.append(asset.relativePath); filesList.append(asset.relativePath);
@@ -599,15 +608,45 @@ bool BundleHelper::isItemBundle(const QString &bundleId) const
namespace { namespace {
// library imported Components won't be detected. TODO: find a feasible solution for detecting them
// and either add them as dependencies or warn the user
Utils::FilePath getComponentFilePath(const QString &nodeType, const Utils::FilePath &compDir) Utils::FilePath getComponentFilePath(const QString &nodeType, const Utils::FilePath &compDir)
{ {
Utils::FilePath compFilePath = compDir.pathAppended(QLatin1String("%1.qml").arg(nodeType)); QString compName = nodeType.split('.').last();
if (compFilePath.exists())
return compFilePath;
compFilePath = compDir.pathAppended(QLatin1String("%1.ui.qml").arg(nodeType)); auto findCompFilePath = [&](const Utils::FilePath &dir) -> Utils::FilePath {
Utils::FilePath compFP = dir.pathAppended(QLatin1String("%1.qml").arg(compName));
if (compFP.exists())
return compFP;
compFP = dir.pathAppended(QLatin1String("%1.ui.qml").arg(compName));
if (compFP.exists())
return compFP;
return {};
};
Utils::FilePath compFilePath;
// a component in "Generated" folder
if (nodeType.startsWith("Generated.")) {
Utils::FilePath projectPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
QString nodeTypeSlashSep = nodeType;
nodeTypeSlashSep.replace('.', '/');
Utils::FilePath genCompDir = projectPath.pathAppended(nodeTypeSlashSep);
if (!genCompDir.exists())
genCompDir = genCompDir.parentDir();
compFilePath = findCompFilePath(genCompDir);
if (compFilePath.exists())
return compFilePath;
qWarning() << __FUNCTION__ << "Couldn't find Generated component path";
return {};
}
// for components in the same dir as the main comp., search recursively for the comp. file
compFilePath = findCompFilePath(compDir);
if (compFilePath.exists()) if (compFilePath.exists())
return compFilePath; return compFilePath;
@@ -618,6 +657,7 @@ Utils::FilePath getComponentFilePath(const QString &nodeType, const Utils::FileP
return compFilePath; return compFilePath;
} }
qWarning() << __FUNCTION__ << "Couldn't find component path";
return {}; return {};
} }
@@ -627,8 +667,7 @@ QSet<AssetPath> BundleHelper::getComponentDependencies(const Utils::FilePath &fi
const Utils::FilePath &mainCompDir) const Utils::FilePath &mainCompDir)
{ {
QSet<AssetPath> depList; QSet<AssetPath> depList;
AssetPath compAssetPath = {mainCompDir, filePath.relativePathFrom(mainCompDir).toFSPathString()};
depList.insert({mainCompDir, filePath.relativePathFrom(mainCompDir).toFSPathString()});
#ifdef QDS_USE_PROJECTSTORAGE #ifdef QDS_USE_PROJECTSTORAGE
// TODO add model with ProjectStorageDependencies // TODO add model with ProjectStorageDependencies
@@ -658,7 +697,16 @@ QSet<AssetPath> BundleHelper::getComponentDependencies(const Utils::FilePath &fi
if (!nodeType.startsWith("QtQuick")) { if (!nodeType.startsWith("QtQuick")) {
Utils::FilePath compFilPath = getComponentFilePath(nodeType, mainCompDir); Utils::FilePath compFilPath = getComponentFilePath(nodeType, mainCompDir);
if (!compFilPath.isEmpty()) { if (!compFilPath.isEmpty()) {
depList.unite(getComponentDependencies(compFilPath, mainCompDir)); Utils::FilePath compDir = compFilPath.isChildOf(mainCompDir) ? mainCompDir
: compFilPath.parentDir();
depList.unite(getComponentDependencies(compFilPath, compDir));
// for sub components, mark their imports to be removed from their parent component
// as they will be moved to the same folder as the parent
QString import = nodeType.left(nodeType.lastIndexOf('.'));
if (model->hasImport(import))
compAssetPath.importsToRemove.append(import);
return; return;
} }
} }
@@ -687,6 +735,7 @@ QSet<AssetPath> BundleHelper::getComponentDependencies(const Utils::FilePath &fi
assetPathBase = mainCompDir; assetPathBase = mainCompDir;
} }
QTC_ASSERT(!assetPathRelative.isEmpty(), continue);
depList.insert({assetPathBase, assetPathRelative}); depList.insert({assetPathBase, assetPathRelative});
} }
} }
@@ -701,6 +750,8 @@ QSet<AssetPath> BundleHelper::getComponentDependencies(const Utils::FilePath &fi
parseNode(rootNode); parseNode(rootNode);
depList.insert(compAssetPath);
return depList; return depList;
} }

View File

@@ -25,8 +25,11 @@ class NodeMetaInfo;
class AssetPath class AssetPath
{ {
public: public:
Utils::FilePath basePath; AssetPath(const Utils::FilePath &bsPath, const QString &relPath, const QStringList &imports = {})
QString relativePath; : basePath(bsPath)
, relativePath(relPath)
, importsToRemove(imports)
{}
Utils::FilePath absFilPath() const; Utils::FilePath absFilPath() const;
@@ -35,6 +38,10 @@ public:
return basePath == other.basePath && relativePath == other.relativePath; return basePath == other.basePath && relativePath == other.relativePath;
} }
Utils::FilePath basePath;
QString relativePath;
QStringList importsToRemove;
private: private:
friend size_t qHash(const AssetPath &asset) friend size_t qHash(const AssetPath &asset)
{ {