From 4425a1a78f28cd68c853b0f8b9cc383be27e7741 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Mon, 27 Apr 2026 11:16:43 +0200 Subject: [PATCH 01/14] Add `check` command for potential pack updates --- libs/rtemodel/include/RteKernel.h | 22 ++-- libs/rtemodel/src/RteKernel.cpp | 41 ++++++- test/packs/.Local/ARM.RteTestBoard.pdsc | 57 ++++++++++ test/packs/.Local/local_repository.pidx | 2 + .../RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc | 51 +++++++++ .../0.0.1/Board/Flash/BoardAlgo1.FLM | 1 + .../0.0.1/Board/Flash/BoardAlgo2.FLM | 1 + .../RteTestBoard/0.0.1/Documents/README.md | 1 + .../RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc | 6 + tools/projmgr/include/ProjMgr.h | 1 + tools/projmgr/include/ProjMgrWorker.h | 17 +++ tools/projmgr/src/ProjMgr.cpp | 29 +++++ tools/projmgr/src/ProjMgrWorker.cpp | 103 ++++++++++++++++++ .../checkPackVerCmd.cproject.yml | 4 + .../checkPackVerCmd.csolution.yml | 17 +++ tools/projmgr/test/src/ProjMgrUnitTests.cpp | 37 +++++++ 16 files changed, 381 insertions(+), 9 deletions(-) create mode 100644 test/packs/.Local/ARM.RteTestBoard.pdsc create mode 100644 test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc create mode 100644 test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo1.FLM create mode 100644 test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo2.FLM create mode 100644 test/packs/ARM/RteTestBoard/0.0.1/Documents/README.md create mode 100644 tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.cproject.yml create mode 100644 tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml diff --git a/libs/rtemodel/include/RteKernel.h b/libs/rtemodel/include/RteKernel.h index 0f6a4e375..b35241513 100644 --- a/libs/rtemodel/include/RteKernel.h +++ b/libs/rtemodel/include/RteKernel.h @@ -320,6 +320,13 @@ class RteKernel */ void SetToolInfo(const XmlItem& attr) { m_toolInfo = attr; } + /** + * @brief reads latest pack versions from repository indices + * @param map of pack IDs to latest available versions to fill + * @return true if at least one repository index was parsed successfully, false otherwise + */ + bool ReadPackLatestVersions(std::map& latestPacks) const; + protected: /** * @brief get local pdsc files, optionally filtered @@ -330,9 +337,14 @@ class RteKernel bool GetLocalPdscFiles(const XmlItem& attr, std::map& pdscMap) const; /** * @brief parses $CMSIS_PACK_ROOT/.Local/loacl_repository.pidx file - * @return pointer to "index" element if successful, nullptr otherwise + * @return pointer to "pindex" element if successful, nullptr otherwise */ XMLTreeElement* ParseLocalRepositoryIdx() const; + /** + * @brief parses $CMSIS_PACK_ROOT/.Web/index.pidx file + * @return pointer to "pindex" element if successful, nullptr otherwise + */ + XMLTreeElement* ParseWebRepositoryIdx() const; /** * @brief create an XMLTree object to parse XML files @@ -348,12 +360,8 @@ class RteKernel */ virtual YmlTree* CreateYmlTree(IXmlItemBuilder* itemBuilder) const; - /** - * @brief get this pointer to use in const methods - * @return this - */ RteKernel* GetThisKernel() const { return const_cast(this); } - + XMLTreeElement* ParseRepositoryIdx(const std::string& indexPath) const; // data protected: @@ -366,6 +374,6 @@ class RteKernel std::string m_cmsisToolboxDir; std::map m_externalGeneratorFiles; std::map m_externalGenerators; - + }; #endif // RteKernel_H diff --git a/libs/rtemodel/src/RteKernel.cpp b/libs/rtemodel/src/RteKernel.cpp index 03bfcfa0f..36f5ba092 100644 --- a/libs/rtemodel/src/RteKernel.cpp +++ b/libs/rtemodel/src/RteKernel.cpp @@ -610,9 +610,17 @@ bool RteKernel::GetLocalPdscFiles(const XmlItem& attr, std::map& latestPacks) const { + auto mergePackVersions = [&latestPacks](XMLTreeElement* index) { + if (!index) { + return; + } + for (auto& child : index->GetChildren()) { + if (!child || child->GetTag() != "pdsc") { + continue; + } + const string& vendor = child->GetAttribute("vendor"); + const string& name = child->GetAttribute("name"); + const string& version = child->GetAttribute("version"); + // ignore incomplete pack entries + if (vendor.empty() || name.empty() || version.empty()) { + continue; + } + const string packId = vendor + "::" + name; + auto it = latestPacks.find(packId); + if (it == latestPacks.end() || VersionCmp::Compare(it->second, version) < 0) { + latestPacks[packId] = version; + } + } + }; + unique_ptr webPIndexChild(ParseWebRepositoryIdx()); + mergePackVersions(webPIndexChild.get()); + unique_ptr localPIndexChild(ParseLocalRepositoryIdx()); + mergePackVersions(localPIndexChild.get()); + return !latestPacks.empty(); +} unique_ptr RteKernel::CreateUniqueXmlTree(IXmlItemBuilder* itemBuilder, const std::string& ext) const { diff --git a/test/packs/.Local/ARM.RteTestBoard.pdsc b/test/packs/.Local/ARM.RteTestBoard.pdsc new file mode 100644 index 000000000..28fc5a2db --- /dev/null +++ b/test/packs/.Local/ARM.RteTestBoard.pdsc @@ -0,0 +1,57 @@ + + + + RteTestBoard + Testing packages listing + ARM + + + + Initial version + + + Pre-initial version 0.0.2 for testing CheckPackVersionCmd + + + Pre-initial version 0.0.1 for testing CheckPackVersionCmd + + + + + + + + + + + + uVision Simulator + + + + + + + + + + + No device board + + + + + + uVision Simulator + + + + + + + + + + + + diff --git a/test/packs/.Local/local_repository.pidx b/test/packs/.Local/local_repository.pidx index ed8f10697..391545c71 100644 --- a/test/packs/.Local/local_repository.pidx +++ b/test/packs/.Local/local_repository.pidx @@ -12,6 +12,8 @@ + + diff --git a/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc new file mode 100644 index 000000000..2efc90d66 --- /dev/null +++ b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc @@ -0,0 +1,51 @@ + + + + RteTestBoard + Testing packages listing + ARM + + + + Pre-initial version 0.0.1 forS tesing CheckPackVersionCmd + + + + + + + + + + + + uVision Simulator + + + + + + + + + + + No device board + + + + + + uVision Simulator + + + + + + + + + + + + diff --git a/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo1.FLM b/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo1.FLM new file mode 100644 index 000000000..6fca4f90e --- /dev/null +++ b/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo1.FLM @@ -0,0 +1 @@ +CortexM4Device.FLM : not real flash algorithm \ No newline at end of file diff --git a/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo2.FLM b/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo2.FLM new file mode 100644 index 000000000..0f2e24ff2 --- /dev/null +++ b/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo2.FLM @@ -0,0 +1 @@ +CortexM4SubFamily.FLM : not real flash algorithm \ No newline at end of file diff --git a/test/packs/ARM/RteTestBoard/0.0.1/Documents/README.md b/test/packs/ARM/RteTestBoard/0.0.1/Documents/README.md new file mode 100644 index 000000000..783244691 --- /dev/null +++ b/test/packs/ARM/RteTestBoard/0.0.1/Documents/README.md @@ -0,0 +1 @@ +# Board documentation diff --git a/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc b/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc index 29c585c11..bbcde23fc 100644 --- a/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc +++ b/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc @@ -9,6 +9,12 @@ Initial version + + Pre-initial version 0.0.2 for tesing CheckPackVersionCmd + + + Pre-initial version 0.0.1 for tesing CheckPackVersionCmd + diff --git a/tools/projmgr/include/ProjMgr.h b/tools/projmgr/include/ProjMgr.h index c86485cc8..439d690b4 100644 --- a/tools/projmgr/include/ProjMgr.h +++ b/tools/projmgr/include/ProjMgr.h @@ -222,6 +222,7 @@ class ProjMgr { std::vector m_allContexts; std::set m_failedContext; + bool RunCheckPackVerCmd(); bool RunConfigure(); bool RunCodeGenerator(); bool RunListPacks(); diff --git a/tools/projmgr/include/ProjMgrWorker.h b/tools/projmgr/include/ProjMgrWorker.h index da5987500..6b84c2871 100644 --- a/tools/projmgr/include/ProjMgrWorker.h +++ b/tools/projmgr/include/ProjMgrWorker.h @@ -1033,6 +1033,23 @@ class ProjMgrWorker { */ bool CheckMissingFiles(); + /** + * @brief check selected packs against latest versions + * @param vector of output lines describing pack update status + * @param optional filter + * @return true if check completed successfully + */ + bool CheckPackVerAndCollectRelNotes(std::vector& results, const std::string& filter = RteUtils::EMPTY_STRING); + + /** + * @brief reads release notes between current and latest pack versions + * @param current pack information + * @param latest pack version + * @param output release notes + * @return true if release notes were found, false otherwise + */ + bool ReadPackReleaseNotes(const PackInfo& currentPack, const std::string& latestVersion, std::vector& releaseNotes); + /** * @brief collect unused packs for each selected context */ diff --git a/tools/projmgr/src/ProjMgr.cpp b/tools/projmgr/src/ProjMgr.cpp index 1ca551578..5e0d81c03 100644 --- a/tools/projmgr/src/ProjMgr.cpp +++ b/tools/projmgr/src/ProjMgr.cpp @@ -22,6 +22,7 @@ static constexpr const char* USAGE = "\n\ Usage:\n\ csolution [.csolution.yml] [options]\n\n\ Commands:\n\ + check Check existing project for potential pack updates\n\ convert Convert user input *.yml files to *.cbuild.yml files\n\ list boards Print list of available board names\n\ list configs Print list of configuration files\n\ @@ -179,6 +180,7 @@ int ProjMgr::ParseCommandLine(int argc, char** argv) { {"update-rte", { false, {context, contextSet, activeTargetSet, debug, load, quiet, schemaCheck, toolchain, verbose, frozenPacks}}}, {"convert", { false, {context, contextSet, activeTargetSet, debug, exportSuffix, load, quiet, schemaCheck, noUpdateRte, output, outputAlt, toolchain, verbose, frozenPacks, cbuildgen}}}, {"run", { false, {context, contextSet, activeTargetSet, debug, generator, load, quiet, schemaCheck, verbose, dryRun}}}, + {"check", { false, {context, contextSet, activeTargetSet, debug, load, quiet, schemaCheck, verbose}}}, {"list packs", { true, {context, contextSet, activeTargetSet, debug, filter, load, missing, locked, quiet, schemaCheck, toolchain, verbose}}}, {"list boards", { true, {context, contextSet, activeTargetSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, {"list devices", { true, {context, contextSet, activeTargetSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}}, @@ -397,6 +399,10 @@ int ProjMgr::ProcessCommands() { if (!m_rpcServer.Run()) { return ErrorCode::ERROR; } + } else if (m_command == "check") { + if (!RunCheckPackVerCmd()) { + return ErrorCode::ERROR; + } } else { ProjMgrLogger::Get().Error(" was not found"); return ErrorCode::ERROR; @@ -1034,6 +1040,29 @@ bool ProjMgr::RunCodeGenerator(void) { return true; } +bool ProjMgr::RunCheckPackVerCmd(void) { + if (m_csolutionFile.empty()) { + ProjMgrLogger::Get().Error("input csolution.yml was not specified"); + return false; + } + // Check input options + if (!PopulateContexts()) { + return false; + } + // Parse all input files and create contexts + if (!ParseAndValidateContexts()) { + return false; + } + + vector outputs; + const bool result = m_worker.CheckPackVerAndCollectRelNotes(outputs, m_filter); + + for (const auto& line : outputs) { + ProjMgrLogger::out() << line << std::endl; + } + return result; +} + bool ProjMgr::RunListToolchains(void) { if (!m_csolutionFile.empty()) { // Parse all input files and create contexts diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index 6f7a951e5..139e81970 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -6023,6 +6023,109 @@ void ProjMgrWorker::CheckMissingLinkerScript(ContextItem& context) { } } +bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(vector& results, const string& filter) { + map usedPacks; // string (Vendor::Name) -> PackInfo (name, vendor, version) + map latestPacks; // string (Vendor::Name) -> string (latest pack version) + vector selectedContexts = m_selectedContexts; + if (selectedContexts.empty()) { + for (const auto& [contextName, _] : m_contexts) { + selectedContexts.push_back(contextName); + } + } + for (const auto& contextName : selectedContexts) { + ContextItem& context = m_contexts.at(contextName); + if (!LoadPacks(context)) { + return false; + } + for (const auto& pack : m_loadedPacks) { + const string packId = pack->GetVendorString() + "::" + pack->GetName(); + const string& currentVersion = pack->GetVersionString(); + usedPacks[packId] = { pack->GetName(), pack->GetVendorString(), currentVersion }; + } + } + + if (!m_kernel->ReadPackLatestVersions(latestPacks)) { + ProjMgrLogger::Get().Error("failed to read latest pack versions from pack index"); + return false; + } + + vector checkPackResults; + for (const auto& [packId, currentPack] : usedPacks) { + auto latestPack = latestPacks.find(packId); + if (latestPack == latestPacks.end()) { + checkPackResults.push_back(packId + "@" + currentPack.version + " (not found in pack index)"); + continue; + } + const string& latestVersion = latestPack->second; + const int cmp = VersionCmp::Compare(currentPack.version, latestVersion); + if (cmp < 0) { + string outStr = packId + "@" + currentPack.version + " -> " + latestVersion; + if (m_verbose) { + vector releaseNotes; + if (ReadPackReleaseNotes(currentPack, latestVersion, releaseNotes)) { + for (const auto& note : releaseNotes) { + outStr += note; + } + } else { + outStr += "\n Release notes: unavailable (latest PDSC not found in .Web/.Local)"; + } + } + checkPackResults.push_back(outStr); + } else { + checkPackResults.push_back(packId + "@" + currentPack.version + " (up-to-date)"); + } + } + if (checkPackResults.empty()) { + ProjMgrLogger::Get().Error("no packs were found for version check"); + return false; + } + if (!filter.empty()) { + std::vector matchedPacks; + RteUtils::ApplyFilter(checkPackResults, RteUtils::SplitStringToSet(filter), matchedPacks); + if (matchedPacks.empty()) { + ProjMgrLogger::Get().Error("no packs were found for version check with filter '" + filter + "'"); + return false; + } + checkPackResults = matchedPacks; + } + results.assign(checkPackResults.begin(), checkPackResults.end()); + return true; +} + +bool ProjMgrWorker::ReadPackReleaseNotes(const PackInfo& currentPack, const string& latestVersion, vector& releaseNotes) { + string pdscFile = m_kernel->GetCmsisPackRoot() + "/.Web/" + currentPack.vendor + "." + currentPack.name + ".pdsc"; + if (!RteFsUtils::Exists(pdscFile)) { + // fall back to .Local if the PDSC is not present in .Web + pdscFile = m_kernel->GetCmsisPackRoot() + "/.Local/" + currentPack.vendor + "." + currentPack.name + ".pdsc"; + } + if (!RteFsUtils::Exists(pdscFile)) { return false; } + + RtePackage* pack(m_kernel->LoadPack(pdscFile)); + if (!pack) { return false; } + + RteItem* releases = pack->GetFirstChild("releases"); + if (!releases) { return false; } + + for (auto& child : releases->GetChildren()) { + if (!child || child->GetTag() != "release") { + continue; + } + const string& releaseVersion = child->GetAttribute("version"); + const string& text = child->GetText(); + if (releaseVersion.empty() || text.empty()) { + continue; + } + if (VersionCmp::Compare(releaseVersion, latestVersion) > 0) { + continue; + } + if (VersionCmp::Compare(releaseVersion, currentPack.version) <= 0) { + break; + } + releaseNotes.push_back("\n Release notes for v" + releaseVersion + ":\n " + text); + } + return !releaseNotes.empty(); +} + void ProjMgrWorker::CollectUnusedPacks() { for (const auto& contextName : m_selectedContexts) { auto& context = m_contexts[contextName]; diff --git a/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.cproject.yml b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.cproject.yml new file mode 100644 index 000000000..bf0ddcae8 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.cproject.yml @@ -0,0 +1,4 @@ +project: + components: + - component: Startup + - component: RteTest:CORE diff --git a/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml new file mode 100644 index 000000000..07023c789 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml @@ -0,0 +1,17 @@ +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + + build-types: + - type: Debug + compiler: AC6 + + packs: + - pack: ARM::RteTest + - pack: ARM::RteTest_DFP@0.1.1 + - pack: ARM::RteTestBoard@0.0.1 + - pack: LocalVendor::LocalPack + + projects: + - project: ./checkPackVerCmd.cproject.yml diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index 370e40cda..d4de3de8a 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -657,6 +657,43 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_ListDependencies) { EXPECT_NE(errStr.find(expectedErr), string::npos); } +TEST_F(ProjMgrUnitTests, RunProjMgr_CheckPackVerCmd) { + char* argv[4]; + StdStreamRedirect streamRedirect; + string csolutionFile = testinput_folder + "/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml"; + // no csolution file provided + argv[1] = (char*)"check"; + EXPECT_EQ(1, RunProjMgr(3, argv, 0)); + auto errStr = streamRedirect.GetErrorString(); + EXPECT_STREQ(errStr.c_str(), "error csolution: input csolution.yml was not specified\n"); + + // standard check output + argv[2] = (char*)csolutionFile.c_str(); + EXPECT_EQ(0, RunProjMgr(3, argv, 0)); + auto outStr = streamRedirect.GetOutString(); + EXPECT_STREQ(outStr.c_str(), "\ +ARM::RteTest@0.1.0 (not found in pack index)\n\ +ARM::RteTestBoard@0.0.1 -> 0.1.0\n\ +ARM::RteTest_DFP@0.1.1+metadata -> 0.2.0\n\ +LocalVendor::LocalPack@1.0.1 (up-to-date)\n"); + + // check verbose output + streamRedirect.ClearStringStreams(); + argv[3] = (char*)"--verbose"; + EXPECT_EQ(0, RunProjMgr(4, argv, 0)); + outStr = streamRedirect.GetOutString(); + EXPECT_STREQ(outStr.c_str(), "\ +ARM::RteTest@0.1.0 (not found in pack index)\n\ +ARM::RteTestBoard@0.0.1 -> 0.1.0\n\ + Release notes for v0.1.0:\n\ + Initial version\n\ + Release notes for v0.0.2:\n\ + Pre-initial version 0.0.2 for testing CheckPackVersionCmd\n\ +ARM::RteTest_DFP@0.1.1+metadata -> 0.2.0\n\ + Release notes: unavailable (latest PDSC not found in .Web/.Local)\n\ +LocalVendor::LocalPack@1.0.1 (up-to-date)\n"); +} + TEST_F(ProjMgrUnitTests, RunProjMgr_ConvertProject_1) { char* argv[7]; string csolutionFile = UpdateTestSolutionFile("./TestProject4/test.cproject.yml"); From 3ba82ac9f80627fb60c4e74bd3113d05e7d4a256 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Mon, 27 Apr 2026 13:38:56 +0200 Subject: [PATCH 02/14] Small fix --- test/packs/.Local/ARM.RteTestBoard.pdsc | 8 ++++---- test/packs/.Local/local_repository.pidx | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/packs/.Local/ARM.RteTestBoard.pdsc b/test/packs/.Local/ARM.RteTestBoard.pdsc index 28fc5a2db..afc675061 100644 --- a/test/packs/.Local/ARM.RteTestBoard.pdsc +++ b/test/packs/.Local/ARM.RteTestBoard.pdsc @@ -10,11 +10,11 @@ Initial version - Pre-initial version 0.0.2 for testing CheckPackVersionCmd - + Pre-initial version 0.0.2 for testing CheckPackVersionCmd + - Pre-initial version 0.0.1 for testing CheckPackVersionCmd - + Pre-initial version 0.0.1 for testing CheckPackVersionCmd + diff --git a/test/packs/.Local/local_repository.pidx b/test/packs/.Local/local_repository.pidx index 391545c71..b2a3d3182 100644 --- a/test/packs/.Local/local_repository.pidx +++ b/test/packs/.Local/local_repository.pidx @@ -12,6 +12,7 @@ + From 410d3cb8fc8a8b0fffc806f60f2276aae4b0d336 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Mon, 27 Apr 2026 14:41:01 +0200 Subject: [PATCH 03/14] Refine workflow --- libs/rtemodel/include/RteKernel.h | 7 -- libs/rtemodel/src/RteKernel.cpp | 41 +--------- test/packs/.Local/ARM.RteTestBoard.pdsc | 57 -------------- test/packs/.Local/local_repository.pidx | 3 - .../RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc | 2 +- .../RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc | 4 +- tools/projmgr/include/ProjMgrWorker.h | 15 ++-- tools/projmgr/src/ProjMgrWorker.cpp | 78 ++++++++++++------- .../checkPackVerCmd.csolution.yml | 1 - tools/projmgr/test/src/ProjMgrUnitTests.cpp | 13 ++-- 10 files changed, 71 insertions(+), 150 deletions(-) delete mode 100644 test/packs/.Local/ARM.RteTestBoard.pdsc diff --git a/libs/rtemodel/include/RteKernel.h b/libs/rtemodel/include/RteKernel.h index b35241513..2cc5c73ef 100644 --- a/libs/rtemodel/include/RteKernel.h +++ b/libs/rtemodel/include/RteKernel.h @@ -320,13 +320,6 @@ class RteKernel */ void SetToolInfo(const XmlItem& attr) { m_toolInfo = attr; } - /** - * @brief reads latest pack versions from repository indices - * @param map of pack IDs to latest available versions to fill - * @return true if at least one repository index was parsed successfully, false otherwise - */ - bool ReadPackLatestVersions(std::map& latestPacks) const; - protected: /** * @brief get local pdsc files, optionally filtered diff --git a/libs/rtemodel/src/RteKernel.cpp b/libs/rtemodel/src/RteKernel.cpp index 36f5ba092..03bfcfa0f 100644 --- a/libs/rtemodel/src/RteKernel.cpp +++ b/libs/rtemodel/src/RteKernel.cpp @@ -609,18 +609,10 @@ bool RteKernel::GetLocalPdscFiles(const XmlItem& attr, std::map& latestPacks) const { - auto mergePackVersions = [&latestPacks](XMLTreeElement* index) { - if (!index) { - return; - } - for (auto& child : index->GetChildren()) { - if (!child || child->GetTag() != "pdsc") { - continue; - } - const string& vendor = child->GetAttribute("vendor"); - const string& name = child->GetAttribute("name"); - const string& version = child->GetAttribute("version"); - // ignore incomplete pack entries - if (vendor.empty() || name.empty() || version.empty()) { - continue; - } - const string packId = vendor + "::" + name; - auto it = latestPacks.find(packId); - if (it == latestPacks.end() || VersionCmp::Compare(it->second, version) < 0) { - latestPacks[packId] = version; - } - } - }; - unique_ptr webPIndexChild(ParseWebRepositoryIdx()); - mergePackVersions(webPIndexChild.get()); - unique_ptr localPIndexChild(ParseLocalRepositoryIdx()); - mergePackVersions(localPIndexChild.get()); - return !latestPacks.empty(); -} unique_ptr RteKernel::CreateUniqueXmlTree(IXmlItemBuilder* itemBuilder, const std::string& ext) const { diff --git a/test/packs/.Local/ARM.RteTestBoard.pdsc b/test/packs/.Local/ARM.RteTestBoard.pdsc deleted file mode 100644 index afc675061..000000000 --- a/test/packs/.Local/ARM.RteTestBoard.pdsc +++ /dev/null @@ -1,57 +0,0 @@ - - - - RteTestBoard - Testing packages listing - ARM - - - - Initial version - - - Pre-initial version 0.0.2 for testing CheckPackVersionCmd - - - Pre-initial version 0.0.1 for testing CheckPackVersionCmd - - - - - - - - - - - - uVision Simulator - - - - - - - - - - - No device board - - - - - - uVision Simulator - - - - - - - - - - - - diff --git a/test/packs/.Local/local_repository.pidx b/test/packs/.Local/local_repository.pidx index b2a3d3182..ed8f10697 100644 --- a/test/packs/.Local/local_repository.pidx +++ b/test/packs/.Local/local_repository.pidx @@ -12,9 +12,6 @@ - - - diff --git a/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc index 2efc90d66..98c4c374b 100644 --- a/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc +++ b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc @@ -7,7 +7,7 @@ - Pre-initial version 0.0.1 forS tesing CheckPackVersionCmd + Pre-initial version 0.0.1 forS testing CheckPackVersionCmd diff --git a/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc b/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc index bbcde23fc..24e71ffba 100644 --- a/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc +++ b/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc @@ -10,10 +10,10 @@ Initial version - Pre-initial version 0.0.2 for tesing CheckPackVersionCmd + Pre-initial version 0.0.2 for testing CheckPackVerCmd - Pre-initial version 0.0.1 for tesing CheckPackVersionCmd + Pre-initial version 0.0.1 for testing CheckPackVerCmd diff --git a/tools/projmgr/include/ProjMgrWorker.h b/tools/projmgr/include/ProjMgrWorker.h index 6b84c2871..358693631 100644 --- a/tools/projmgr/include/ProjMgrWorker.h +++ b/tools/projmgr/include/ProjMgrWorker.h @@ -1042,13 +1042,14 @@ class ProjMgrWorker { bool CheckPackVerAndCollectRelNotes(std::vector& results, const std::string& filter = RteUtils::EMPTY_STRING); /** - * @brief reads release notes between current and latest pack versions - * @param current pack information - * @param latest pack version - * @param output release notes - * @return true if release notes were found, false otherwise - */ - bool ReadPackReleaseNotes(const PackInfo& currentPack, const std::string& latestVersion, std::vector& releaseNotes); + * @brief read release notes for versions newer than the current version and up to the latest version + * @param resolved path to the PDSC file of the latest effective pack + * @param version currently used by the project + * @param latest available version resolved for the pack + * @param output list of collected release note strings for versions + * @return true if at least one matching release note was found, otherwise false + */ + bool ReadPackReleaseNotes(const std::string& pdscFile, const std::string& currentVersion, const std::string& latestVersion, std::vector& releaseNotes); /** * @brief collect unused packs for each selected context diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index 139e81970..ae7ea1e05 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -6023,9 +6023,13 @@ void ProjMgrWorker::CheckMissingLinkerScript(ContextItem& context) { } } -bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(vector& results, const string& filter) { - map usedPacks; // string (Vendor::Name) -> PackInfo (name, vendor, version) - map latestPacks; // string (Vendor::Name) -> string (latest pack version) +bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& results, const std::string& filter) { + struct LatestPackInfo { + string version; + string pdscFile; + }; + map usedPacks; + map latestPacks; vector selectedContexts = m_selectedContexts; if (selectedContexts.empty()) { for (const auto& [contextName, _] : m_contexts) { @@ -6043,31 +6047,56 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(vector& results, cons usedPacks[packId] = { pack->GetName(), pack->GetVendorString(), currentVersion }; } } + map effectivePdscMap; + if (!m_kernel->GetEffectivePdscFilesAsMap(effectivePdscMap, true)) { + ProjMgrLogger::Get().Error("failed to get effective PDSC files"); + return false; + } + if (effectivePdscMap.empty()) { + ProjMgrLogger::Get().Error("no effective PDSC files found"); + return false; + } + for (const auto& [_, pdscFile] : effectivePdscMap) { + RtePackage* pack = m_kernel->LoadPack(pdscFile); + if (!pack) { + continue; + } + const string& vendor = pack->GetVendorString(); + const string& name = pack->GetName(); + const string& version = pack->GetVersionString(); + // Ignore incomplete pack entries + if (vendor.empty() || name.empty() || version.empty()) { + continue; + } + const string packId = vendor + "::" + name; + latestPacks[packId] = { version, pdscFile }; + } - if (!m_kernel->ReadPackLatestVersions(latestPacks)) { - ProjMgrLogger::Get().Error("failed to read latest pack versions from pack index"); + if (latestPacks.empty()) { + ProjMgrLogger::Get().Error("failed to resolve latest pack information from effective PDSC files"); return false; } vector checkPackResults; for (const auto& [packId, currentPack] : usedPacks) { - auto latestPack = latestPacks.find(packId); - if (latestPack == latestPacks.end()) { - checkPackResults.push_back(packId + "@" + currentPack.version + " (not found in pack index)"); + auto latestPackIt = latestPacks.find(packId); + if (latestPackIt == latestPacks.end()) { + checkPackResults.push_back(packId + "@" + currentPack.version + " (not found in CMSIS pack root)"); continue; } - const string& latestVersion = latestPack->second; + const LatestPackInfo& latestPack = latestPackIt->second; + const string& latestVersion = latestPack.version; const int cmp = VersionCmp::Compare(currentPack.version, latestVersion); if (cmp < 0) { string outStr = packId + "@" + currentPack.version + " -> " + latestVersion; if (m_verbose) { vector releaseNotes; - if (ReadPackReleaseNotes(currentPack, latestVersion, releaseNotes)) { + if (ReadPackReleaseNotes(latestPack.pdscFile, currentPack.version, latestVersion, releaseNotes)) { for (const auto& note : releaseNotes) { outStr += note; } } else { - outStr += "\n Release notes: unavailable (latest PDSC not found in .Web/.Local)"; + outStr += "\n Release notes: unavailable"; } } checkPackResults.push_back(outStr); @@ -6092,33 +6121,30 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(vector& results, cons return true; } -bool ProjMgrWorker::ReadPackReleaseNotes(const PackInfo& currentPack, const string& latestVersion, vector& releaseNotes) { - string pdscFile = m_kernel->GetCmsisPackRoot() + "/.Web/" + currentPack.vendor + "." + currentPack.name + ".pdsc"; - if (!RteFsUtils::Exists(pdscFile)) { - // fall back to .Local if the PDSC is not present in .Web - pdscFile = m_kernel->GetCmsisPackRoot() + "/.Local/" + currentPack.vendor + "." + currentPack.name + ".pdsc"; +bool ProjMgrWorker::ReadPackReleaseNotes(const string& pdscFile, const string& currentVersion, const string& latestVersion, vector& releaseNotes) { + RtePackage* pack = m_kernel->LoadPack(pdscFile); + if (!pack) { + return false; } - if (!RteFsUtils::Exists(pdscFile)) { return false; } - - RtePackage* pack(m_kernel->LoadPack(pdscFile)); - if (!pack) { return false; } - RteItem* releases = pack->GetFirstChild("releases"); - if (!releases) { return false; } - + if (!releases) { + return false; + } for (auto& child : releases->GetChildren()) { if (!child || child->GetTag() != "release") { continue; } - const string& releaseVersion = child->GetAttribute("version"); - const string& text = child->GetText(); + const std::string& releaseVersion = child->GetAttribute("version"); + const std::string& text = child->GetText(); if (releaseVersion.empty() || text.empty()) { continue; } + // skip versions newer than the resolved latest version if (VersionCmp::Compare(releaseVersion, latestVersion) > 0) { continue; } - if (VersionCmp::Compare(releaseVersion, currentPack.version) <= 0) { + // stop when reaching current version or older + if (VersionCmp::Compare(releaseVersion, currentVersion) <= 0) { break; } releaseNotes.push_back("\n Release notes for v" + releaseVersion + ":\n " + text); diff --git a/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml index 07023c789..8aa9ad0c7 100644 --- a/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml +++ b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml @@ -11,7 +11,6 @@ solution: - pack: ARM::RteTest - pack: ARM::RteTest_DFP@0.1.1 - pack: ARM::RteTestBoard@0.0.1 - - pack: LocalVendor::LocalPack projects: - project: ./checkPackVerCmd.cproject.yml diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index d4de3de8a..ec69e11d0 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -672,10 +672,9 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_CheckPackVerCmd) { EXPECT_EQ(0, RunProjMgr(3, argv, 0)); auto outStr = streamRedirect.GetOutString(); EXPECT_STREQ(outStr.c_str(), "\ -ARM::RteTest@0.1.0 (not found in pack index)\n\ +ARM::RteTest@0.1.0 (up-to-date)\n\ ARM::RteTestBoard@0.0.1 -> 0.1.0\n\ -ARM::RteTest_DFP@0.1.1+metadata -> 0.2.0\n\ -LocalVendor::LocalPack@1.0.1 (up-to-date)\n"); +ARM::RteTest_DFP@0.1.1+metadata -> 0.2.0\n"); // check verbose output streamRedirect.ClearStringStreams(); @@ -683,15 +682,15 @@ LocalVendor::LocalPack@1.0.1 (up-to-date)\n"); EXPECT_EQ(0, RunProjMgr(4, argv, 0)); outStr = streamRedirect.GetOutString(); EXPECT_STREQ(outStr.c_str(), "\ -ARM::RteTest@0.1.0 (not found in pack index)\n\ +ARM::RteTest@0.1.0 (up-to-date)\n\ ARM::RteTestBoard@0.0.1 -> 0.1.0\n\ Release notes for v0.1.0:\n\ Initial version\n\ Release notes for v0.0.2:\n\ - Pre-initial version 0.0.2 for testing CheckPackVersionCmd\n\ + Pre-initial version 0.0.2 for testing CheckPackVerCmd\n\ ARM::RteTest_DFP@0.1.1+metadata -> 0.2.0\n\ - Release notes: unavailable (latest PDSC not found in .Web/.Local)\n\ -LocalVendor::LocalPack@1.0.1 (up-to-date)\n"); + Release notes for v0.2.0:\n\ + Added a new device 'RteTest_ARMCM0_Dual'\n"); } TEST_F(ProjMgrUnitTests, RunProjMgr_ConvertProject_1) { From 2503fbaaae2d7bcc0ccde9ee4b837b276e666825 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Mon, 27 Apr 2026 15:50:04 +0200 Subject: [PATCH 04/14] Refine workflow --- libs/rtemodel/include/RteKernel.h | 7 ++ libs/rtemodel/src/RteKernel.cpp | 55 +++++++++++++++- .../RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc | 4 +- tools/projmgr/src/ProjMgrWorker.cpp | 65 +++++-------------- 4 files changed, 80 insertions(+), 51 deletions(-) diff --git a/libs/rtemodel/include/RteKernel.h b/libs/rtemodel/include/RteKernel.h index 2cc5c73ef..758e865bb 100644 --- a/libs/rtemodel/include/RteKernel.h +++ b/libs/rtemodel/include/RteKernel.h @@ -320,6 +320,13 @@ class RteKernel */ void SetToolInfo(const XmlItem& attr) { m_toolInfo = attr; } + /** + * @brief read the latest available pack version and resolved PDSC file for each pack. + * @param Output map of pack ID to latest version and resolved PDSC file path + * @return true if at least one latest pack entry was found, otherwise false + */ + bool ReadPackLatestVerAndPath(std::map>& latestPacks) const; + protected: /** * @brief get local pdsc files, optionally filtered diff --git a/libs/rtemodel/src/RteKernel.cpp b/libs/rtemodel/src/RteKernel.cpp index 03bfcfa0f..24e0509d4 100644 --- a/libs/rtemodel/src/RteKernel.cpp +++ b/libs/rtemodel/src/RteKernel.cpp @@ -610,9 +610,17 @@ bool RteKernel::GetLocalPdscFiles(const XmlItem& attr, std::map>& latestPacks) const { + // read latest public pack versions from /.Web/index.pidx and the corresponding latest Web PDSC file paths + unique_ptr webPIndexChild(ParseWebRepositoryIdx()); + if (webPIndexChild) { + for (auto& child : webPIndexChild->GetChildren()) { + if (!child || child->GetTag() != "pdsc") { + continue; + } + const string& vendor = child->GetAttribute("vendor"); + const string& name = child->GetAttribute("name"); + const string& version = child->GetAttribute("version"); + if (vendor.empty() || name.empty() || version.empty()) { + continue; + } + const string packId = vendor + "::" + name; + const string pdscFile = GetCmsisPackRoot() + "/.Web/" + vendor + "." + name + ".pdsc"; + latestPacks[packId] = { version, pdscFile }; + } + } + // read effective PDSC files (installed + local), keeping only the latest ones. Override the current entry if the local version is newer than the web version + XmlItem attributes; + map effectivePdscMap; + if (GetEffectivePdscFilesAsMap(effectivePdscMap, true)) { + for (const auto& [_, localPdscFile] : effectivePdscMap) { + RtePackage* pack = LoadPack(localPdscFile); + if (!pack) { + continue; + } + const string& vendor = pack->GetVendorString(); + const string& name = pack->GetName(); + const string& version = pack->GetVersionString(); + if (vendor.empty() || name.empty() || version.empty()) { + continue; + } + const string packId = vendor + "::" + name; + auto it = latestPacks.find(packId); + if (it == latestPacks.end() || VersionCmp::Compare(it->second.first, version) < 0) { + latestPacks[packId] = { version, localPdscFile }; + } + } + } + return !latestPacks.empty(); +} unique_ptr RteKernel::CreateUniqueXmlTree(IXmlItemBuilder* itemBuilder, const std::string& ext) const { diff --git a/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc index 98c4c374b..c356e85c0 100644 --- a/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc +++ b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc @@ -7,8 +7,8 @@ - Pre-initial version 0.0.1 forS testing CheckPackVersionCmd - + Pre-initial version 0.0.1 forS testing CheckPackVersionCmd + diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index ae7ea1e05..30e2ee1fb 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -6024,12 +6024,8 @@ void ProjMgrWorker::CheckMissingLinkerScript(ContextItem& context) { } bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& results, const std::string& filter) { - struct LatestPackInfo { - string version; - string pdscFile; - }; - map usedPacks; - map latestPacks; + map usedPacks; // Vendor::Name -> pack name, vendor and currently used version + map> latestPacks; // Vendor::Name -> (latest available version, resolved PDSC file path) vector selectedContexts = m_selectedContexts; if (selectedContexts.empty()) { for (const auto& [contextName, _] : m_contexts) { @@ -6041,57 +6037,34 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res if (!LoadPacks(context)) { return false; } + for (const auto& pack : m_loadedPacks) { const string packId = pack->GetVendorString() + "::" + pack->GetName(); const string& currentVersion = pack->GetVersionString(); usedPacks[packId] = { pack->GetName(), pack->GetVendorString(), currentVersion }; } } - map effectivePdscMap; - if (!m_kernel->GetEffectivePdscFilesAsMap(effectivePdscMap, true)) { - ProjMgrLogger::Get().Error("failed to get effective PDSC files"); - return false; - } - if (effectivePdscMap.empty()) { - ProjMgrLogger::Get().Error("no effective PDSC files found"); - return false; - } - for (const auto& [_, pdscFile] : effectivePdscMap) { - RtePackage* pack = m_kernel->LoadPack(pdscFile); - if (!pack) { - continue; - } - const string& vendor = pack->GetVendorString(); - const string& name = pack->GetName(); - const string& version = pack->GetVersionString(); - // Ignore incomplete pack entries - if (vendor.empty() || name.empty() || version.empty()) { - continue; - } - const string packId = vendor + "::" + name; - latestPacks[packId] = { version, pdscFile }; - } - if (latestPacks.empty()) { - ProjMgrLogger::Get().Error("failed to resolve latest pack information from effective PDSC files"); + if (!m_kernel->ReadPackLatestVerAndPath(latestPacks)) { + ProjMgrLogger::Get().Error("failed to read latest pack information from pack index"); return false; } vector checkPackResults; for (const auto& [packId, currentPack] : usedPacks) { - auto latestPackIt = latestPacks.find(packId); - if (latestPackIt == latestPacks.end()) { + auto latestPack = latestPacks.find(packId); + if (latestPack == latestPacks.end()) { checkPackResults.push_back(packId + "@" + currentPack.version + " (not found in CMSIS pack root)"); continue; } - const LatestPackInfo& latestPack = latestPackIt->second; - const string& latestVersion = latestPack.version; + const string& latestVersion = latestPack->second.first; + const string& latestPdscFile = latestPack->second.second; const int cmp = VersionCmp::Compare(currentPack.version, latestVersion); if (cmp < 0) { string outStr = packId + "@" + currentPack.version + " -> " + latestVersion; if (m_verbose) { vector releaseNotes; - if (ReadPackReleaseNotes(latestPack.pdscFile, currentPack.version, latestVersion, releaseNotes)) { + if (ReadPackReleaseNotes(latestPdscFile, currentPack.version, latestVersion, releaseNotes)) { for (const auto& note : releaseNotes) { outStr += note; } @@ -6123,27 +6096,25 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res bool ProjMgrWorker::ReadPackReleaseNotes(const string& pdscFile, const string& currentVersion, const string& latestVersion, vector& releaseNotes) { RtePackage* pack = m_kernel->LoadPack(pdscFile); - if (!pack) { - return false; - } + if (!pack) { return false; } + RteItem* releases = pack->GetFirstChild("releases"); - if (!releases) { - return false; - } + if (!releases) { return false; } + for (auto& child : releases->GetChildren()) { if (!child || child->GetTag() != "release") { continue; } - const std::string& releaseVersion = child->GetAttribute("version"); - const std::string& text = child->GetText(); + const string& releaseVersion = child->GetAttribute("version"); + const string& text = child->GetText(); if (releaseVersion.empty() || text.empty()) { continue; } - // skip versions newer than the resolved latest version + // ignore releases newer than the resolved latest version if (VersionCmp::Compare(releaseVersion, latestVersion) > 0) { continue; } - // stop when reaching current version or older + // stop once the current version or an older version is reached if (VersionCmp::Compare(releaseVersion, currentVersion) <= 0) { break; } From 3b68a1004498abbab97d4ae5dd6a3e8d4a5fb211 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Mon, 27 Apr 2026 16:01:34 +0200 Subject: [PATCH 05/14] Small fix --- libs/rtemodel/include/RteKernel.h | 10 ++++++++++ libs/rtemodel/src/RteKernel.cpp | 2 +- .../packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc | 2 +- .../ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo1.FLM | 2 +- .../ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo2.FLM | 2 +- .../packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc | 2 +- tools/projmgr/src/ProjMgrWorker.cpp | 1 - 7 files changed, 15 insertions(+), 6 deletions(-) diff --git a/libs/rtemodel/include/RteKernel.h b/libs/rtemodel/include/RteKernel.h index 758e865bb..47a17b449 100644 --- a/libs/rtemodel/include/RteKernel.h +++ b/libs/rtemodel/include/RteKernel.h @@ -360,7 +360,17 @@ class RteKernel */ virtual YmlTree* CreateYmlTree(IXmlItemBuilder* itemBuilder) const; + /** + * @brief get this pointer to use in const methods + * @return this + */ RteKernel* GetThisKernel() const { return const_cast(this); } + + /** + * @brief parses a repository index file + * @param absolute path to the repository index file + * @return pointer to "pindex" element if successful, nullptr otherwise + */ XMLTreeElement* ParseRepositoryIdx(const std::string& indexPath) const; // data diff --git a/libs/rtemodel/src/RteKernel.cpp b/libs/rtemodel/src/RteKernel.cpp index 24e0509d4..779cad6f8 100644 --- a/libs/rtemodel/src/RteKernel.cpp +++ b/libs/rtemodel/src/RteKernel.cpp @@ -659,7 +659,7 @@ bool RteKernel::ReadPackLatestVerAndPath(map>& late latestPacks[packId] = { version, pdscFile }; } } - // read effective PDSC files (installed + local), keeping only the latest ones. Override the current entry if the local version is newer than the web version + // read effective PDSC files (installed + local). Override the current entry if the local version is newer than the web version XmlItem attributes; map effectivePdscMap; if (GetEffectivePdscFilesAsMap(effectivePdscMap, true)) { diff --git a/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc index c356e85c0..e35a076e4 100644 --- a/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc +++ b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc @@ -7,7 +7,7 @@ - Pre-initial version 0.0.1 forS testing CheckPackVersionCmd + Pre-initial version 0.0.1 for testing CheckPackVersionCmd diff --git a/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo1.FLM b/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo1.FLM index 6fca4f90e..49ff6d807 100644 --- a/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo1.FLM +++ b/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo1.FLM @@ -1 +1 @@ -CortexM4Device.FLM : not real flash algorithm \ No newline at end of file +CortexM4Device.FLM : not real flash algorithm diff --git a/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo2.FLM b/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo2.FLM index 0f2e24ff2..d3de2a7a2 100644 --- a/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo2.FLM +++ b/test/packs/ARM/RteTestBoard/0.0.1/Board/Flash/BoardAlgo2.FLM @@ -1 +1 @@ -CortexM4SubFamily.FLM : not real flash algorithm \ No newline at end of file +CortexM4SubFamily.FLM : not real flash algorithm diff --git a/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc b/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc index 24e71ffba..4eaec244e 100644 --- a/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc +++ b/test/packs/ARM/RteTestBoard/0.1.0/ARM.RteTestBoard.pdsc @@ -12,7 +12,7 @@ Pre-initial version 0.0.2 for testing CheckPackVerCmd - + Pre-initial version 0.0.1 for testing CheckPackVerCmd diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index 30e2ee1fb..ac58d632c 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -6037,7 +6037,6 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res if (!LoadPacks(context)) { return false; } - for (const auto& pack : m_loadedPacks) { const string packId = pack->GetVendorString() + "::" + pack->GetName(); const string& currentVersion = pack->GetVersionString(); From 5481314d0e2d3dccc304e63e8533ff3546391949 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Mon, 27 Apr 2026 16:36:20 +0200 Subject: [PATCH 06/14] Fix unit tests --- libs/rtemodel/src/RteKernel.cpp | 2 +- tools/projmgr/src/ProjMgrWorker.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/rtemodel/src/RteKernel.cpp b/libs/rtemodel/src/RteKernel.cpp index 779cad6f8..db8dcaffb 100644 --- a/libs/rtemodel/src/RteKernel.cpp +++ b/libs/rtemodel/src/RteKernel.cpp @@ -656,7 +656,7 @@ bool RteKernel::ReadPackLatestVerAndPath(map>& late } const string packId = vendor + "::" + name; const string pdscFile = GetCmsisPackRoot() + "/.Web/" + vendor + "." + name + ".pdsc"; - latestPacks[packId] = { version, pdscFile }; + latestPacks[packId] = { version, RteFsUtils::Exists(pdscFile) ? pdscFile : string() }; } } // read effective PDSC files (installed + local). Override the current entry if the local version is newer than the web version diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index 9cf65b9ef..b417b4678 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -6050,6 +6050,8 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res } bool ProjMgrWorker::ReadPackReleaseNotes(const string& pdscFile, const string& currentVersion, const string& latestVersion, vector& releaseNotes) { + if (pdscFile.empty() || !RteFsUtils::Exists(pdscFile)) { return false; } + RtePackage* pack = m_kernel->LoadPack(pdscFile); if (!pack) { return false; } From 85c61506f5d30e7280e901caa22af6b9f0427544 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Mon, 27 Apr 2026 16:44:59 +0200 Subject: [PATCH 07/14] Fix unit tests --- tools/projmgr/test/src/ProjMgrUnitTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index ec69e11d0..bd931d062 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -663,7 +663,7 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_CheckPackVerCmd) { string csolutionFile = testinput_folder + "/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml"; // no csolution file provided argv[1] = (char*)"check"; - EXPECT_EQ(1, RunProjMgr(3, argv, 0)); + EXPECT_EQ(1, RunProjMgr(2, argv, 0)); auto errStr = streamRedirect.GetErrorString(); EXPECT_STREQ(errStr.c_str(), "error csolution: input csolution.yml was not specified\n"); From 0cc9f66978f996385dfc622404f51abec7da4fd7 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Mon, 27 Apr 2026 16:51:22 +0200 Subject: [PATCH 08/14] Remove redundant code --- tools/projmgr/src/ProjMgrWorker.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index b417b4678..9cf65b9ef 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -6050,8 +6050,6 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res } bool ProjMgrWorker::ReadPackReleaseNotes(const string& pdscFile, const string& currentVersion, const string& latestVersion, vector& releaseNotes) { - if (pdscFile.empty() || !RteFsUtils::Exists(pdscFile)) { return false; } - RtePackage* pack = m_kernel->LoadPack(pdscFile); if (!pack) { return false; } From ab9c712aae97beb7a4b7025c52ec4afa89adaee3 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Mon, 27 Apr 2026 17:13:20 +0200 Subject: [PATCH 09/14] Update unit tests --- libs/rtemodel/test/src/RteChkTest.cpp | 8 ++++---- libs/rtemodel/test/src/RteModelTest.cpp | 2 +- tools/projmgr/test/src/ProjMgrUnitTests.cpp | 15 ++++++++++++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/libs/rtemodel/test/src/RteChkTest.cpp b/libs/rtemodel/test/src/RteChkTest.cpp index 886bd60a1..c6fe370af 100644 --- a/libs/rtemodel/test/src/RteChkTest.cpp +++ b/libs/rtemodel/test/src/RteChkTest.cpp @@ -15,7 +15,7 @@ using namespace std; TEST(RteChkTest, Summary) { -const string summary = "Collecting pdsc files 8 files found\n\ +const string summary = "Collecting pdsc files 9 files found\n\ Parsing XML passed\n\ \n\ Constructing Model passed\n\ @@ -25,10 +25,10 @@ Cleaning XML data\n\ Validating Model passed\n\ \n\ Summary:\n\ -Packs: 8\n\ +Packs: 9\n\ Generic: 4\n\ DFP: 3\n\ -BSP: 1\n\ +BSP: 2\n\ \n\ Components: 61\n\ From generic packs: 36\n\ @@ -50,7 +50,7 @@ completed\n"; rteChk.AddFileDir(RteModelTestConfig::CMSIS_PACK_ROOT); int res = rteChk.RunCheckRte(); EXPECT_EQ(res, 0); - EXPECT_EQ(rteChk.GetPackCount(), 8); + EXPECT_EQ(rteChk.GetPackCount(), 9); EXPECT_EQ(rteChk.GetComponentCount(), 61); EXPECT_EQ(rteChk.GetDeviceCount(), 10); EXPECT_EQ(rteChk.GetBoardCount(), 15); diff --git a/libs/rtemodel/test/src/RteModelTest.cpp b/libs/rtemodel/test/src/RteModelTest.cpp index db9c2f34f..bfefcc745 100644 --- a/libs/rtemodel/test/src/RteModelTest.cpp +++ b/libs/rtemodel/test/src/RteModelTest.cpp @@ -143,7 +143,7 @@ TEST(RteModelTest, LoadPacks) { list files; rteKernel.GetEffectivePdscFiles(files, false); - EXPECT_EQ(files.size(), 11); + EXPECT_EQ(files.size(), 12); RteModel* rteModel = rteKernel.GetGlobalModel(); ASSERT_NE(rteModel, nullptr); diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index bd931d062..038f639db 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -658,7 +658,7 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_ListDependencies) { } TEST_F(ProjMgrUnitTests, RunProjMgr_CheckPackVerCmd) { - char* argv[4]; + char* argv[6]; StdStreamRedirect streamRedirect; string csolutionFile = testinput_folder + "/TestSolution/CheckPackVerCmd/checkPackVerCmd.csolution.yml"; // no csolution file provided @@ -691,6 +691,19 @@ ARM::RteTestBoard@0.0.1 -> 0.1.0\n\ ARM::RteTest_DFP@0.1.1+metadata -> 0.2.0\n\ Release notes for v0.2.0:\n\ Added a new device 'RteTest_ARMCM0_Dual'\n"); + + // check verbose output with filtering + streamRedirect.ClearStringStreams(); + argv[4] = (char*)"-f"; + argv[5] = (char*)"RteTestBoard"; + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + outStr = streamRedirect.GetOutString(); + EXPECT_STREQ(outStr.c_str(), "\ +ARM::RteTestBoard@0.0.1 -> 0.1.0\n\ + Release notes for v0.1.0:\n\ + Initial version\n\ + Release notes for v0.0.2:\n\ + Pre-initial version 0.0.2 for testing CheckPackVerCmd\n"); } TEST_F(ProjMgrUnitTests, RunProjMgr_ConvertProject_1) { From b15301e3cb89c4a6cdaab2ba00f4d7a05d6f12c3 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Tue, 28 Apr 2026 09:06:47 +0200 Subject: [PATCH 10/14] Small improvement --- libs/rtemodel/include/RteKernel.h | 1 - .../ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc | 2 +- tools/projmgr/include/ProjMgrWorker.h | 6 +++--- tools/projmgr/src/ProjMgrWorker.cpp | 16 ++++++++-------- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libs/rtemodel/include/RteKernel.h b/libs/rtemodel/include/RteKernel.h index 47a17b449..0bc680549 100644 --- a/libs/rtemodel/include/RteKernel.h +++ b/libs/rtemodel/include/RteKernel.h @@ -384,6 +384,5 @@ class RteKernel std::string m_cmsisToolboxDir; std::map m_externalGeneratorFiles; std::map m_externalGenerators; - }; #endif // RteKernel_H diff --git a/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc index e35a076e4..dc3521d51 100644 --- a/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc +++ b/test/packs/ARM/RteTestBoard/0.0.1/ARM.RteTestBoard.pdsc @@ -7,7 +7,7 @@ - Pre-initial version 0.0.1 for testing CheckPackVersionCmd + Pre-initial version 0.0.1 for testing CheckPackVerCmd diff --git a/tools/projmgr/include/ProjMgrWorker.h b/tools/projmgr/include/ProjMgrWorker.h index d19fb638b..683ba1d9a 100644 --- a/tools/projmgr/include/ProjMgrWorker.h +++ b/tools/projmgr/include/ProjMgrWorker.h @@ -1065,10 +1065,10 @@ class ProjMgrWorker { /** * @brief read release notes for versions newer than the current version and up to the latest version - * @param resolved path to the PDSC file of the latest effective pack + * @param resolved path to the latest PDSC file * @param version currently used by the project - * @param latest available version resolved for the pack - * @param output list of collected release note strings for versions + * @param latest available version resolved for the latest pack or the .pidx file + * @param output list of collected release note strings for versions to be filled * @return true if at least one matching release note was found, otherwise false */ bool ReadPackReleaseNotes(const std::string& pdscFile, const std::string& currentVersion, const std::string& latestVersion, std::vector& releaseNotes); diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index 9cf65b9ef..e6e0336f7 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -5980,7 +5980,7 @@ void ProjMgrWorker::CheckMissingLinkerScript(ContextItem& context) { } bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& results, const std::string& filter) { - map usedPacks; // Vendor::Name -> pack name, vendor and currently used version + map usedPacks; // Vendor::Name -> currently used version map> latestPacks; // Vendor::Name -> (latest available version, resolved PDSC file path) vector selectedContexts = m_selectedContexts; if (selectedContexts.empty()) { @@ -5996,7 +5996,7 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res for (const auto& pack : m_loadedPacks) { const string packId = pack->GetVendorString() + "::" + pack->GetName(); const string& currentVersion = pack->GetVersionString(); - usedPacks[packId] = { pack->GetName(), pack->GetVendorString(), currentVersion }; + usedPacks[packId] = currentVersion; } } @@ -6006,20 +6006,20 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res } vector checkPackResults; - for (const auto& [packId, currentPack] : usedPacks) { + for (const auto& [packId, currentVersion] : usedPacks) { auto latestPack = latestPacks.find(packId); if (latestPack == latestPacks.end()) { - checkPackResults.push_back(packId + "@" + currentPack.version + " (not found in CMSIS pack root)"); + checkPackResults.push_back(packId + "@" + currentVersion + " (not found in CMSIS pack root)"); continue; } const string& latestVersion = latestPack->second.first; const string& latestPdscFile = latestPack->second.second; - const int cmp = VersionCmp::Compare(currentPack.version, latestVersion); + const int cmp = VersionCmp::Compare(currentVersion, latestVersion); if (cmp < 0) { - string outStr = packId + "@" + currentPack.version + " -> " + latestVersion; + string outStr = packId + "@" + currentVersion + " -> " + latestVersion; if (m_verbose) { vector releaseNotes; - if (ReadPackReleaseNotes(latestPdscFile, currentPack.version, latestVersion, releaseNotes)) { + if (ReadPackReleaseNotes(latestPdscFile, currentVersion, latestVersion, releaseNotes)) { for (const auto& note : releaseNotes) { outStr += note; } @@ -6029,7 +6029,7 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res } checkPackResults.push_back(outStr); } else { - checkPackResults.push_back(packId + "@" + currentPack.version + " (up-to-date)"); + checkPackResults.push_back(packId + "@" + currentVersion + " (up-to-date)"); } } if (checkPackResults.empty()) { From 6d2ce61007ccc46d599a575907167e9d7c2f9f17 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Tue, 28 Apr 2026 09:11:33 +0200 Subject: [PATCH 11/14] Small improvement2 --- libs/rtemodel/include/RteKernel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/rtemodel/include/RteKernel.h b/libs/rtemodel/include/RteKernel.h index 0bc680549..b895a0232 100644 --- a/libs/rtemodel/include/RteKernel.h +++ b/libs/rtemodel/include/RteKernel.h @@ -384,5 +384,6 @@ class RteKernel std::string m_cmsisToolboxDir; std::map m_externalGeneratorFiles; std::map m_externalGenerators; + }; #endif // RteKernel_H From afcf91d36febba3a6d90c66f270ae8eab79aa9b8 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Tue, 28 Apr 2026 13:47:11 +0200 Subject: [PATCH 12/14] Additionally check packs required via `path:` node --- tools/projmgr/src/ProjMgrWorker.cpp | 51 +++++++++++++++---- .../checkPackVerCmd_my-packs.csolution.yml | 17 +++++++ .../RteTestPack/ARM.RteTestBoard.pdsc | 29 +++++++++++ tools/projmgr/test/src/ProjMgrUnitTests.cpp | 11 ++++ 4 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd_my-packs.csolution.yml create mode 100644 tools/projmgr/test/data/TestSolution/CheckPackVerCmd/my-packs/RteTestPack/ARM.RteTestBoard.pdsc diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index e6e0336f7..29b90d602 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -5982,6 +5982,7 @@ void ProjMgrWorker::CheckMissingLinkerScript(ContextItem& context) { bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& results, const std::string& filter) { map usedPacks; // Vendor::Name -> currently used version map> latestPacks; // Vendor::Name -> (latest available version, resolved PDSC file path) + map workspacePacks; // Vendor::Name -> local pack path specified in project '- pack: path:' section vector selectedContexts = m_selectedContexts; if (selectedContexts.empty()) { for (const auto& [contextName, _] : m_contexts) { @@ -5995,8 +5996,7 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res } for (const auto& pack : m_loadedPacks) { const string packId = pack->GetVendorString() + "::" + pack->GetName(); - const string& currentVersion = pack->GetVersionString(); - usedPacks[packId] = currentVersion; + usedPacks[packId] = pack->GetVersionString(); } } @@ -6004,20 +6004,53 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res ProjMgrLogger::Get().Error("failed to read latest pack information from pack index"); return false; } + // merge project-specified path packs into latestPacks + for (const auto& contextName : selectedContexts) { + ContextItem& context = m_contexts.at(contextName); + for (const auto& [pdscFile, pathVersion] : context.pdscFiles) { + const string& packPath = pathVersion.first; + // skip packs without specified local path and therefore pathVersion.first is empty + if (packPath.empty()) { + continue; + } + RtePackage* pack = m_kernel->LoadPack(pdscFile); + if (!pack) { + continue; + } + const string& vendor = pack->GetVendorString(); + const string& name = pack->GetName(); + const string& version = pack->GetVersionString(); + if (vendor.empty() || name.empty() || version.empty()) { + continue; + } + const string packId = vendor + "::" + name; + auto latestPack = latestPacks.find(packId); + workspacePacks[packId] = packPath; + if (latestPack == latestPacks.end() || VersionCmp::Compare(latestPack->second.first, version) < 0) { + latestPacks[packId] = { version, pdscFile }; + } + } + } vector checkPackResults; for (const auto& [packId, currentVersion] : usedPacks) { auto latestPack = latestPacks.find(packId); if (latestPack == latestPacks.end()) { - checkPackResults.push_back(packId + "@" + currentVersion + " (not found in CMSIS pack root)"); + checkPackResults.push_back(packId + "@" + currentVersion + " (not found in CMSIS pack root or project-specified pack paths)"); continue; } const string& latestVersion = latestPack->second.first; const string& latestPdscFile = latestPack->second.second; - const int cmp = VersionCmp::Compare(currentVersion, latestVersion); - if (cmp < 0) { - string outStr = packId + "@" + currentVersion + " -> " + latestVersion; - if (m_verbose) { + const bool isOutdated = VersionCmp::Compare(currentVersion, latestVersion) < 0; + string outStr = isOutdated ? + packId + "@" + currentVersion + " -> " + latestVersion : + packId + "@" + currentVersion + " (up-to-date)"; + if (m_verbose) { + auto workspacePack = workspacePacks.find(packId); + if (workspacePack != workspacePacks.end()) { + outStr += "\n Local path: " + workspacePack->second; + } + if (isOutdated) { vector releaseNotes; if (ReadPackReleaseNotes(latestPdscFile, currentVersion, latestVersion, releaseNotes)) { for (const auto& note : releaseNotes) { @@ -6027,10 +6060,8 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res outStr += "\n Release notes: unavailable"; } } - checkPackResults.push_back(outStr); - } else { - checkPackResults.push_back(packId + "@" + currentVersion + " (up-to-date)"); } + checkPackResults.push_back(outStr); } if (checkPackResults.empty()) { ProjMgrLogger::Get().Error("no packs were found for version check"); diff --git a/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd_my-packs.csolution.yml b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd_my-packs.csolution.yml new file mode 100644 index 000000000..f4b1ad885 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/checkPackVerCmd_my-packs.csolution.yml @@ -0,0 +1,17 @@ +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + + build-types: + - type: Debug + compiler: AC6 + + packs: + - pack: ARM::RteTest + - pack: ARM::RteTest_DFP@0.1.1 + - pack: ARM::RteTestBoard + path: ./my-packs/RteTestPack + + projects: + - project: ./checkPackVerCmd.cproject.yml diff --git a/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/my-packs/RteTestPack/ARM.RteTestBoard.pdsc b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/my-packs/RteTestPack/ARM.RteTestBoard.pdsc new file mode 100644 index 000000000..d55757041 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/CheckPackVerCmd/my-packs/RteTestPack/ARM.RteTestBoard.pdsc @@ -0,0 +1,29 @@ + + + + RteTestBoard + Testing packages listing + ARM + + + + Active development... (a project-specified pack for testing CheckPackVerCmd) + + + Initial version + + + Pre-initial version 0.0.2 for testing CheckPackVerCmd + + + Pre-initial version 0.0.1 for testing CheckPackVerCmd + + + + + + + + + + diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index 038f639db..ebc0ef5c4 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -704,6 +704,17 @@ ARM::RteTestBoard@0.0.1 -> 0.1.0\n\ Initial version\n\ Release notes for v0.0.2:\n\ Pre-initial version 0.0.2 for testing CheckPackVerCmd\n"); + + // check verbose output for a project-specified pack + streamRedirect.ClearStringStreams(); + csolutionFile = testinput_folder + "/TestSolution/CheckPackVerCmd/checkPackVerCmd_my-packs.csolution.yml"; + argv[2] = (char*)csolutionFile.c_str(); + EXPECT_EQ(0, RunProjMgr(6, argv, 0)); + outStr = streamRedirect.GetOutString(); + const string expectedStr = "\ +ARM::RteTestBoard@0.2.0-dev (up-to-date)\n\ + Local path: " + testinput_folder + "/TestSolution/CheckPackVerCmd/my-packs/RteTestPack\n"; + EXPECT_STREQ(outStr.c_str(), expectedStr.c_str()); } TEST_F(ProjMgrUnitTests, RunProjMgr_ConvertProject_1) { From c87f29f9584bbdb90b8c3a525824e03b6ab58569 Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Tue, 28 Apr 2026 15:42:00 +0200 Subject: [PATCH 13/14] Refine code --- tools/projmgr/src/ProjMgrWorker.cpp | 56 +++++++-------------- tools/projmgr/test/src/ProjMgrUnitTests.cpp | 2 +- 2 files changed, 19 insertions(+), 39 deletions(-) diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index 29b90d602..b29d46218 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -5980,15 +5980,18 @@ void ProjMgrWorker::CheckMissingLinkerScript(ContextItem& context) { } bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& results, const std::string& filter) { - map usedPacks; // Vendor::Name -> currently used version + map> usedPacks; // Vendor::Name -> (currently used version, project-specified path if any) map> latestPacks; // Vendor::Name -> (latest available version, resolved PDSC file path) - map workspacePacks; // Vendor::Name -> local pack path specified in project '- pack: path:' section vector selectedContexts = m_selectedContexts; if (selectedContexts.empty()) { for (const auto& [contextName, _] : m_contexts) { selectedContexts.push_back(contextName); } } + if (!m_kernel->ReadPackLatestVerAndPath(latestPacks)) { + ProjMgrLogger::Get().Error("failed to read latest pack information from pack index"); + return false; + } for (const auto& contextName : selectedContexts) { ContextItem& context = m_contexts.at(contextName); if (!LoadPacks(context)) { @@ -5996,44 +5999,21 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res } for (const auto& pack : m_loadedPacks) { const string packId = pack->GetVendorString() + "::" + pack->GetName(); - usedPacks[packId] = pack->GetVersionString(); - } - } - - if (!m_kernel->ReadPackLatestVerAndPath(latestPacks)) { - ProjMgrLogger::Get().Error("failed to read latest pack information from pack index"); - return false; - } - // merge project-specified path packs into latestPacks - for (const auto& contextName : selectedContexts) { - ContextItem& context = m_contexts.at(contextName); - for (const auto& [pdscFile, pathVersion] : context.pdscFiles) { - const string& packPath = pathVersion.first; - // skip packs without specified local path and therefore pathVersion.first is empty - if (packPath.empty()) { - continue; - } - RtePackage* pack = m_kernel->LoadPack(pdscFile); - if (!pack) { - continue; - } - const string& vendor = pack->GetVendorString(); - const string& name = pack->GetName(); const string& version = pack->GetVersionString(); - if (vendor.empty() || name.empty() || version.empty()) { - continue; - } - const string packId = vendor + "::" + name; - auto latestPack = latestPacks.find(packId); - workspacePacks[packId] = packPath; - if (latestPack == latestPacks.end() || VersionCmp::Compare(latestPack->second.first, version) < 0) { - latestPacks[packId] = { version, pdscFile }; + usedPacks[packId].first = version; + if (pack->GetPackageState() == PS_EXPLICIT_PATH) { + usedPacks[packId].second = pack->GetAbsolutePackagePath(); + auto latestPack = latestPacks.find(packId); + if (latestPack == latestPacks.end() || VersionCmp::Compare(latestPack->second.first, version) < 0) { + latestPacks[packId] = { version, pack->GetPackageFileName() }; + } } } } vector checkPackResults; - for (const auto& [packId, currentVersion] : usedPacks) { + for (const auto& [packId, packInfo] : usedPacks) { + const string& currentVersion = packInfo.first; auto latestPack = latestPacks.find(packId); if (latestPack == latestPacks.end()) { checkPackResults.push_back(packId + "@" + currentVersion + " (not found in CMSIS pack root or project-specified pack paths)"); @@ -6046,9 +6026,9 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res packId + "@" + currentVersion + " -> " + latestVersion : packId + "@" + currentVersion + " (up-to-date)"; if (m_verbose) { - auto workspacePack = workspacePacks.find(packId); - if (workspacePack != workspacePacks.end()) { - outStr += "\n Local path: " + workspacePack->second; + const string& specifiedPackPath = packInfo.second; + if (!specifiedPackPath.empty()) { + outStr += "\n Local path: " + specifiedPackPath; } if (isOutdated) { vector releaseNotes; @@ -6084,7 +6064,7 @@ bool ProjMgrWorker::ReadPackReleaseNotes(const string& pdscFile, const string& c RtePackage* pack = m_kernel->LoadPack(pdscFile); if (!pack) { return false; } - RteItem* releases = pack->GetFirstChild("releases"); + RteItem* releases = pack->GetReleases(); if (!releases) { return false; } for (auto& child : releases->GetChildren()) { diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index ebc0ef5c4..251421c78 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -713,7 +713,7 @@ ARM::RteTestBoard@0.0.1 -> 0.1.0\n\ outStr = streamRedirect.GetOutString(); const string expectedStr = "\ ARM::RteTestBoard@0.2.0-dev (up-to-date)\n\ - Local path: " + testinput_folder + "/TestSolution/CheckPackVerCmd/my-packs/RteTestPack\n"; + Local path: " + testinput_folder + "/TestSolution/CheckPackVerCmd/my-packs/RteTestPack/\n"; EXPECT_STREQ(outStr.c_str(), expectedStr.c_str()); } From 8ac1cf83e51e50f4fba378d4d348920c3003c78c Mon Sep 17 00:00:00 2001 From: Jen-Tse Huang Date: Tue, 28 Apr 2026 16:06:47 +0200 Subject: [PATCH 14/14] Change `Local Path:` absolute path to relative path starting from coslution.yml --- tools/projmgr/src/ProjMgrWorker.cpp | 2 +- tools/projmgr/test/src/ProjMgrUnitTests.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index b29d46218..58afa2c96 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -6002,7 +6002,7 @@ bool ProjMgrWorker::CheckPackVerAndCollectRelNotes(std::vector& res const string& version = pack->GetVersionString(); usedPacks[packId].first = version; if (pack->GetPackageState() == PS_EXPLICIT_PATH) { - usedPacks[packId].second = pack->GetAbsolutePackagePath(); + usedPacks[packId].second = RteFsUtils::RelativePath(pack->GetAbsolutePackagePath(), context.csolution->directory); auto latestPack = latestPacks.find(packId); if (latestPack == latestPacks.end() || VersionCmp::Compare(latestPack->second.first, version) < 0) { latestPacks[packId] = { version, pack->GetPackageFileName() }; diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index 251421c78..d45b2f4ed 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -713,7 +713,7 @@ ARM::RteTestBoard@0.0.1 -> 0.1.0\n\ outStr = streamRedirect.GetOutString(); const string expectedStr = "\ ARM::RteTestBoard@0.2.0-dev (up-to-date)\n\ - Local path: " + testinput_folder + "/TestSolution/CheckPackVerCmd/my-packs/RteTestPack/\n"; + Local path: my-packs/RteTestPack\n"; EXPECT_STREQ(outStr.c_str(), expectedStr.c_str()); }