From df61a222c58d52c1ac73d341a7bb3f9103abeeeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20SVENSSON?= Date: Thu, 6 Jul 2023 20:50:30 +0200 Subject: [PATCH] Implement cbuild-pack.yml support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1122 Contributed by STMicroelectronics Signed-off-by: Torbjörn SVENSSON Co-authored-by: Erik MÅLLBERG --- tools/projmgr/include/ProjMgrParser.h | 26 +++ tools/projmgr/include/ProjMgrUtils.h | 35 +++ tools/projmgr/include/ProjMgrWorker.h | 19 +- tools/projmgr/include/ProjMgrYamlEmitter.h | 7 + tools/projmgr/include/ProjMgrYamlParser.h | 6 + .../include/ProjMgrYamlSchemaChecker.h | 1 + tools/projmgr/schemas/cbuild-pack.schema.json | 13 ++ tools/projmgr/schemas/common.schema.json | 26 +++ tools/projmgr/src/ProjMgr.cpp | 2 + tools/projmgr/src/ProjMgrUtils.cpp | 58 +++++ tools/projmgr/src/ProjMgrWorker.cpp | 118 ++++++++-- tools/projmgr/src/ProjMgrYamlEmitter.cpp | 132 ++++++++++- tools/projmgr/src/ProjMgrYamlParser.cpp | 74 ++++++ .../projmgr/src/ProjMgrYamlSchemaChecker.cpp | 3 + ...build_pack_invalid_content.cbuild-pack.yml | 8 + .../cbuild_pack_invalid_content.csolution.yml | 10 + ...uild_pack_invalid_content2.cbuild-pack.yml | 1 + ...cbuild_pack_invalid_content2.csolution.yml | 10 + ...pack_with_disallowed_field.cbuild-pack.yml | 9 + ...d_pack_with_disallowed_field.csolution.yml | 10 + ...ack_with_disallowed_field2.cbuild-pack.yml | 4 + ..._pack_with_disallowed_field2.csolution.yml | 10 + ...pack_with_unmatched_vendor.cbuild-pack.yml | 8 + ...d_pack_with_unmatched_vendor.csolution.yml | 10 + .../lock_pack_version.cbuild-pack.yml | 8 + .../lock_pack_version.csolution.yml | 12 + .../pack_lock_with_added_pack.cbuild-pack.yml | 8 + .../pack_lock_with_added_pack.cproject.yml | 8 + .../pack_lock_with_added_pack.csolution.yml | 11 + ...pack_lock_with_version_range.csolution.yml | 11 + ..._pack_lock_with_added_pack.cbuild-pack.yml | 8 + ...ect_pack_lock_with_added_pack.cproject.yml | 11 + ...ct_pack_lock_with_added_pack.csolution.yml | 8 + ...pack_lock_with_version_range.csolution.yml | 11 + .../project_with_dfp_components.cproject.yml | 7 + ...ck_lock_with_version_range.cbuild-pack.yml | 12 + ...ck_lock_with_version_range.cbuild-pack.yml | 12 + .../ref/project_with_dfp_components+CM0.cprj | 31 +++ .../TestSolution/ref/test.cbuild-pack.yml | 7 + .../ref/test2.Debug+TestGen_export.cprj | 2 +- .../ref/test_pack_selection.cbuild-pack.yml | 11 + tools/projmgr/test/src/ProjMgrTestEnv.cpp | 7 + tools/projmgr/test/src/ProjMgrUnitTests.cpp | 214 ++++++++++++++++++ .../test/src/ProjMgrUtilsUnitTests.cpp | 171 ++++++++++++++ .../test/src/ProjMgrWorkerUnitTests.cpp | 28 +++ 45 files changed, 1159 insertions(+), 39 deletions(-) create mode 100644 tools/projmgr/schemas/cbuild-pack.schema.json create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content2.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content2.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field2.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field2.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_unmatched_vendor.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_unmatched_vendor.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/lock_pack_version.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/lock_pack_version.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.cproject.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_version_range.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.cproject.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_version_range.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/project_with_dfp_components.cproject.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/ref/pack_lock_with_version_range.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/ref/project_pack_lock_with_version_range.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/PackLocking/ref/project_with_dfp_components+CM0.cprj create mode 100644 tools/projmgr/test/data/TestSolution/ref/test.cbuild-pack.yml create mode 100644 tools/projmgr/test/data/TestSolution/ref/test_pack_selection.cbuild-pack.yml diff --git a/tools/projmgr/include/ProjMgrParser.h b/tools/projmgr/include/ProjMgrParser.h index cc938085e..679b44587 100644 --- a/tools/projmgr/include/ProjMgrParser.h +++ b/tools/projmgr/include/ProjMgrParser.h @@ -80,6 +80,16 @@ struct PackItem { TypeFilter type; }; +/** + * @brief resolved pack item containing, + * pack ID, + * list of selected-by expressions (original expressions causing this pack to be added) +*/ +struct ResolvedPackItem { + std::string pack; + std::vector selectedBy; +}; + /** * @brief processor item containing * processor fpu, @@ -294,6 +304,21 @@ struct ContextDesc { TypeFilter type; }; +/** + * @brief cbuild pack descriptor containing + * filename, + * full path to cbuild pack file, + * containing directory, + * list of resolved packs +*/ +struct CbuildPackItem { + std::string name; + std::string path; + std::string directory; + + std::vector packs; +}; + /** * @brief default item containing * cdefault path, @@ -334,6 +359,7 @@ struct CsolutionItem { std::vector packs; bool enableCdefault; GeneratorsItem generators; + CbuildPackItem cbuildPack; }; /** diff --git a/tools/projmgr/include/ProjMgrUtils.h b/tools/projmgr/include/ProjMgrUtils.h index 2d69f685f..487c0baeb 100644 --- a/tools/projmgr/include/ProjMgrUtils.h +++ b/tools/projmgr/include/ProjMgrUtils.h @@ -57,6 +57,18 @@ struct OutputTypes { OutputType cmse; }; +/** + * @brief pack info containing + * pack name, + * pack vendor, + * pack version +*/ +struct PackInfo { + std::string name; + std::string vendor; + std::string version; +}; + /** * @brief vector of ConnectionsCollection */ @@ -299,6 +311,29 @@ class ProjMgrUtils { const std::vector& allContexts, const std::string& contextReplace); + + /** + * @brief convert a pack ID to a pack info + * @param packId the pack id (YML format) + * @param packInfo the pack info struct + * @return true on success + */ + static bool ConvertToPackInfo(const std::string& packId, PackInfo& packInfo); + + /** + * @brief check if the two pack info structs match + * @param exactPackInfo fully qualified pack ID, without wildcards or ranges + * @param packInfoToMatch pack ID, may include wildcards or ranges + * @return true if match + */ + static bool IsMatchingPackInfo(const PackInfo& exactPackInfo, const PackInfo& packInfoToMatch); + + /** + * @brief convert version in YML format to CPRJ range format + * @param version version in YML format + * @return version in CPRJ range format + */ + static std::string ConvertToVersionRange(const std::string& version); protected: static std::string ConstructID(const std::vector>& elements); /** diff --git a/tools/projmgr/include/ProjMgrWorker.h b/tools/projmgr/include/ProjMgrWorker.h index 1391a4287..093f03a4d 100644 --- a/tools/projmgr/include/ProjMgrWorker.h +++ b/tools/projmgr/include/ProjMgrWorker.h @@ -86,18 +86,6 @@ struct ToolchainItem { std::string config; }; -/** - * @brief pack info containing - * pack name, - * pack vendor, - * pack version -*/ -struct PackInfo { - std::string name; - std::string vendor; - std::string version; -}; - /** * @brief package item containing * pack information pack, @@ -272,7 +260,8 @@ struct ContextTypesItem { * linker options, * map of variables, * external generator directory, - * boolean processed precedences + * boolean processed precedences, + * map of fully qualified pack ID to pack ID with version range */ struct ContextItem { CdefaultItem* cdefault = nullptr; @@ -316,6 +305,7 @@ struct ContextItem { std::map variables; StrMap extGenDir; bool precedences; + std::map eagerlyReplacedPackIdMap; }; /** @@ -672,7 +662,7 @@ class ProjMgrWorker { bool ProcessDevicePrecedence(StringCollection& item); bool ProcessBoardPrecedence(StringCollection& item); bool ProcessToolchain(ContextItem& context); - bool ProcessPackages(ContextItem& context); + bool ProcessPackages(ContextItem& context, const std::string& packRoot); bool ProcessComponents(ContextItem& context); RteComponent* ProcessComponent(ContextItem& context, ComponentItem& item, RteComponentMap& componentMap); bool ProcessGpdsc(ContextItem& context); @@ -755,6 +745,7 @@ class ProjMgrWorker { void CheckTypeFilterSpelling(const TypeFilter& typeFilter); void CheckCompilerFilterSpelling(const std::string& compiler); bool ProcessGeneratedLayers(ContextItem& context); + bool IsPackInCbuildPack(const PackItem& needle, const std::vector& resolvedPacks, ResolvedPackItem& match); }; #endif // PROJMGRWORKER_H diff --git a/tools/projmgr/include/ProjMgrYamlEmitter.h b/tools/projmgr/include/ProjMgrYamlEmitter.h index 0d4242483..be3a455f7 100644 --- a/tools/projmgr/include/ProjMgrYamlEmitter.h +++ b/tools/projmgr/include/ProjMgrYamlEmitter.h @@ -60,6 +60,13 @@ class ProjMgrYamlEmitter { * @return true if executed successfully */ static bool GenerateCbuildSet(ProjMgrParser& parser, const std::vector contexts, const std::string& selectedCompiler); + + /** + * @brief generate cbuild pack file + * @param contexts vector with pointers to contexts + * @return true if executed successfully + */ + static bool GenerateCbuildPack(ProjMgrParser& parser, const std::vector contexts); }; #endif // PROJMGRYAMLEMITTER_H diff --git a/tools/projmgr/include/ProjMgrYamlParser.h b/tools/projmgr/include/ProjMgrYamlParser.h index 0160fa994..7941c8f76 100644 --- a/tools/projmgr/include/ProjMgrYamlParser.h +++ b/tools/projmgr/include/ProjMgrYamlParser.h @@ -30,6 +30,7 @@ static constexpr const char* YAML_CBUILDS = "cbuilds"; static constexpr const char* YAML_CBUILD = "cbuild"; static constexpr const char* YAML_CBUILD_GENS = "cbuild-gens"; static constexpr const char* YAML_CBUILD_GEN = "cbuild-gen"; +static constexpr const char* YAML_CBUILD_PACK = "cbuild-pack"; static constexpr const char* YAML_CBUILD_SET = "cbuild-set"; static constexpr const char* YAML_CDEFAULT = "cdefault"; static constexpr const char* YAML_CLAYERS = "clayers"; @@ -118,6 +119,8 @@ static constexpr const char* YAML_PROJECTS = "projects"; static constexpr const char* YAML_PROJECT_TYPE = "project-type"; static constexpr const char* YAML_PROVIDES = "provides"; static constexpr const char* YAML_REGIONS = "regions"; +static constexpr const char* YAML_RESOLVED_PACK = "resolved-pack"; +static constexpr const char* YAML_RESOLVED_PACKS = "resolved-packs"; static constexpr const char* YAML_RTE = "rte"; static constexpr const char* YAML_RUN = "run"; static constexpr const char* YAML_SCOPE = "scope"; @@ -209,9 +212,11 @@ class ProjMgrYamlParser { std::map& generators, bool checkSchema); protected: + bool ParseCbuildPack(const std::string& input, CbuildPackItem& cbuildPack, bool checkSchema); void ParseMisc(const YAML::Node& parent, std::vector& misc); void ParseDefine(const YAML::Node& parent, std::vector& define); void ParsePacks(const YAML::Node& parent, const std::string& file, std::vector& packs); + void ParseResolvedPacks(const YAML::Node& parent, std::vector& resolvedPacks); void ParseProcessor(const YAML::Node& parent, ProcessorItem& processor); void ParseBoolean(const YAML::Node& parent, const std::string& key, bool& value, bool def); void ParseString(const YAML::Node& parent, const std::string& key, std::string& value); @@ -241,6 +246,7 @@ class ProjMgrYamlParser { bool ValidateCsolution(const std::string& input, const YAML::Node& root); bool ValidateCproject(const std::string& input, const YAML::Node& root); bool ValidateClayer(const std::string& input, const YAML::Node& root); + bool ValidateCbuildPack(const std::string& input, const YAML::Node& root); bool ValidateCbuildSet(const std::string& input, const YAML::Node& root); bool ValidateKeys(const std::string& input, const YAML::Node& parent, const std::set& keys); bool ValidateSequence(const std::string& input, const YAML::Node& parent, const std::string& seqKey); diff --git a/tools/projmgr/include/ProjMgrYamlSchemaChecker.h b/tools/projmgr/include/ProjMgrYamlSchemaChecker.h index ea2d8264f..4acd2ca2d 100644 --- a/tools/projmgr/include/ProjMgrYamlSchemaChecker.h +++ b/tools/projmgr/include/ProjMgrYamlSchemaChecker.h @@ -21,6 +21,7 @@ class ProjMgrYamlSchemaChecker { PROJECT, LAYER, BUILD, + BUILD_PACK, BUILDIDX, BUILDSET, GENERATOR, diff --git a/tools/projmgr/schemas/cbuild-pack.schema.json b/tools/projmgr/schemas/cbuild-pack.schema.json new file mode 100644 index 000000000..338afc9f6 --- /dev/null +++ b/tools/projmgr/schemas/cbuild-pack.schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/schemas/projmgr/2.1.0/tools/projmgr/schemas/cbuild-pack.schema.json", + "title": "CMSIS cbuild-pack", + "description": "file containing all pack versions used, used for pack locking", + "version": "2.1.0", + "properties": { + "cbuild-pack": { + "$ref": "./common.schema.json#/definitions/BuildPackDescType" + } + }, + "required": [ "cbuild-pack" ] +} diff --git a/tools/projmgr/schemas/common.schema.json b/tools/projmgr/schemas/common.schema.json index 4fd0a5cdd..a7af70866 100644 --- a/tools/projmgr/schemas/common.schema.json +++ b/tools/projmgr/schemas/common.schema.json @@ -899,6 +899,32 @@ } } }, + "BuildPackDescType": { + "type": "object", + "properties": { + "resolved-packs": { "$ref": "#/definitions/ResolvedPacksType" } + }, + "additionalProperties": false, + "required": [ "resolved-packs" ] + }, + "ResolvedPacksType": { + "type": "array", + "uniqueItems": true, + "items": { "$ref": "#/definitions/ResolvedPackType" } + }, + "ResolvedPackType": { + "type": "object", + "properties": { + "resolved-pack": { "$ref": "#/definitions/PackID" }, + "selected-by": { + "type": "array", + "uniqueItems": true, + "items": { "$ref": "#/definitions/PackID" } + } + }, + "additionalProperties": false, + "required": [ "resolved-pack" ] + }, "BuildPacksType": { "type": "array", "uniqueItems": true, diff --git a/tools/projmgr/src/ProjMgr.cpp b/tools/projmgr/src/ProjMgr.cpp index 2417d9493..c67c57333 100644 --- a/tools/projmgr/src/ProjMgr.cpp +++ b/tools/projmgr/src/ProjMgr.cpp @@ -546,6 +546,8 @@ bool ProjMgr::RunConvert(void) { if (!m_emitter.GenerateCbuild(contextItem)) { return false; } + + m_emitter.GenerateCbuildPack(m_parser, m_processedContexts); } return !error; diff --git a/tools/projmgr/src/ProjMgrUtils.cpp b/tools/projmgr/src/ProjMgrUtils.cpp index 478a1b1a7..e3d9111c5 100644 --- a/tools/projmgr/src/ProjMgrUtils.cpp +++ b/tools/projmgr/src/ProjMgrUtils.cpp @@ -420,3 +420,61 @@ vector ProjMgrUtils::GetFilteredContexts( } return selectedContexts; } + +bool ProjMgrUtils::ConvertToPackInfo(const string& packId, PackInfo& packInfo) { + string packInfoStr = packId; + if (packInfoStr.find("::") != string::npos) { + packInfo.vendor = RteUtils::RemoveSuffixByString(packInfoStr, "::"); + packInfoStr = RteUtils::RemovePrefixByString(packInfoStr, "::"); + packInfo.name = RteUtils::GetPrefix(packInfoStr, '@'); + } else { + packInfo.vendor = RteUtils::GetPrefix(packInfoStr, '@'); + } + packInfo.version = RteUtils::GetSuffix(packInfoStr, '@'); + + return true; +} + +bool ProjMgrUtils::IsMatchingPackInfo(const PackInfo& exactPackInfo, const PackInfo& packInfoToMatch) { + // Check if vendor matches + if (packInfoToMatch.vendor != exactPackInfo.vendor) { + // Not same vendor + return false; + } + + // Check if pack name matches + if (!packInfoToMatch.name.empty()) { + if (WildCards::IsWildcardPattern(packInfoToMatch.name)) { + // Check if filter matches + if (!WildCards::Match(packInfoToMatch.name, exactPackInfo.name)) { + // Name filter does not match needle + return false; + } + } else if (packInfoToMatch.name != exactPackInfo.name) { + // Not same pack name + return false; + } + } + + // Check if version matches + string reqVersionRange = ConvertToVersionRange(packInfoToMatch.version); + if (!reqVersionRange.empty() && VersionCmp::RangeCompare(exactPackInfo.version, reqVersionRange) != 0) { + // Version out of range + return false; + } + + // Needle matches this resolved pack + return true; +} + +string ProjMgrUtils::ConvertToVersionRange(const string& version) { + string versionRange = version; + if (!versionRange.empty()) { + if (versionRange.find(">=") != string::npos) { + versionRange = versionRange.substr(2); + } else { + versionRange = versionRange + ":" + versionRange; + } + } + return versionRange; +} diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index 5d5812734..97336634b 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -222,21 +222,14 @@ void ProjMgrWorker::SetEnvironmentVariables(const StrVec& envVars) { } bool ProjMgrWorker::GetRequiredPdscFiles(ContextItem& context, const std::string& packRoot, std::set& errMsgs) { - if (!ProcessPackages(context)) { + if (!ProcessPackages(context, packRoot)) { return false; } for (auto packItem : context.packRequirements) { // parse required version range const auto& pack = packItem.pack; const auto& reqVersion = pack.version; - string reqVersionRange; - if (!reqVersion.empty()) { - if (reqVersion.find(">=") != string::npos) { - reqVersionRange = reqVersion.substr(2); - } else { - reqVersionRange = reqVersion + ":" + reqVersion; - } - } + string reqVersionRange = ProjMgrUtils::ConvertToVersionRange(reqVersion); if (packItem.path.empty()) { bool bPackFilter = (pack.name.empty() || WildCards::IsWildcardPattern(pack.name)); @@ -1297,7 +1290,43 @@ bool ProjMgrWorker::ProcessDevicePrecedence(StringCollection& item) { return true; } -bool ProjMgrWorker::ProcessPackages(ContextItem& context) { +bool ProjMgrWorker::IsPackInCbuildPack(const PackItem& needle, const vector& resolvedPacks, ResolvedPackItem& match) { + // This should never happen, assuming that the parser validates the pack ID + if (needle.pack.empty()) { + return false; + } + + // Only consider non-project-local packs + if (!needle.path.empty()) { + return false; + } + + // First try exact matching + for (const auto& resolvedPack : resolvedPacks) { + if (find(resolvedPack.selectedBy.cbegin(), resolvedPack.selectedBy.cend(), needle.pack) != resolvedPack.selectedBy.end()) { + match = resolvedPack; + return true; + } + } + + // Next, try fuzzy matching + PackInfo needleInfo; + ProjMgrUtils::ConvertToPackInfo(needle.pack, needleInfo); + + for (const auto& resolvedPack : resolvedPacks) { + PackInfo resolvedInfo; + ProjMgrUtils::ConvertToPackInfo(resolvedPack.pack, resolvedInfo); + + if (ProjMgrUtils::IsMatchingPackInfo(resolvedInfo, needleInfo)) { + match = resolvedPack; + return true; + } + } + + return false; +} + +bool ProjMgrWorker::ProcessPackages(ContextItem& context, const string& packRoot) { vector packRequirements; // Solution package requirements @@ -1312,8 +1341,7 @@ bool ProjMgrWorker::ProcessPackages(ContextItem& context) { for (const auto& [_, clayer] : context.clayers) { InsertPackRequirements(clayer->packs, packRequirements, clayer->directory); } - AddPackRequirements(context, packRequirements); - return true; + return AddPackRequirements(context, packRequirements); } void ProjMgrWorker::InsertPackRequirements(const vector& src, vector& dst, string base) { @@ -1326,6 +1354,8 @@ void ProjMgrWorker::InsertPackRequirements(const vector& src, vector

