From 1551f5fbb0fe7ac41804a2d638cda033a25d6f33 Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Fri, 6 Feb 2026 16:58:31 +0100 Subject: [PATCH] Make behavior of pack filtering consistent in case of all packs enabled (#1411) * Make behavior of pack filtering consistent in case of all packs enabled Filter to use all latest packs also includes all explicitly selected Required by RPC and is consistent with csolution processing * Update tools/projmgr/test/src/ProjMgrRpcTests.cpp Co-authored-by: Daniel Brondani * Copyright and format --------- Co-authored-by: Daniel Brondani --- libs/rtemodel/src/RtePackage.cpp | 13 ++--- libs/rteutils/include/CollectionUtils.h | 34 +++++++++++- libs/rteutils/test/src/RteUtilsTest.cpp | 11 +++- tools/projmgr/src/ProjMgrRpcServer.cpp | 19 ++++--- tools/projmgr/src/ProjMgrWorker.cpp | 4 +- .../test_pack_requirements.csolution.yml | 4 ++ tools/projmgr/test/src/ProjMgrRpcTests.cpp | 53 +++++++++++++++++++ 7 files changed, 119 insertions(+), 19 deletions(-) diff --git a/libs/rtemodel/src/RtePackage.cpp b/libs/rtemodel/src/RtePackage.cpp index 3afa5beaf..b7ee52c2e 100644 --- a/libs/rtemodel/src/RtePackage.cpp +++ b/libs/rtemodel/src/RtePackage.cpp @@ -6,7 +6,7 @@ */ /******************************************************************************/ /* - * Copyright (c) 2020-2021 Arm Limited. All rights reserved. + * Copyright (c) 2020-2026 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ @@ -1139,7 +1139,7 @@ bool RtePackageFilter::AreAllExcluded() const bool RtePackageFilter::IsUseAllPacks() const { - return m_bUseAllPacks && m_selectedPacks.empty() && m_latestPacks.empty(); + return m_bUseAllPacks; } bool RtePackageFilter::IsPackageSelected(const string& packId) const @@ -1170,10 +1170,10 @@ bool RtePackageFilter::IsPackageFiltered(RtePackage* pack) const bool RtePackageFilter::IsPackageFiltered(const string& packId) const { + if(IsPackageSelected(packId)) { // pack is explicitly selected => filtered + return true; + } if (!IsUseAllPacks()) { - if (IsPackageSelected(packId)) - return true; - string commonId = RtePackage::CommonIdFromId(packId); if (m_latestPacks.find(commonId) == m_latestPacks.end()) return false; @@ -1185,8 +1185,9 @@ bool RtePackageFilter::IsPackageFiltered(const string& packId) const } } } - if (m_latestInstalledPacks.find(packId) != m_latestInstalledPacks.end()) + if(m_latestInstalledPacks.find(packId) != m_latestInstalledPacks.end()) { return true; + } return false; } diff --git a/libs/rteutils/include/CollectionUtils.h b/libs/rteutils/include/CollectionUtils.h index 7639a8e0e..77ffb37a4 100644 --- a/libs/rteutils/include/CollectionUtils.h +++ b/libs/rteutils/include/CollectionUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2024 Arm Limited. All rights reserved. + * Copyright (c) 2020-2026 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,7 @@ #include #include #include +#include /** * @brief Returns value stored in a map for a given key or default value if no entry is found @@ -87,6 +88,37 @@ auto key_set(const M& m) { return ks; } +/** + * @brief Finds the first element in a container that satisfies a predicate. + * + * Searches the container in forward order and returns a reference to the + * first element for which the predicate returns true. + * + * @tparam Container A container type providing begin()/end() and value_type. + * @tparam Predicate A callable with signature bool(const value_type&). + * + * @param c Container to search. + * @param pred Predicate applied to each element. + * + * @return std::optional containing a reference to the matching element, + * or std::nullopt if no such element is found. + * + * @note The returned reference remains valid only as long as the container + * is not structurally modified (e.g. erase, reallocation). + * + * @complexity Linear in the size of the container. + */ +template +auto find_item(Container& c, Predicate pred) + -> std::optional> +{ + auto it = std::find_if(std::begin(c), std::end(c), pred); + if(it == std::end(c)) { + return std::nullopt; + } + return *it; // reference, not a copy +} + /** * @brief string pair */ diff --git a/libs/rteutils/test/src/RteUtilsTest.cpp b/libs/rteutils/test/src/RteUtilsTest.cpp index e03371b3f..af68e8ffc 100644 --- a/libs/rteutils/test/src/RteUtilsTest.cpp +++ b/libs/rteutils/test/src/RteUtilsTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2025 Arm Limited. All rights reserved. + * Copyright (c) 2020-2026 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ @@ -497,6 +497,15 @@ TEST(RteUtils, CollectionUtils) EXPECT_EQ(*get_or_default(strToPtr, "two", sDefault), '2'); EXPECT_EQ(*get_or_default(strToPtr, "four", sDefault), 'd'); + + auto notFound = find_item(intToInt, [](const auto& kv) {return kv.second < 5; }); + EXPECT_FALSE(!!notFound); + auto foundInt = find_item(intToInt, [](const auto& kv) {return kv.second > 5; }); + ASSERT_TRUE(!!foundInt); + auto& [key, val] = foundInt->get(); + EXPECT_EQ(key, 1); + EXPECT_EQ(val, 10); + } TEST(RteUtils, ExpandAccessSequences) { diff --git a/tools/projmgr/src/ProjMgrRpcServer.cpp b/tools/projmgr/src/ProjMgrRpcServer.cpp index 8bab3cf68..a000407d6 100644 --- a/tools/projmgr/src/ProjMgrRpcServer.cpp +++ b/tools/projmgr/src/ProjMgrRpcServer.cpp @@ -327,18 +327,17 @@ void RpcHandler::UpdateFilter(const string& context, RteTarget* rteTarget, bool StoreSelectedComponents(rteTarget, selectedComponents); RtePackageFilter packFilter; - if(!all) { - // construct and apply filter - // use resolved pack ID's from selected references - set packIds; - for(auto& ref : GetPackReferences(context)) { - if(ref.selected && ref.resolvedPack.has_value()) { - packIds.insert(ref.resolvedPack.value()); - } + // construct and apply filter + // use resolved pack ID's from selected references + set packIds; + for(auto& ref : GetPackReferences(context)) { + if(ref.selected && ref.resolvedPack.has_value()) { + packIds.insert(ref.resolvedPack.value()); } - packFilter.SetSelectedPackages(packIds); - packFilter.SetUseAllPacks(false); } + packFilter.SetSelectedPackages(packIds); + packFilter.SetUseAllPacks(all); + // only update filter if differs from current state if(!packFilter.IsEqual(rteTarget->GetPackageFilter())) { rteTarget->SetPackageFilter(packFilter); diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index 4e197b1ee..fae591045 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -567,11 +567,13 @@ bool ProjMgrWorker::LoadPacks(ContextItem& context) { set selectedPacks; const bool allOrLatest = (m_loadPacksPolicy == LoadPacksPolicy::ALL) || (m_loadPacksPolicy == LoadPacksPolicy::LATEST); for (const auto& pack : m_loadedPacks) { - if (allOrLatest || (context.pdscFiles.find(pack->GetPackageFileName()) != context.pdscFiles.end())) { + if (context.pdscFiles.find(pack->GetPackageFileName()) != context.pdscFiles.end()) { selectedPacks.insert(pack->GetPackageID()); } } RtePackageFilter filter; + // use all packs is enabled by default, by default policy it should be disabled if selectedPacks is not empty + filter.SetUseAllPacks(allOrLatest || selectedPacks.empty()); filter.SetSelectedPackages(selectedPacks); context.rteActiveTarget->SetPackageFilter(filter); context.rteActiveTarget->UpdateFilterModel(); diff --git a/tools/projmgr/test/data/TestSolution/test_pack_requirements.csolution.yml b/tools/projmgr/test/data/TestSolution/test_pack_requirements.csolution.yml index 1a29e1b30..68d8b7f7c 100644 --- a/tools/projmgr/test/data/TestSolution/test_pack_requirements.csolution.yml +++ b/tools/projmgr/test/data/TestSolution/test_pack_requirements.csolution.yml @@ -8,12 +8,16 @@ solution: build-types: - type: Debug compiler: AC6 + - type: DebugOldDfp + compiler: AC6 - type: Release compiler: GCC packs: - pack: ARM::RteTest for-context: .Debug + - pack: ARM::RteTest_DFP@0.1.1 + for-context: .DebugOldDfp - pack: ARM::RteTest_DFP@>=0.2.0 for-context: .Release - pack: ARM::RteTestRequired diff --git a/tools/projmgr/test/src/ProjMgrRpcTests.cpp b/tools/projmgr/test/src/ProjMgrRpcTests.cpp index bafb14dbf..72cdb1687 100644 --- a/tools/projmgr/test/src/ProjMgrRpcTests.cpp +++ b/tools/projmgr/test/src/ProjMgrRpcTests.cpp @@ -19,6 +19,10 @@ using namespace std; +auto find_item_by_id(json& items, const std::string& id) { + return find_item(items, [&](const auto& item) { return item["id"] == id; }); +} + class ProjMgrRpcTests : public ProjMgr, public ::testing::Test { protected: ProjMgrRpcTests() {} @@ -1012,6 +1016,7 @@ TEST_F(ProjMgrRpcTests, RpcGetPacksInfo) { auto packs = responses[2]["result"]["packs"]; EXPECT_EQ(packs[0]["pack"], "ARM::RteTest_DFP@>=0.2.0"); EXPECT_EQ(packs[0]["resolvedPack"], "ARM::RteTest_DFP@0.2.0"); + EXPECT_FALSE(packs[0].contains("upgrade")); EXPECT_TRUE(responses[3]["result"]["success"]); // get pack infos auto packInfos = responses[3]["result"]["packs"]; @@ -1025,6 +1030,54 @@ TEST_F(ProjMgrRpcTests, RpcGetPacksInfo) { EXPECT_FALSE(packInfos[7].contains("used")); } + +TEST_F(ProjMgrRpcTests, RpcGetPacksNotLatest) { + string context = "test1.DebugOldDfp+CM0"; + vector contextList = { + context + }; + + auto requests = CreateLoadRequests("/TestSolution/test_pack_requirements.csolution.yml", "", contextList); + requests += FormatRequest(3, "GetUsedItems", json({{ "context", context }})); + requests += FormatRequest(4, "GetPacksInfo", json({{ "context", context }, {"all", false}})); + requests += FormatRequest(5, "GetPacksInfo", json({{ "context", context }, {"all", true}})); + + const auto& responses = RunRpcMethods(requests); + + EXPECT_TRUE(responses[2]["result"]["success"]); + auto packs = responses[2]["result"]["packs"]; + EXPECT_EQ(packs[0]["pack"], "ARM::RteTest_DFP@0.1.1"); + EXPECT_EQ(packs[0]["resolvedPack"], "ARM::RteTest_DFP@0.1.1"); + + EXPECT_TRUE(responses[3]["result"]["success"]); // get pack infos + auto packInfos = responses[3]["result"]["packs"]; + EXPECT_EQ(packInfos.size(), 2); + auto p = find_item_by_id(packInfos, "ARM::RteTest_DFP@0.1.1"); + EXPECT_TRUE(!!p); + EXPECT_TRUE(p->get()["used"]); + EXPECT_TRUE(p->get().contains("references")); + p = find_item_by_id(packInfos, "ARM::RteTest_DFP@0.2.0"); + EXPECT_FALSE(!!p); + + auto packInfosAll = responses[4]["result"]["packs"]; + EXPECT_TRUE(packInfosAll.size() > packInfos.size()); + + p = find_item_by_id(packInfosAll, "SomeVendor::RteTest@0.0.1"); + EXPECT_TRUE(!!p); + EXPECT_FALSE(p->get().contains("used")); + + p = find_item_by_id(packInfosAll, "ARM::RteTest_DFP@0.1.1"); + EXPECT_TRUE(!!p); + EXPECT_TRUE(p->get()["used"]); + EXPECT_TRUE(p->get().contains("references")); + + p = find_item_by_id(packInfosAll, "ARM::RteTest_DFP@0.2.0"); + EXPECT_TRUE(!!p); + EXPECT_FALSE(p->get().contains("used")); + EXPECT_FALSE(p->get().contains("references")); +} + + TEST_F(ProjMgrRpcTests, RpcGetPacksInfoLayer) { string context = "packs.CompatibleLayers+RteTest_ARMCM3"; vector contextList = {