From 71ae73119ee9ba16efaebabc03d13a1c9af3676f Mon Sep 17 00:00:00 2001 From: Yasser Grimes Date: Mon, 24 Oct 2022 18:50:27 +0300 Subject: [PATCH] McuSupport: Support globbing in default paths With this change default paths containing globbing characters will be expanded to an available path. example: "sdk-*" will be replaced with "sdk-1.2.3" if the latter is available. To test the wildcards and make sure it works with QtCreator macros a fake_kit was added containing fake packages. Task-number: QTCREATORBUG-26900 Change-Id: I31440d24e42a6170fc5f1905f884bb3be43c57bc Reviewed-by: Eike Ziller --- src/plugins/mcusupport/mcusupportoptions.cpp | 23 +++++- src/plugins/mcusupport/mcusupportoptions.h | 2 +- .../mcusupport/mcusupportoptionspage.cpp | 2 +- src/plugins/mcusupport/mcusupportsdk.cpp | 2 +- src/plugins/mcusupport/mcutargetfactory.cpp | 1 - src/plugins/mcusupport/test/unittest.cpp | 81 ++++++++++++++++++- src/plugins/mcusupport/test/unittest.h | 3 + .../mcusupport/test/wildcards_test_kit_json.h | 74 +++++++++++++++++ 8 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 src/plugins/mcusupport/test/wildcards_test_kit_json.h diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index 25d922bfe8d..cd87896803a 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -30,18 +30,37 @@ using namespace Utils; namespace McuSupport::Internal { +static const Utils::FilePath expandWildcards(const Utils::FilePath& path) +{ + if (!path.fileName().contains("*") && !path.fileName().contains("?")) + return path; + + const FilePath p = path.parentDir(); + + auto entries = p.dirEntries( + Utils::FileFilter({path.fileName()}, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)); + + if (entries.isEmpty()) + return path; + + // Return the last match (can correspond to the latest version) + sort(entries, [](const FilePath &a, const FilePath &b) { return a.fileName() < b.fileName(); }); + + return entries.last(); +} + Macros *McuSdkRepository::globalMacros() { static Macros macros; return ¯os; } -void McuSdkRepository::expandVariables() +void McuSdkRepository::expandVariablesAndWildcards() { for (const auto &target : std::as_const(mcuTargets)) { auto macroExpander = getMacroExpander(*target); for (const auto &package : target->packages()) { - package->setPath(macroExpander->expand(package->path())); + package->setPath(expandWildcards(macroExpander->expand(package->path()))); } } } diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index 8fddf21ab40..f6e39e529ae 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -40,7 +40,7 @@ public: Targets mcuTargets; Packages packages; - void expandVariables(); + void expandVariablesAndWildcards(); MacroExpanderPtr getMacroExpander(const McuTarget &target); static Macros *globalMacros(); diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index 556dfd0e216..f317026c07f 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -289,7 +289,7 @@ void McuSupportOptionsWidget::apply() bool pathsChanged = false; m_settingsHandler->setAutomaticKitCreation(m_options.automaticKitCreationEnabled()); - m_options.sdkRepository.expandVariables(); + m_options.sdkRepository.expandVariablesAndWildcards(); QMessageBox warningPopup(QMessageBox::Icon::Warning, Tr::tr("Warning"), diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index d68a8e9ea88..043aad927f3 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -593,7 +593,7 @@ McuSdkRepository targetsFromDescriptions(const QList &desc } McuSdkRepository repo{mcuTargets, mcuPackages}; - repo.expandVariables(); + repo.expandVariablesAndWildcards(); return repo; } diff --git a/src/plugins/mcusupport/mcutargetfactory.cpp b/src/plugins/mcusupport/mcutargetfactory.cpp index 6f5be2a1026..c54a41b4409 100644 --- a/src/plugins/mcusupport/mcutargetfactory.cpp +++ b/src/plugins/mcusupport/mcutargetfactory.cpp @@ -11,7 +11,6 @@ #include "mcutargetdescription.h" #include -#include #include #include diff --git a/src/plugins/mcusupport/test/unittest.cpp b/src/plugins/mcusupport/test/unittest.cpp index 9a2e1153c43..86df7b69d27 100644 --- a/src/plugins/mcusupport/test/unittest.cpp +++ b/src/plugins/mcusupport/test/unittest.cpp @@ -15,8 +15,9 @@ #include "ghs_tviic2d6m_baremetal_json.h" #include "iar_mimxrt1064_evk_freertos_json.h" #include "iar_stm32f469i_discovery_baremetal_json.h" -#include "msvc_desktop_json.h" #include "mingw_desktop_json.h" +#include "msvc_desktop_json.h" +#include "wildcards_test_kit_json.h" #include "mcuhelpers.h" #include "mcukitmanager.h" @@ -27,6 +28,7 @@ #include "mcusupportsdk.h" #include "mcusupportversiondetection.h" #include "mcutargetdescription.h" +#include "mcutargetfactory.h" #include "mcutargetfactorylegacy.h" #include @@ -44,13 +46,15 @@ #include #include -#include +#include +#include #include #include #include #include +#include #include namespace McuSupport::Internal::Test { @@ -172,6 +176,11 @@ const QString jlinkDetectionPath{HostOsInfo::isWindowsHost() const QString unsupportedToolchainFilePath = QString{qtForMcuSdkPath} + "/lib/cmake/Qul/toolchain/unsupported.cmake"; +// Build/Testing/QtMCUs +const auto testing_output_dir = (FilePath::fromString(QCoreApplication::applicationDirPath()).parentDir() + / "Testing/QtMCUs") + .canonicalPath(); + const QStringList jsonFiles{QString::fromUtf8(armgcc_mimxrt1050_evk_freertos_json), QString::fromUtf8(iar_mimxrt1064_evk_freertos_json)}; @@ -201,7 +210,7 @@ const Id cxxLanguageId{ProjectExplorer::Constants::CXX_LANGUAGE_ID}; //Expand variables in a tested {targets, packages} pair auto expandTargetsAndPackages = [](Targets &targets, Packages &packages) { - McuSdkRepository{targets, packages}.expandVariables(); + McuSdkRepository{targets, packages}.expandVariablesAndWildcards(); }; void verifyIarToolchain(const McuToolChainPackagePtr &iarToolchainPackage) @@ -358,6 +367,30 @@ void verifyPackage(const McuPackagePtr &package, QCOMPARE(package->versions(), versions); } +// create fake files and folders for testing under the "testing_output_dir" folder +bool createFakePath(const FilePath& path, const bool is_file = false) +{ + if (path.exists()) + return true; + + //create an empty file or folder + if (is_file) { + if (!path.parentDir().createDir()) { + qWarning() << "Could not create the parent dir for testing file " << path; + return false; + } + if (!path.writeFileContents("placeholder text")) { + qWarning() << "Could not write to testing file " << path; + return false; + } + } else if (!path.createDir()) { + qWarning() << "Could not create testing dir " << path; + return false; + } + + return true; +}; + McuSupportTest::McuSupportTest() : targetFactory{settingsMockPtr} , compilerDescription{armGccLabel, armGccEnvVar, TOOLCHAIN_DIR_CMAKE_VARIABLE, armGccLabel, armGccDirectorySetting, {}, {}, {}, {}, false} @@ -415,6 +448,15 @@ McuSupportTest::McuSupportTest() testing::FLAGS_gmock_verbose = "error"; } +// load the test file +std::pair McuSupportTest::createTestingKitTargetsAndPackages(QByteArray test_file) +{ + McuTargetFactory factory(settingsMockPtr); + auto [targets, packages] = factory.createTargets(parseDescriptionJson(test_file), sdkPackagePtr); + expandTargetsAndPackages(targets, packages); + return {targets, packages}; +} + void McuSupportTest::initTestCase() { EXPECT_CALL(*freeRtosPackage, environmentVariableName()) @@ -455,6 +497,9 @@ void McuSupportTest::initTestCase() void McuSupportTest::init() { + McuSdkRepository::globalMacros() + ->insert("MCU_TESTING_FOLDER", + [dir = testing_output_dir.absoluteFilePath().toString()] { return dir; }); qDebug() << __func__; } @@ -1650,6 +1695,36 @@ void McuSupportTest::test_addToSystemPathFlag() QCOMPARE(freeRtosPackage.shouldAddToSystemPath, false); } +void McuSupportTest::test_processWildcards_data() +{ + QTest::addColumn("package_label"); + QTest::addColumn("path"); + QTest::addColumn("isFile"); + + QTest::newRow("\"*\" at the end") << "FAKE_WILDCARD_TEST_1" + << "folder-123" << false; + QTest::newRow("\"*\" in the middle") << "FAKE_WILDCARD_TEST_2" + << "file-123.exe" << true; + QTest::newRow("\"*\" at the start") << "FAKE_WILDCARD_TEST_3" + << "123-file.exe" << true; +} + +void McuSupportTest::test_processWildcards() +{ + QFETCH(QString, package_label); + QFETCH(QString, path); + QFETCH(bool, isFile); + + QVERIFY(createFakePath(testing_output_dir / "wildcards" / path, isFile)); + + auto [targets, packages] = createTestingKitTargetsAndPackages(wildcards_test_kit); + auto testWildcardsPackage = findOrDefault(packages, [&](const McuPackagePtr &pkg) { + return (pkg->label() == package_label); + }); + QVERIFY(testWildcardsPackage != nullptr); + QCOMPARE(testWildcardsPackage->path().toString(), FilePath(testing_output_dir / "wildcards" / path).toString()); +} + void McuSupportTest::test_nonemptyVersionDetector() { PackageDescription pkgDesc; diff --git a/src/plugins/mcusupport/test/unittest.h b/src/plugins/mcusupport/test/unittest.h index 50e823d10b2..088bad1475a 100644 --- a/src/plugins/mcusupport/test/unittest.h +++ b/src/plugins/mcusupport/test/unittest.h @@ -22,6 +22,7 @@ class McuSupportTest : public QObject public: McuSupportTest(); + std::pair createTestingKitTargetsAndPackages(QByteArray test_file); private slots: void initTestCase(); @@ -102,6 +103,8 @@ private slots: void test_differentValueForEachOperationSystem(); void test_addToSystemPathFlag(); + void test_processWildcards_data(); + void test_processWildcards(); void test_nonemptyVersionDetector(); void test_emptyVersionDetector(); diff --git a/src/plugins/mcusupport/test/wildcards_test_kit_json.h b/src/plugins/mcusupport/test/wildcards_test_kit_json.h new file mode 100644 index 00000000000..6737c39f56c --- /dev/null +++ b/src/plugins/mcusupport/test/wildcards_test_kit_json.h @@ -0,0 +1,74 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +// This file is intended for testing McuSupport logic by adding fake packages + +#pragma once + +constexpr auto wildcards_test_kit = R"( +{ + "qulVersion": "2.3.0", + "compatVersion": "1", + "platform": { + "id": "fake-platform", + "vendor": "fake-vendor", + "colorDepths": [32], + "cmakeEntries": [ + { + "label": "FAKE_WILDCARD_TEST_1", + "description": "Assert '*' is replaced by possible values", + "defaultValue": "%{MCU_TESTING_FOLDER}/wildcards/folder-*", + "envVar": "", + "type": "path" + }, + { + "label": "FAKE_WILDCARD_TEST_2", + "description": "Assert '*' is replaced by possible values", + "defaultValue": "%{MCU_TESTING_FOLDER}/wildcards/file-*.exe", + "envVar": "", + "type": "path" + }, + { + "label": "FAKE_WILDCARD_TEST_3", + "description": "Assert '*' is replaced by possible values", + "defaultValue": "%{MCU_TESTING_FOLDER}/wildcards/*-file.exe", + "envVar": "", + "type": "path" + } + ] + }, + "toolchain": { + "id": "fake-compiler", + "versions": [ + "0.0.1" + ], + "compiler": { + "cmakeVar": "QUL_TARGET_TOOLCHAIN_DIR", + "setting": "", + "label": "fake compiler", + "type": "path", + "optional": false + }, + "file": { + "cmakeVar": "CMAKE_TOOLCHAIN_FILE", + "type": "file", + "defaultValue": "", + "visible": false, + "optional": false + } + }, + "boardSdk": { + "envVar": "", + "setting": "", + "versions": [ + "0.0.1" + ], + "label": "", + "cmakeVar": "QUL_BOARD_SDK_DIR", + "type": "path", + "defaultValue": "", + "versionDetection": {}, + "optional": false + } +} +)";