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 <eike.ziller@qt.io>
This commit is contained in:
Yasser Grimes
2022-10-24 18:50:27 +03:00
parent e16a5c8d0e
commit 71ae73119e
8 changed files with 179 additions and 9 deletions

View File

@@ -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 &macros;
}
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())));
}
}
}

View File

@@ -40,7 +40,7 @@ public:
Targets mcuTargets;
Packages packages;
void expandVariables();
void expandVariablesAndWildcards();
MacroExpanderPtr getMacroExpander(const McuTarget &target);
static Macros *globalMacros();

View File

@@ -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"),

View File

@@ -593,7 +593,7 @@ McuSdkRepository targetsFromDescriptions(const QList<McuTargetDescription> &desc
}
McuSdkRepository repo{mcuTargets, mcuPackages};
repo.expandVariables();
repo.expandVariablesAndWildcards();
return repo;
}

View File

@@ -11,7 +11,6 @@
#include "mcutargetdescription.h"
#include <utils/algorithm.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <QVersionNumber>

View File

@@ -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 <baremetal/baremetalconstants.h>
@@ -44,13 +46,15 @@
#include <utils/algorithm.h>
#include <utils/environment.h>
#include <utils/filepath.h>
#include <utils/fileutils.h>
#include <QCoreApplication>
#include <QJsonArray>
#include <QJsonDocument>
#include <QtTest>
#include <algorithm>
#include <tuple>
#include <type_traits>
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<Targets, Packages> 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<QString>("package_label");
QTest::addColumn<QString>("path");
QTest::addColumn<bool>("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;

View File

@@ -22,6 +22,7 @@ class McuSupportTest : public QObject
public:
McuSupportTest();
std::pair<Targets, Packages> 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();

View File

@@ -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
}
}
)";