packRequirements) { + const vector& resolvedPacks = context.csolution->cbuildPack.packs; + // Filter context specific package requirements vector packages; for (const auto& packItem : packRequirements) { @@ -1333,22 +1363,66 @@ bool ProjMgrWorker::AddPackRequirements(ContextItem& context, const vectordirectory + "/"); + if (!RteFsUtils::Exists(package.path)) { + ProjMgrLogger::Error("pack path: " + packageEntry.path + " does not exist"); + return false; + } + ProjMgrUtils::ConvertToPackInfo(packageEntry.pack, package.pack); + string pdscFile = package.pack.vendor + '.' + package.pack.name + ".pdsc"; + RteFsUtils::NormalizePath(pdscFile, package.path + "/"); + if (!RteFsUtils::Exists(pdscFile)) { + ProjMgrLogger::Error("pdsc file was not found in: " + packageEntry.path); + return false; + } + context.packRequirements.push_back(package); + } + } + + // Add wildcard entries for (const auto& packageEntry : packages) { PackageItem package; package.path = packageEntry.path; - auto& pack = package.pack; - string packInfoStr = packageEntry.pack; - if (packInfoStr.find("::") != string::npos) { - pack.vendor = RteUtils::RemoveSuffixByString(packInfoStr, "::"); - packInfoStr = RteUtils::RemovePrefixByString(packInfoStr, "::"); - pack.name = RteUtils::GetPrefix(packInfoStr, '@'); - } else { - pack.vendor = RteUtils::GetPrefix(packInfoStr, '@'); + ProjMgrUtils::ConvertToPackInfo(packageEntry.pack, package.pack); + + if (package.pack.name.empty() || WildCards::IsWildcardPattern(package.pack.name)) { + context.packRequirements.push_back(package); } - pack.version = RteUtils::GetSuffix(packInfoStr, '@'); - context.packRequirements.push_back(package); } + return true; } diff --git a/tools/projmgr/src/ProjMgrYamlEmitter.cpp b/tools/projmgr/src/ProjMgrYamlEmitter.cpp index a7b368b35..77260cc76 100644 --- a/tools/projmgr/src/ProjMgrYamlEmitter.cpp +++ b/tools/projmgr/src/ProjMgrYamlEmitter.cpp @@ -35,7 +35,7 @@ class ProjMgrYamlBase { const string FormatPath(const string& original, const string& directory); bool CompareFile(const string& filename, const YAML::Node& rootNode); bool CompareNodes(const YAML::Node& lhs, const YAML::Node& rhs); - bool WriteFile(YAML::Node& rootNode, const std::string& filename); + bool WriteFile(YAML::Node& rootNode, const std::string& filename, const std::string& schemaName=""); const bool m_useAbsolutePaths; }; @@ -71,6 +71,121 @@ class ProjMgrYamlCbuildIdx : public ProjMgrYamlBase { ProjMgrYamlCbuildIdx(YAML::Node node, const vector processedContexts, ProjMgrParser& parser, const string& directory); }; +class ProjMgrYamlCbuildPack : public ProjMgrYamlBase { +private: + friend class ProjMgrYamlEmitter; + ProjMgrYamlCbuildPack(YAML::Node node, const vector processedContexts, ProjMgrParser& parser); +}; + + +ProjMgrYamlCbuildPack::ProjMgrYamlCbuildPack(YAML::Node node, const vector processedContexts, ProjMgrParser& parser) : + ProjMgrYamlBase(false) +{ + const auto& csolution = parser.GetCsolution(); + + struct ModelItem { + PackInfo info; + ResolvedPackItem resolvedPack; + }; + + map model; + + // Stage 1: Add all known items from the current cbuild pack file + for (auto& resolvedItem : csolution.cbuildPack.packs) { + ModelItem modelItem; + ProjMgrUtils::ConvertToPackInfo(resolvedItem.pack, modelItem.info); + modelItem.resolvedPack = resolvedItem; + ProjMgrUtils::PushBackUniquely(modelItem.resolvedPack.selectedBy, resolvedItem.pack); + model[resolvedItem.pack] = modelItem; + } + + // Stage 2: Process packs that are required by used components + for (const auto& context : processedContexts) { + for (const auto& [packId, _] : context->packages) { +// TODO: Skip if project local packs + if (model.find(packId) == model.end()) { + // Add pack + ModelItem modelItem; + ProjMgrUtils::ConvertToPackInfo(packId, modelItem.info); + modelItem.resolvedPack.pack = packId; + modelItem.resolvedPack.selectedBy.push_back(packId); + model[packId] = modelItem; + } + } + } + + // Stage 3: Add all packs that do not contain wildcard and also not used by any component + for (const auto& context : processedContexts) { + for (const auto& packItem : context->packRequirements) { + // Skip project local packs + if (!packItem.path.empty()) { + continue; + } + + const auto& reqInfo = packItem.pack; + + // Skip wildcard packs + if (reqInfo.name.empty() || WildCards::IsWildcardPattern(reqInfo.name)) { + continue; + } + + const string packId = RtePackage::ComposePackageID(reqInfo.vendor, reqInfo.name, reqInfo.version); + if (model.find(packId) == model.end()) { + // Pack does not have a version range, so add it + ModelItem modelItem; + ProjMgrUtils::ConvertToPackInfo(packId, modelItem.info); + modelItem.resolvedPack.pack = packId; + modelItem.resolvedPack.selectedBy.push_back(packId); + model[packId] = modelItem; + } + } + } + + // Stage 4: Add all original expressions that was eagerly replaced + for (const auto& context : processedContexts) { + for (const auto& [key, val] : context->eagerlyReplacedPackIdMap) { + if (model.find(val) != model.end()) { + ProjMgrUtils::PushBackUniquely(model[val].resolvedPack.selectedBy, key); + } + } + } + + // Stage 5: Process all wildcard patterns from user and add to selected-by list + for (const auto& context : processedContexts) { + for (const auto& packItem : context->packRequirements) { + // Skip project local packs + if (!packItem.path.empty()) { + continue; + } + + const PackInfo& reqInfo = packItem.pack; + if (reqInfo.name.empty() || WildCards::IsWildcardPattern(reqInfo.name)) { + const string packId = RtePackage::ComposePackageID(reqInfo.vendor, reqInfo.name, reqInfo.version); + + for (auto& [key, val] : model) { + if (ProjMgrUtils::IsMatchingPackInfo(val.info, reqInfo)) { + ProjMgrUtils::PushBackUniquely(val.resolvedPack.selectedBy, packId); + } + } + } + } + } + + // Produce the yml output + for (auto& [packId, modelItem] : model) { + YAML::Node resolvedPackNode; + auto& packItem = modelItem.resolvedPack; + + SetNodeValue(resolvedPackNode[YAML_RESOLVED_PACK], packId); + + sort(packItem.selectedBy.begin(), packItem.selectedBy.end()); + SetNodeValue(resolvedPackNode[YAML_SELECTED_BY], packItem.selectedBy); + + node[YAML_RESOLVED_PACKS].push_back(resolvedPackNode); + } +} + + ProjMgrYamlBase::ProjMgrYamlBase(bool useAbsolutePaths) : m_useAbsolutePaths(useAbsolutePaths) { } @@ -584,7 +699,7 @@ bool ProjMgrYamlBase::CompareNodes(const YAML::Node& lhs, const YAML::Node& rhs) return (lhsData == rhsData) ? true : false; } -bool ProjMgrYamlBase::WriteFile(YAML::Node& rootNode, const std::string& filename) { +bool ProjMgrYamlBase::WriteFile(YAML::Node& rootNode, const std::string& filename, const std::string& schemaName) { // Compare yaml contents if (!CompareFile(filename, rootNode)) { if (!RteFsUtils::MakeSureFilePath(filename)) { @@ -596,6 +711,9 @@ bool ProjMgrYamlBase::WriteFile(YAML::Node& rootNode, const std::string& filenam ProjMgrLogger::Error(filename, "file cannot be written"); return false; } + if (!schemaName.empty()) { + fileStream << "# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/" << schemaName << ".schema.json" << endl << endl; + } YAML::Emitter emitter; emitter << rootNode; fileStream << emitter.c_str(); @@ -696,3 +814,13 @@ bool ProjMgrYamlEmitter::GenerateCbuildGenIndex(ProjMgrParser& parser, const vec ProjMgrYamlCbuild cbuild(rootNode[YAML_BUILD_GEN_IDX], siblings, type, output, gendir); return cbuild.WriteFile(rootNode, filename); } + +bool ProjMgrYamlEmitter::GenerateCbuildPack(ProjMgrParser& parser, const vector contexts) { + // generate cbuild-pack.yml + const string& filename = parser.GetCsolution().directory + "/" + parser.GetCsolution().name + ".cbuild-pack.yml"; + + YAML::Node rootNode; + ProjMgrYamlCbuildPack cbuildPack(rootNode[YAML_CBUILD_PACK], contexts, parser); + + return cbuildPack.WriteFile(rootNode, filename, "cbuild-pack"); +} diff --git a/tools/projmgr/src/ProjMgrYamlParser.cpp b/tools/projmgr/src/ProjMgrYamlParser.cpp index ce2463f20..cf99af3bc 100644 --- a/tools/projmgr/src/ProjMgrYamlParser.cpp +++ b/tools/projmgr/src/ProjMgrYamlParser.cpp @@ -53,6 +53,14 @@ bool ProjMgrYamlParser::ParseCdefault(const string& input, bool ProjMgrYamlParser::ParseCsolution(const string& input, CsolutionItem& csolution, bool checkSchema) { + + string cbuildPackFile = RteUtils::RemoveSuffixByString(input, ".csolution.yml") + ".cbuild-pack.yml"; + if (fs::exists(cbuildPackFile)) { + if (!ParseCbuildPack(cbuildPackFile, csolution.cbuildPack, checkSchema)) { + return false; + } + } + try { // Validate file schema if (checkSchema && @@ -102,6 +110,36 @@ bool ProjMgrYamlParser::ParseCsolution(const string& input, return true; } +bool ProjMgrYamlParser::ParseCbuildPack(const string& input, + CbuildPackItem& cbuildPack, bool checkSchema) { + try { + // Validate file schema + if (checkSchema && + !ProjMgrYamlSchemaChecker().Validate( + input, ProjMgrYamlSchemaChecker::FileType::BUILD_PACK)) { + return false; + } + + cbuildPack.path = RteFsUtils::MakePathCanonical(input); + cbuildPack.directory = RteFsUtils::ParentPath(cbuildPack.path); + cbuildPack.name = fs::path(input).stem().stem().stem().generic_string(); + + const YAML::Node& root = YAML::LoadFile(input); + if (!ValidateCbuildPack(input, root)) { + return false; + } + + const YAML::Node& cbuildPackNode = root[YAML_CBUILD_PACK]; + + ParseResolvedPacks(cbuildPackNode, cbuildPack.packs); + + } catch (YAML::Exception& e) { + ProjMgrLogger::Error(input, e.mark.line + 1, e.mark.column + 1, e.msg); + return false; + } + return true; +} + bool ProjMgrYamlParser::ParseCproject(const string& input, CsolutionItem& csolution, map& cprojects, bool single, bool checkSchema) { @@ -537,6 +575,18 @@ void ProjMgrYamlParser::ParseMisc(const YAML::Node& parent, vector& mi } } +void ProjMgrYamlParser::ParseResolvedPacks(const YAML::Node& parent, vector& packs) { + if (parent[YAML_RESOLVED_PACKS].IsDefined()) { + const YAML::Node& packsNode = parent[YAML_RESOLVED_PACKS]; + for (const auto& packEntry : packsNode) { + ResolvedPackItem packItem; + ParseString(packEntry, YAML_RESOLVED_PACK, packItem.pack); + ParseVector(packEntry, YAML_SELECTED_BY, packItem.selectedBy); + packs.push_back(packItem); + } + } +} + void ProjMgrYamlParser::ParsePacks(const YAML::Node& parent, const string& file, vector& packs) { if (parent[YAML_PACKS].IsDefined()) { const YAML::Node& packNode = parent[YAML_PACKS]; @@ -930,6 +980,10 @@ const set cbuildSetKeys = { YAML_COMPILER, }; +const set cbuildPackKeys = { + YAML_RESOLVED_PACKS, +}; + const set targetTypeKeys = { YAML_TYPE, YAML_DEVICE, @@ -1014,6 +1068,11 @@ const set packsKeys = { YAML_NOTFORCONTEXT, }; +const set resolvedPacksKeys = { + YAML_RESOLVED_PACK, + YAML_SELECTED_BY, +}; + const set componentsKeys = { YAML_COMPONENT, YAML_CONDITION, @@ -1103,6 +1162,7 @@ const map> sequences = { {YAML_BUILDTYPES, buildTypeKeys}, {YAML_MISC, miscKeys}, {YAML_PACKS, packsKeys}, + {YAML_RESOLVED_PACKS, resolvedPacksKeys}, {YAML_COMPONENTS, componentsKeys}, {YAML_CONNECTIONS, connectionsKeys}, {YAML_LAYERS, layersKeys}, @@ -1176,6 +1236,20 @@ bool ProjMgrYamlParser::ValidateClayer(const string& input, const YAML::Node& ro return true; } +bool ProjMgrYamlParser::ValidateCbuildPack(const string& input, const YAML::Node& root) { + const set rootKeys = { + YAML_CBUILD_PACK, + }; + if (!ValidateKeys(input, root, rootKeys)) { + return false; + } + const YAML::Node& cbuildPackNode = root[YAML_CBUILD_PACK]; + if (!ValidateKeys(input, cbuildPackNode, cbuildPackKeys)) { + return false; + } + return true; +} + bool ProjMgrYamlParser::ValidateCbuildSet(const string& input, const YAML::Node& root) { const set rootKeys = { YAML_CBUILD_SET, diff --git a/tools/projmgr/src/ProjMgrYamlSchemaChecker.cpp b/tools/projmgr/src/ProjMgrYamlSchemaChecker.cpp index 81b4fade8..441ce2c4d 100644 --- a/tools/projmgr/src/ProjMgrYamlSchemaChecker.cpp +++ b/tools/projmgr/src/ProjMgrYamlSchemaChecker.cpp @@ -77,6 +77,9 @@ bool ProjMgrYamlSchemaChecker::GetSchemaFile(string& schemaFile, const ProjMgrYa case ProjMgrYamlSchemaChecker::FileType::BUILDIDX: schemaFileName = "cbuild-idx.schema.json"; break; + case ProjMgrYamlSchemaChecker::FileType::BUILD_PACK: + schemaFileName = "cbuild-pack.schema.json"; + break; case ProjMgrYamlSchemaChecker::FileType::BUILDSET: schemaFileName = "cbuildset.schema.json"; break; diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content.cbuild-pack.yml new file mode 100644 index 000000000..a67ca62a2 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content.cbuild-pack.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + resolvd-packs: + - resolved-pack: ARM::RteTest_DFP@0.1.1 + selected-by: + - ARM::RteTest_DFP + - ARM::RteTest_DFP@0.1.1 diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content.csolution.yml new file mode 100644 index 000000000..f80fca762 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content.csolution.yml @@ -0,0 +1,10 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + packs: + - pack: ARM::RteTest_DFP + projects: + - project: ./project_with_dfp_components.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content2.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content2.cbuild-pack.yml new file mode 100644 index 000000000..257cc5642 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content2.cbuild-pack.yml @@ -0,0 +1 @@ +foo diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content2.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content2.csolution.yml new file mode 100644 index 000000000..f80fca762 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_invalid_content2.csolution.yml @@ -0,0 +1,10 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + packs: + - pack: ARM::RteTest_DFP + projects: + - project: ./project_with_dfp_components.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field.cbuild-pack.yml new file mode 100644 index 000000000..a1378b268 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field.cbuild-pack.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +misc: 1 +cbuild-pack: + resolved-packs: + - resolved-pack: ARM::RteTest_DFP@0.1.1 + selected-by: + - ARM::RteTest_DFP + - ARM::RteTest_DFP@0.1.1 diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field.csolution.yml new file mode 100644 index 000000000..f80fca762 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field.csolution.yml @@ -0,0 +1,10 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + packs: + - pack: ARM::RteTest_DFP + projects: + - project: ./project_with_dfp_components.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field2.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field2.cbuild-pack.yml new file mode 100644 index 000000000..4a582983f --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field2.cbuild-pack.yml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + misc: 1 diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field2.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field2.csolution.yml new file mode 100644 index 000000000..f80fca762 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_disallowed_field2.csolution.yml @@ -0,0 +1,10 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + packs: + - pack: ARM::RteTest_DFP + projects: + - project: ./project_with_dfp_components.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_unmatched_vendor.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_unmatched_vendor.cbuild-pack.yml new file mode 100644 index 000000000..d9f10d4a5 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_unmatched_vendor.cbuild-pack.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + resolved-packs: + - resolved-pack: SomeVendor::RteTest_DFP@0.1.1 + selected-by: + - SomeVendor::RteTest_DFP + - SomeVendor::RteTest_DFP@0.1.1 diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_unmatched_vendor.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_unmatched_vendor.csolution.yml new file mode 100644 index 000000000..f80fca762 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/cbuild_pack_with_unmatched_vendor.csolution.yml @@ -0,0 +1,10 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + packs: + - pack: ARM::RteTest_DFP + projects: + - project: ./project_with_dfp_components.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/lock_pack_version.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/lock_pack_version.cbuild-pack.yml new file mode 100644 index 000000000..761d10392 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/lock_pack_version.cbuild-pack.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + resolved-packs: + - resolved-pack: ARM::RteTest_DFP@0.1.1 + selected-by: + - ARM::RteTest_DFP + - ARM::RteTest_DFP@0.1.1 diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/lock_pack_version.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/lock_pack_version.csolution.yml new file mode 100644 index 000000000..8c05b801e --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/lock_pack_version.csolution.yml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + packs: + - pack: ARM::RteTest_DFP + - pack: ARM::RteTest + path: ../../SolutionSpecificPack2 + projects: + - project: ./project_with_dfp_components.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.cbuild-pack.yml new file mode 100644 index 000000000..761d10392 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.cbuild-pack.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + resolved-packs: + - resolved-pack: ARM::RteTest_DFP@0.1.1 + selected-by: + - ARM::RteTest_DFP + - ARM::RteTest_DFP@0.1.1 diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.cproject.yml b/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.cproject.yml new file mode 100644 index 000000000..ee5e0f349 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.cproject.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cproject.schema.json + +project: + compiler: GCC + components: + - component: Startup + - component: CORE + - component: RteTest:ComponentLevel diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.csolution.yml new file mode 100644 index 000000000..1be264e16 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_added_pack.csolution.yml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + packs: + - pack: ARM::RteTest_DFP + - pack: ARM::RteTest + projects: + - project: ./pack_lock_with_added_pack.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_version_range.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_version_range.csolution.yml new file mode 100644 index 000000000..f19ac478e --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/pack_lock_with_version_range.csolution.yml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + packs: + - pack: ARM::RteTest_DFP + - pack: ARM::RteTest@>=0.0.1 + projects: + - project: ./project_with_dfp_components.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.cbuild-pack.yml new file mode 100644 index 000000000..761d10392 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.cbuild-pack.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + resolved-packs: + - resolved-pack: ARM::RteTest_DFP@0.1.1 + selected-by: + - ARM::RteTest_DFP + - ARM::RteTest_DFP@0.1.1 diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.cproject.yml b/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.cproject.yml new file mode 100644 index 000000000..2989621d0 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.cproject.yml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cproject.schema.json + +project: + compiler: GCC + packs: + - pack: ARM::RteTest_DFP + - pack: ARM::RteTest + components: + - component: Startup + - component: CORE + - component: RteTest:ComponentLevel diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.csolution.yml new file mode 100644 index 000000000..fe9b9ccf9 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_added_pack.csolution.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + projects: + - project: ./project_pack_lock_with_added_pack.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_version_range.csolution.yml b/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_version_range.csolution.yml new file mode 100644 index 000000000..f19ac478e --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/project_pack_lock_with_version_range.csolution.yml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + packs: + - pack: ARM::RteTest_DFP + - pack: ARM::RteTest@>=0.0.1 + projects: + - project: ./project_with_dfp_components.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/project_with_dfp_components.cproject.yml b/tools/projmgr/test/data/TestSolution/PackLocking/project_with_dfp_components.cproject.yml new file mode 100644 index 000000000..16422289b --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/project_with_dfp_components.cproject.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cproject.schema.json + +project: + compiler: GCC + components: + - component: Startup + - component: CORE diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/ref/pack_lock_with_version_range.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/ref/pack_lock_with_version_range.cbuild-pack.yml new file mode 100644 index 000000000..557fd30dc --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/ref/pack_lock_with_version_range.cbuild-pack.yml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + resolved-packs: + - resolved-pack: ARM::RteTest@0.1.0 + selected-by: + - ARM::RteTest@0.1.0 + - ARM::RteTest@>=0.0.1 + - resolved-pack: ARM::RteTest_DFP@0.2.0 + selected-by: + - ARM::RteTest_DFP + - ARM::RteTest_DFP@0.2.0 diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/ref/project_pack_lock_with_version_range.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/PackLocking/ref/project_pack_lock_with_version_range.cbuild-pack.yml new file mode 100644 index 000000000..557fd30dc --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/ref/project_pack_lock_with_version_range.cbuild-pack.yml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + resolved-packs: + - resolved-pack: ARM::RteTest@0.1.0 + selected-by: + - ARM::RteTest@0.1.0 + - ARM::RteTest@>=0.0.1 + - resolved-pack: ARM::RteTest_DFP@0.2.0 + selected-by: + - ARM::RteTest_DFP + - ARM::RteTest_DFP@0.2.0 diff --git a/tools/projmgr/test/data/TestSolution/PackLocking/ref/project_with_dfp_components+CM0.cprj b/tools/projmgr/test/data/TestSolution/PackLocking/ref/project_with_dfp_components+CM0.cprj new file mode 100644 index 000000000..740bf0a03 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/PackLocking/ref/project_with_dfp_components+CM0.cprj @@ -0,0 +1,31 @@ + + + + + + Automatically generated project + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/projmgr/test/data/TestSolution/ref/test.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/ref/test.cbuild-pack.yml new file mode 100644 index 000000000..7ae41392e --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/ref/test.cbuild-pack.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + resolved-packs: + - resolved-pack: ARM::RteTest_DFP@0.2.0 + selected-by: + - ARM::RteTest_DFP@0.2.0 diff --git a/tools/projmgr/test/data/TestSolution/ref/test2.Debug+TestGen_export.cprj b/tools/projmgr/test/data/TestSolution/ref/test2.Debug+TestGen_export.cprj index 528c91f8a..10ea3b479 100644 --- a/tools/projmgr/test/data/TestSolution/ref/test2.Debug+TestGen_export.cprj +++ b/tools/projmgr/test/data/TestSolution/ref/test2.Debug+TestGen_export.cprj @@ -8,7 +8,7 @@ - + diff --git a/tools/projmgr/test/data/TestSolution/ref/test_pack_selection.cbuild-pack.yml b/tools/projmgr/test/data/TestSolution/ref/test_pack_selection.cbuild-pack.yml new file mode 100644 index 000000000..604e3f9f7 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/ref/test_pack_selection.cbuild-pack.yml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/cbuild-pack.schema.json + +cbuild-pack: + resolved-packs: + - resolved-pack: ARM::RteTestGenerator@0.1.0 + selected-by: + - ARM::RteTestGenerator@0.1.0 + - resolved-pack: ARM::RteTest_DFP@0.2.0 + selected-by: + - ARM::RteTest_DFP@0.2.0 + - ARM::RteTest_DFP@>=0.2.0 diff --git a/tools/projmgr/test/src/ProjMgrTestEnv.cpp b/tools/projmgr/test/src/ProjMgrTestEnv.cpp index 383759329..a4fcd8862 100644 --- a/tools/projmgr/test/src/ProjMgrTestEnv.cpp +++ b/tools/projmgr/test/src/ProjMgrTestEnv.cpp @@ -92,6 +92,13 @@ void ProjMgrTestEnv::SetUp() { } RteFsUtils::CreateDirectories(destPackPath); fs::copy(fs::path(srcPackPath), fs::path(destPackPath), fs::copy_options::recursive, ec); + srcPackPath = testcmsispack_folder + "/ARM/RteTest/0.1.0"; + destPackPath = testinput_folder + "/SolutionSpecificPack2"; + if (RteFsUtils::Exists(destPackPath)) { + RteFsUtils::RemoveDir(destPackPath); + } + RteFsUtils::CreateDirectories(destPackPath); + fs::copy(fs::path(srcPackPath), fs::path(destPackPath), fs::copy_options::recursive, ec); // copy invalid packs string srcInvalidPacks, destInvalidPacks; diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index ba9767ea9..35c43cdd8 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -574,6 +574,10 @@ TEST_F(ProjMgrUnitTests, RunProjMgrSolution) { ProjMgrYamlSchemaChecker::FileType::BUILD)); EXPECT_TRUE(ProjMgrYamlSchemaChecker().Validate(testoutput_folder + "/test2.Debug+CM3.cbuild.yml", ProjMgrYamlSchemaChecker::FileType::BUILD)); + + // Check generated cbuild-pack file + ProjMgrTestEnv::CompareFile(testinput_folder + "/TestSolution/test.cbuild-pack.yml", + testinput_folder + "/TestSolution/ref/test.cbuild-pack.yml"); } TEST_F(ProjMgrUnitTests, RunProjMgrSolution_PositionalArguments) { @@ -696,6 +700,212 @@ TEST_F(ProjMgrUnitTests, RunProjMgrLayers) { EXPECT_TRUE(RteFsUtils::Exists(testinput_folder + "/TestLayers/Layer3/RTE/RteTest/MyDir")); } +TEST_F(ProjMgrUnitTests, RunProjMgrSolution_LockPackVersion) { + char* argv[6]; + + // convert --solution solution.yml + const string csolution = testinput_folder + "/TestSolution/PackLocking/lock_pack_version.csolution.yml"; + const string cbuildPack = testinput_folder + "/TestSolution/PackLocking/lock_pack_version.cbuild-pack.yml"; + const string cbuildPackBackup = RteFsUtils::BackupFile(cbuildPack); + const string output = testoutput_folder + "/testpacklock"; + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolution.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)output.c_str(); + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + + // Check in the generated CPRJ that RteTest_DFP::0.1.1 is still used, even if 0.2.0 is available + ProjMgrTestEnv::CompareFile(testoutput_folder + "/testpacklock/project_with_dfp_components+CM0.cprj", + testinput_folder + "/TestSolution/PackLocking/ref/project_with_dfp_components+CM0.cprj"); + + // Check that the cbuild-pack file hasn't been modified by this operation + ProjMgrTestEnv::CompareFile(cbuildPackBackup, cbuildPack); + RteFsUtils::RemoveFile(cbuildPackBackup); +} + +TEST_F(ProjMgrUnitTests, RunProjMgrSolution_CbuildPackInvalidContent) { + char* argv[6]; + StdStreamRedirect streamRedirect; + + // convert --solution solution.yml + const string csolution = testinput_folder + "/TestSolution/PackLocking/cbuild_pack_invalid_content.csolution.yml"; + const string csolution2 = testinput_folder + "/TestSolution/PackLocking/cbuild_pack_invalid_content2.csolution.yml"; + const string output = testoutput_folder + "/testpacklock"; + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolution.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)output.c_str(); + EXPECT_NE(0, RunProjMgr(6, argv, 0)); + const string expected = "error csolution: required property 'resolved-packs' not found in object"; + auto errStr = streamRedirect.GetErrorString(); + EXPECT_NE(string::npos, errStr.find(expected)); + + streamRedirect.ClearStringStreams(); + argv[3] = (char*)csolution2.c_str(); + EXPECT_NE(0, RunProjMgr(6, argv, 0)); + const string expected2 = "error csolution: operator[] call on a scalar (key: \"cbuild-pack\")"; + errStr = streamRedirect.GetErrorString(); + EXPECT_NE(string::npos, errStr.find(expected2)); +} + +TEST_F(ProjMgrUnitTests, RunProjMgrSolution_CbuildPackWithDisallowedField) { + char* argv[7]; + StdStreamRedirect streamRedirect; + + // convert --solution solution.yml + const string csolution = testinput_folder + "/TestSolution/PackLocking/cbuild_pack_with_disallowed_field.csolution.yml"; + const string csolution2 = testinput_folder + "/TestSolution/PackLocking/cbuild_pack_with_disallowed_field2.csolution.yml"; + const string output = testoutput_folder + "/testpacklock"; + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolution.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)output.c_str(); + + // Run without "--no-check-schema" + EXPECT_NE(0, RunProjMgr(6, argv, 0)); + const string expected1 = "warning csolution: key 'misc' was not recognized"; + const string expected2 = "error csolution: node 'misc' shall contain sequence elements"; + auto errStr = streamRedirect.GetErrorString(); + EXPECT_NE(string::npos, errStr.find(expected1)); + EXPECT_NE(string::npos, errStr.find(expected2)); + + // Run with "--no-check-schema" + streamRedirect.ClearStringStreams(); + argv[6] = (char*)"--no-check-schema"; + EXPECT_NE(0, RunProjMgr(7, argv, 0)); + errStr = streamRedirect.GetErrorString(); + EXPECT_NE(string::npos, errStr.find(expected1)); + EXPECT_NE(string::npos, errStr.find(expected2)); + + streamRedirect.ClearStringStreams(); + argv[3] = (char*)csolution2.c_str(); + EXPECT_NE(0, RunProjMgr(7, argv, 0)); + errStr = streamRedirect.GetErrorString(); + EXPECT_NE(string::npos, errStr.find(expected1)); + EXPECT_NE(string::npos, errStr.find(expected2)); +} + +TEST_F(ProjMgrUnitTests, RunProjMgrSolution_CbuildPackWithUnmatchedVendor) { + char* argv[6]; + + // convert --solution solution.yml + const string csolution = testinput_folder + "/TestSolution/PackLocking/cbuild_pack_with_unmatched_vendor.csolution.yml"; + const string output = testoutput_folder + "/testpacklock"; + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolution.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)output.c_str(); + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); +} + +TEST_F(ProjMgrUnitTests, RunProjMgrSolution_LockedPackVersionNotChangedByAddedPack) { + char* argv[6]; + + // convert --solution solution.yml + const string csolution = testinput_folder + "/TestSolution/PackLocking/pack_lock_with_added_pack.csolution.yml"; + const string cbuildPack = testinput_folder + "/TestSolution/PackLocking/pack_lock_with_added_pack.cbuild-pack.yml"; + const string output = testoutput_folder + "/testpacklock"; + + // Check that there is a newer version of the locked pack + vector packs; + m_worker.SetLoadPacksPolicy(LoadPacksPolicy::ALL); + EXPECT_TRUE(m_worker.ListPacks(packs, false, "ARM::RteTest_DFP@0.1.1")); + EXPECT_TRUE(m_worker.ListPacks(packs, false, "ARM::RteTest_DFP@0.2.0")); + + // Check that the cbuild-pack file contains the first pack (locked to an old version) but not the second + string buf; + EXPECT_TRUE(RteFsUtils::ReadFile(cbuildPack, buf)); + EXPECT_TRUE(buf.find("- resolved-pack: ARM::RteTest_DFP@0.1.1") != string::npos); + EXPECT_FALSE(buf.find("- resolved-pack: ARM::RteTest@") != string::npos); + + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolution.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)output.c_str(); + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + + // Check that the cbuild-pack file contains both packs and that the first still has the same version + EXPECT_TRUE(RteFsUtils::ReadFile(cbuildPack, buf)); + EXPECT_TRUE(buf.find("- resolved-pack: ARM::RteTest_DFP@0.1.1") != string::npos); + EXPECT_TRUE(buf.find("- resolved-pack: ARM::RteTest@") != string::npos); +} + +TEST_F(ProjMgrUnitTests, RunProjMgrSolution_LockedProjectPackVersionNotChangedByAddedPack) { + char* argv[6]; + + // Same as previous test but with packs listed in project + // convert --solution solution.yml + const string csolution = testinput_folder + "/TestSolution/PackLocking/project_pack_lock_with_added_pack.csolution.yml"; + const string cbuildPack = testinput_folder + "/TestSolution/PackLocking/project_pack_lock_with_added_pack.cbuild-pack.yml"; + const string output = testoutput_folder + "/testpacklock"; + + // Check that there is a newer version of the locked pack + vector packs; + m_worker.SetLoadPacksPolicy(LoadPacksPolicy::ALL); + EXPECT_TRUE(m_worker.ListPacks(packs, false, "ARM::RteTest_DFP@0.1.1")); + EXPECT_TRUE(m_worker.ListPacks(packs, false, "ARM::RteTest_DFP@0.2.0")); + + // Check that the cbuild-pack file contains the first pack (locked to an old version) but not the second + string buf; + EXPECT_TRUE(RteFsUtils::ReadFile(cbuildPack, buf)); + EXPECT_TRUE(buf.find("- resolved-pack: ARM::RteTest_DFP@0.1.1") != string::npos); + EXPECT_FALSE(buf.find("- resolved-pack: ARM::RteTest@") != string::npos); + + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolution.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)output.c_str(); + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + + // Check that the cbuild-pack file contains both packs and that the first still has the same version + EXPECT_TRUE(RteFsUtils::ReadFile(cbuildPack, buf)); + EXPECT_TRUE(buf.find("- resolved-pack: ARM::RteTest_DFP@0.1.1") != string::npos); + EXPECT_TRUE(buf.find("- resolved-pack: ARM::RteTest@") != string::npos); +} + +TEST_F(ProjMgrUnitTests, RunProjMgrSolution_LockPackWithVersionRange) { + char* argv[6]; + + // convert --solution solution.yml + const string csolution = testinput_folder + "/TestSolution/PackLocking/pack_lock_with_version_range.csolution.yml"; + const string output = testoutput_folder + "/testpacklock"; + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolution.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)output.c_str(); + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + + // Check the generated cbuild-pack file + ProjMgrTestEnv::CompareFile(testinput_folder + "/TestSolution/PackLocking/pack_lock_with_version_range.cbuild-pack.yml", + testinput_folder + "/TestSolution/PackLocking/ref/pack_lock_with_version_range.cbuild-pack.yml"); +} + +TEST_F(ProjMgrUnitTests, RunProjMgrSolution_LockProjectPackWithVersionRange) { + char* argv[6]; + + // Same as previous test but with packs listed in project + // convert --solution solution.yml + const string csolution = testinput_folder + "/TestSolution/PackLocking/project_pack_lock_with_version_range.csolution.yml"; + const string output = testoutput_folder + "/testpacklock"; + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolution.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)output.c_str(); + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + + // Check the generated cbuild-pack file + ProjMgrTestEnv::CompareFile(testinput_folder + "/TestSolution/PackLocking/project_pack_lock_with_version_range.cbuild-pack.yml", + testinput_folder + "/TestSolution/PackLocking/ref/project_pack_lock_with_version_range.cbuild-pack.yml"); +} + TEST_F(ProjMgrUnitTests, RunProjMgrLayers2) { char* argv[4]; @@ -2398,6 +2608,10 @@ TEST_F(ProjMgrUnitTests, RunProjMgrSolution_Pack_Selection) { testinput_folder + "/TestSolution/ref/test2.Debug+CM0_pack_selection.cprj"); ProjMgrTestEnv:: CompareFile(testoutput_folder + "/test2.Debug+TestGen.cprj", testinput_folder + "/TestSolution/ref/test2.Debug+TestGen.cprj"); + + // Check generated cbuild-pack file + ProjMgrTestEnv::CompareFile(testinput_folder + "/TestSolution/test_pack_selection.cbuild-pack.yml", + testinput_folder + "/TestSolution/ref/test_pack_selection.cbuild-pack.yml"); } TEST_F(ProjMgrUnitTests, RunProjMgrSolution_No_Packs) { diff --git a/tools/projmgr/test/src/ProjMgrUtilsUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUtilsUnitTests.cpp index d159c51bf..a4c55581b 100644 --- a/tools/projmgr/test/src/ProjMgrUtilsUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUtilsUnitTests.cpp @@ -428,3 +428,174 @@ TEST_F(ProjMgrUtilsUnitTests, GetFilteredContexts) { "failed for input \"" << contextFilter << "\""; } } + +TEST_F(ProjMgrUtilsUnitTests, ConvertToPackInfo) { + PackInfo packInfo; + + packInfo = {"", "", ""}; + EXPECT_TRUE(ProjMgrUtils::ConvertToPackInfo("", packInfo)); + EXPECT_EQ("", packInfo.vendor); + EXPECT_EQ("", packInfo.name); + EXPECT_EQ("", packInfo.version); + + packInfo = {"", "", ""}; + EXPECT_TRUE(ProjMgrUtils::ConvertToPackInfo("ARM", packInfo)); + EXPECT_EQ("ARM", packInfo.vendor); + EXPECT_EQ("", packInfo.name); + EXPECT_EQ("", packInfo.version); + + packInfo = {"", "", ""}; + EXPECT_TRUE(ProjMgrUtils::ConvertToPackInfo("ARM@5.8.0", packInfo)); + EXPECT_EQ("ARM", packInfo.vendor); + EXPECT_EQ("", packInfo.name); + EXPECT_EQ("5.8.0", packInfo.version); + + packInfo = {"", "", ""}; + EXPECT_TRUE(ProjMgrUtils::ConvertToPackInfo("ARM@>=5.8.0", packInfo)); + EXPECT_EQ("ARM", packInfo.vendor); + EXPECT_EQ("", packInfo.name); + EXPECT_EQ(">=5.8.0", packInfo.version); + + packInfo = {"", "", ""}; + EXPECT_TRUE(ProjMgrUtils::ConvertToPackInfo("ARM::CMSIS", packInfo)); + EXPECT_EQ("ARM", packInfo.vendor); + EXPECT_EQ("CMSIS", packInfo.name); + EXPECT_EQ("", packInfo.version); + + packInfo = {"", "", ""}; + EXPECT_TRUE(ProjMgrUtils::ConvertToPackInfo("ARM::CMSIS@5.8.0", packInfo)); + EXPECT_EQ("ARM", packInfo.vendor); + EXPECT_EQ("CMSIS", packInfo.name); + EXPECT_EQ("5.8.0", packInfo.version); + + packInfo = {"", "", ""}; + EXPECT_TRUE(ProjMgrUtils::ConvertToPackInfo("ARM::CMSIS@>=5.8.0", packInfo)); + EXPECT_EQ("ARM", packInfo.vendor); + EXPECT_EQ("CMSIS", packInfo.name); + EXPECT_EQ(">=5.8.0", packInfo.version); +} + +TEST_F(ProjMgrUtilsUnitTests, IsMatchingPackInfo) { + + // Vendor + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "ARM", ""})); + + // Wrong name + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test", "ARM", ""})); + + // Vendor + exact version + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "ARM", "5.7.0"})); + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "ARM", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "ARM", "5.9.0"})); + + // Vendor + ranges + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "ARM", ">=5.7.0"})); + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "ARM", ">=5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "ARM", ">=5.9.0"})); + + // Vendor + wildcard name + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "ARM", ""})); + + // Vendor + wildcard name + exact version + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "ARM", "5.7.0"})); + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "ARM", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "ARM", "5.9.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSI.", "ARM", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "AR.", "5.8.0"})); + + // Vendor + wildcard name + ranges + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "ARM", ">=5.7.0"})); + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "ARM", ">=5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "ARM", ">=5.9.0"})); + + // Vendor + wrong wildcard name + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "ARM", ""})); + + // Vendor + wrong wildcard name + exact version + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "ARM", "5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "ARM", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "ARM", "5.9.0"})); + + // Vendor + wrong wildcard name + ranges + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "ARM", ">=5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "ARM", ">=5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "ARM", ">=5.9.0"})); + + // Vendor + name + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "ARM", ""})); + + // Vendor + name + exact version + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "ARM", "5.7.0"})); + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "ARM", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "ARM", "5.9.0"})); + + // Vendor + name + ranges + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "ARM", ">=5.7.0"})); + EXPECT_TRUE (ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "ARM", ">=5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "ARM", ">=5.9.0"})); + + + + // Wrong vendor + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "Test", ""})); + + // Wrong vendor + wrong name + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test", "Test", ""})); + + // Wrong vendor + exact version + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "Test", "5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "Test", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "Test", "5.9.0"})); + + // Wrong vendor + ranges + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "Test", ">=5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "Test", ">=5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"", "Test", ">=5.9.0"})); + + // Wrong vendor + wildcard name + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "Test", ""})); + + // Wrong vendor + wildcard name + exact version + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "Test", "5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "Test", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "Test", "5.9.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSI.", "Test", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "Tes.", "5.8.0"})); + + // Wrong vendor + wildcard name + ranges + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "Test", ">=5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "Test", ">=5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CM*", "Test", ">=5.9.0"})); + + // Wrong vendor + wrong wildcard name + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "Test", ""})); + + // Wrong vendor + wrong wildcard name + exact version + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "Test", "5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "Test", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "Test", "5.9.0"})); + + // Wrong vendor + wrong wildcard name + ranges + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "Test", ">=5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "Test", ">=5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"Test*", "Test", ">=5.9.0"})); + + // Wrong vendor + name + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "Test", ""})); + + // Wrong vendor + name + exact version + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "Test", "5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "Test", "5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "Test", "5.9.0"})); + + // Wrong vendor + name + ranges + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "Test", ">=5.7.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "Test", ">=5.8.0"})); + EXPECT_FALSE(ProjMgrUtils::IsMatchingPackInfo({"CMSIS", "ARM", "5.8.0"}, {"CMSIS", "Test", ">=5.9.0"})); +} + +TEST_F(ProjMgrUtilsUnitTests, ConvertToVersionRange) { + EXPECT_EQ("", ProjMgrUtils::ConvertToVersionRange("")); + EXPECT_EQ("1.2.3:1.2.3", ProjMgrUtils::ConvertToVersionRange("1.2.3")); + EXPECT_EQ("1.2.3", ProjMgrUtils::ConvertToVersionRange(">=1.2.3")); +} diff --git a/tools/projmgr/test/src/ProjMgrWorkerUnitTests.cpp b/tools/projmgr/test/src/ProjMgrWorkerUnitTests.cpp index 4f7b0d697..a24fb9f51 100644 --- a/tools/projmgr/test/src/ProjMgrWorkerUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrWorkerUnitTests.cpp @@ -1559,3 +1559,31 @@ TEST_F(ProjMgrWorkerUnitTests, GetGeneratorDirDefault) { EXPECT_TRUE(GetGeneratorDir(generator, context, "", genDir)); EXPECT_EQ(genDir, "generated/RteTestGeneratorIdentifier"); }; + +TEST_F(ProjMgrWorkerUnitTests, IsPackInCbuildPack) { + ResolvedPackItem match; + + const ResolvedPackItem pack1 = {"ARM::CMSIS@5.8.0", {"ARM::CMSIS@5.8.0", "ARM::CMSIS", "ARM", "ARM::CMSIS@>=5.7.0"}}; + const ResolvedPackItem pack2 = {"Test::PackTest@1.2.3", {"Test::PackTest@1.2.3"}}; + const ResolvedPackItem pack3 = {"Test::PackTest@2.0.0", {"Test::PackTest"}}; + const vector resolvedPacks = {pack1, pack2, pack3}; + + // No name + EXPECT_FALSE(IsPackInCbuildPack({}, resolvedPacks, match)); + + // Project local pack + EXPECT_FALSE(IsPackInCbuildPack({"ARM::CMSIS", "/path/to/pack"}, resolvedPacks, match)); + + // Selected for "selected-by"-list + EXPECT_TRUE(IsPackInCbuildPack({"ARM::CMSIS"}, resolvedPacks, match)); + EXPECT_EQ(match.pack, pack1.pack); + EXPECT_EQ(match.selectedBy, pack1.selectedBy); + + // Fuzzy matching + EXPECT_TRUE(IsPackInCbuildPack({"Test@>=1.0.0"}, resolvedPacks, match)); + EXPECT_EQ(match.pack, pack2.pack); + EXPECT_EQ(match.selectedBy, pack2.selectedBy); + + // Does not match anything in "selected-by"-list + EXPECT_FALSE(IsPackInCbuildPack({"Test@>=3.0.0"}, resolvedPacks, match)); +}