From 7a6d99a9f61a1ebd3cef9d4081a2071d9b796eb4 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 1 Dec 2023 10:47:02 +0100 Subject: [PATCH] CMakePM: Improve handling of adding translations In case of having no translations setup with the wizard or manually later on we just do nothing and fail with adding the translation file. This patch minimally changes the CMakeLists.txt so that the files are not "lost". Task-number: QTCREATORBUG-29775 Change-Id: I560c8b736ec2a0a8de6e1177317a9172921f4340 Reviewed-by: Cristian Adam --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 95 +++++++++++++++++-- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index b49b7955b7e..e2ed9fa5ee9 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -306,10 +306,18 @@ static std::optional getUncachedCMakeListFile(const FilePath &target } static std::optional findFunction( - const cmListFile &cmakeListFile, std::function pred) + const cmListFile &cmakeListFile, std::function pred, + bool reverse = false) { - auto function = std::find_if(cmakeListFile.Functions.begin(), cmakeListFile.Functions.end(), - pred); + if (reverse) { + auto function = std::find_if(cmakeListFile.Functions.rbegin(), + cmakeListFile.Functions.rend(), pred); + if (function == cmakeListFile.Functions.rend()) + return std::nullopt; + return std::make_optional(*function); + } + auto function + = std::find_if(cmakeListFile.Functions.begin(), cmakeListFile.Functions.end(), pred); if (function == cmakeListFile.Functions.end()) return std::nullopt; return std::make_optional(*function); @@ -494,6 +502,54 @@ static std::optional handleQtCreateTranslation(const cmListF std::nullopt, {"options"}, lastArgumentPos); } + +static expected_str insertQtAddTranslations(const cmListFile &cmakeListFile, + const FilePath &targetCmakeFile, + const QString &targetName, + int targetDefinitionLine, + const QString &filesToAdd, + int qtMajorVersion, + bool addLinguist) +{ + std::optional function + = findFunction(cmakeListFile, [targetDefinitionLine](const auto &func) { + return func.Line() == targetDefinitionLine; + }); + if (!function.has_value()) + return false; + + // FIXME: room for improvement + // * this just updates "the current cmake path" for e.g. conditional setups like + // differentiating between desktop and device build config we do not update all + QString snippet; + if (qtMajorVersion == 5) + snippet = QString("\nqt_create_translation(QM_FILES %1)\n").arg(filesToAdd); + else + snippet = QString("\nqt_add_translations(%1 TS_FILES %2)\n").arg(targetName, filesToAdd); + + const int insertionLine = function->LineEnd() + 1; + expected_str inserted = insertSnippetSilently(targetCmakeFile, + {snippet, insertionLine, 0}); + if (!inserted || !addLinguist) + return inserted; + + function = findFunction(cmakeListFile, [](const auto &func) { + return func.LowerCaseName() == "find_package"; + }, /* reverse = */ true); + if (!function.has_value()) { + qCCritical(cmakeBuildSystemLog) << "Failed to find a find_package()."; + return inserted; // we just fail to insert LinguistTool, but otherwise succeeded + } + if (insertionLine < function->LineEnd() + 1) { + qCCritical(cmakeBuildSystemLog) << "find_package() calls after old insertion. " + "Refusing to process."; + return inserted; // we just fail to insert LinguistTool, but otherwise succeeded + } + + snippet = QString("find_package(Qt%1 REQUIRED COMPONENTS LinguistTools)\n").arg(qtMajorVersion); + return insertSnippetSilently(targetCmakeFile, {snippet, function->LineEnd() + 1, 0}); +} + bool CMakeBuildSystem::addTsFiles(Node *context, const FilePaths &filePaths, FilePaths *notAdded) { if (notAdded) @@ -518,10 +574,37 @@ bool CMakeBuildSystem::addTsFiles(Node *context, const FilePaths &filePaths, Fil if (!function.has_value()) function = handleQtCreateTranslation(*cmakeListFile, &lastArgumentPos); - if (!function.has_value()) // we failed to find any pre-existing, TODO add one ourself - return false; - const QString filesToAdd = relativeFilePaths(filePaths, n->filePath().canonicalPath()); + bool linguistToolsMissing = false; + int qtMajorVersion = -1; + if (!function.has_value()) { + if (auto qt = m_findPackagesFilesHash.value("Qt6Core"); qt.hasValidTarget()) + qtMajorVersion = 6; + else if (auto qt = m_findPackagesFilesHash.value("Qt5Core"); qt.hasValidTarget()) + qtMajorVersion = 5; + + if (qtMajorVersion != -1) { + const QString linguistTools = QString("Qt%1LinguistTools").arg(qtMajorVersion); + auto linguist = m_findPackagesFilesHash.value(linguistTools); + linguistToolsMissing = !linguist.hasValidTarget(); + } + + // we failed to find any pre-existing, add one ourself + expected_str inserted = insertQtAddTranslations(*cmakeListFile, + targetCMakeFile, + targetName, + cmakeFile->targetLine, + filesToAdd, + qtMajorVersion, + linguistToolsMissing); + if (!inserted) + qCCritical(cmakeBuildSystemLog) << inserted.error(); + else if (notAdded) + notAdded->removeIf([filePaths](const FilePath &p) { return filePaths.contains(p); }); + + return inserted.value_or(false); + } + auto lastArgument = function->Arguments().at(lastArgumentPos); const int lastArgLength = static_cast(lastArgument.Value.size()) - 1; SnippetAndLocation snippetLocation{QString("\n%1").arg(filesToAdd),