Skip to content

Commit 03b5bd7

Browse files
authored
[projmgr] Add list packs --locked option
1 parent fdf6511 commit 03b5bd7

File tree

5 files changed

+75
-38
lines changed

5 files changed

+75
-38
lines changed

tools/projmgr/include/ProjMgr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020-2025 Arm Limited. All rights reserved.
2+
* Copyright (c) 2020-2026 Arm Limited. All rights reserved.
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -198,6 +198,7 @@ class ProjMgr {
198198
bool m_cbuildgen;
199199
bool m_updateIdx;
200200
bool m_rpcMode = false;
201+
bool m_locked;
201202
GroupNode m_files;
202203
std::vector<ContextItem*> m_processedContexts;
203204
std::vector<ContextItem*> m_allContexts;

tools/projmgr/include/ProjMgrWorker.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ struct VariablesConfiguration {
480480
* west on flag
481481
* layer variables configurations
482482
* unresolved components
483+
* map of available packs for locked packs
483484
*/
484485
struct ContextItem {
485486
CdefaultItem* cdefault = nullptr;
@@ -553,6 +554,7 @@ struct ContextItem {
553554
bool westOn = false;
554555
std::vector<VariablesConfiguration> variablesConfigurations;
555556
std::set<RteComponentInstance*> unresolvedComponents;
557+
StrMap availablePackVersions;
556558
};
557559

558560
/**
@@ -627,10 +629,11 @@ class ProjMgrWorker {
627629
* @brief list available packs
628630
* @param reference to list of packs
629631
* @param bListMissingPacksOnly only missing packs
632+
* @param bLocked print available update version for locked packs
630633
* @param filter words to filter results
631634
* @return true if executed successfully
632635
*/
633-
bool ListPacks(std::vector<std::string>& packs, bool bListMissingPacksOnly, const std::string& filter = RteUtils::EMPTY_STRING);
636+
bool ListPacks(std::vector<std::string>& packs, bool bListMissingPacksOnly, bool bLocked = false, const std::string& filter = RteUtils::EMPTY_STRING);
634637

635638
/**
636639
* @brief list available boards
@@ -1298,7 +1301,7 @@ class ProjMgrWorker {
12981301
bool IsEnvironmentCompatible(const std::string& environment, const StrVec& filter);
12991302
bool HasCompatibleEnvironment(const Collection<RteItem*>& environments, const StrVec& filter);
13001303
template<class T> bool CheckFilter(const std::string& filter, const T& item);
1301-
void ResolvePackRequirement(ContextItem& context, const PackItem& packEntry);
1304+
void ResolvePackRequirement(ContextItem& context, const PackItem& packEntry, bool ignoreCBuildPack);
13021305
void FormatResolvedPackIds();
13031306
};
13041307

tools/projmgr/src/ProjMgr.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020-2025 Arm Limited. All rights reserved.
2+
* Copyright (c) 2020-2026 Arm Limited. All rights reserved.
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -170,14 +170,15 @@ int ProjMgr::ParseCommandLine(int argc, char** argv) {
170170
cxxopts::Option cbuildgen("cbuildgen", "Generate legacy *.cprj files", cxxopts::value<bool>()->default_value("false"));
171171
cxxopts::Option contentLength("content-length", "Prepend 'Content-Length' header to JSON RPC requests and responses", cxxopts::value<bool>()->default_value("false"));
172172
cxxopts::Option activeTargetSet("a,active", "Select active target-set: <target-type>[@<set>]", cxxopts::value<string>());
173+
cxxopts::Option locked("locked", "Print available update version for locked packs", cxxopts::value<bool>()->default_value("false"));
173174

174175
// command options dictionary
175176
map<string, std::pair<bool, vector<cxxopts::Option>>> optionsDict = {
176177
// command, optional args, options
177178
{"update-rte", { false, {context, contextSet, activeTargetSet, debug, load, quiet, schemaCheck, toolchain, verbose, frozenPacks}}},
178179
{"convert", { false, {context, contextSet, activeTargetSet, debug, exportSuffix, load, quiet, schemaCheck, noUpdateRte, output, outputAlt, toolchain, verbose, frozenPacks, cbuildgen}}},
179180
{"run", { false, {context, contextSet, activeTargetSet, debug, generator, load, quiet, schemaCheck, verbose, dryRun}}},
180-
{"list packs", { true, {context, contextSet, activeTargetSet, debug, filter, load, missing, quiet, schemaCheck, toolchain, verbose}}},
181+
{"list packs", { true, {context, contextSet, activeTargetSet, debug, filter, load, missing, locked, quiet, schemaCheck, toolchain, verbose}}},
181182
{"list boards", { true, {context, contextSet, activeTargetSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}},
182183
{"list devices", { true, {context, contextSet, activeTargetSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}},
183184
{"list configs", { false, {context, contextSet, activeTargetSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}},
@@ -201,7 +202,8 @@ int ProjMgr::ParseCommandLine(int argc, char** argv) {
201202
solution, context, contextSet, filter, generator,
202203
load, clayerSearchPath, missing, schemaCheck, noUpdateRte, output, outputAlt,
203204
help, version, verbose, debug, dryRun, exportSuffix, toolchain, ymlOrder,
204-
relativePaths, frozenPacks, updateIdx, quiet, cbuildgen, contentLength, activeTargetSet
205+
relativePaths, frozenPacks, updateIdx, quiet, cbuildgen, contentLength,
206+
activeTargetSet, locked
205207
});
206208
options.parse_positional({ "positional" });
207209

@@ -230,6 +232,7 @@ int ProjMgr::ParseCommandLine(int argc, char** argv) {
230232
ProjMgrLogger::m_quiet = parseResult.count("quiet");
231233
m_rpcServer.SetContentLengthHeader(parseResult.count("content-length"));
232234
m_rpcServer.SetDebug(m_debug);
235+
m_locked = parseResult.count("locked");
233236

234237
vector<string> positionalArguments;
235238
if (parseResult.count("positional")) {
@@ -804,7 +807,7 @@ bool ProjMgr::RunListPacks(void) {
804807
}
805808

806809
vector<string> packs;
807-
bool ret = m_worker.ListPacks(packs, m_missingPacks, m_filter);
810+
bool ret = m_worker.ListPacks(packs, m_missingPacks, m_locked, m_filter);
808811
for (const auto& pack : packs) {
809812
ProjMgrLogger::out() << pack << endl;
810813
}

tools/projmgr/src/ProjMgrWorker.cpp

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,27 +1713,13 @@ bool ProjMgrWorker::AddPackRequirements(ContextItem& context, const vector<PackI
17131713
if (!specifiedMetadata.empty()) {
17141714
m_packMetadata[RteUtils::ExtractPrefix(packageEntry.pack, "+")] = specifiedMetadata;
17151715
}
1716-
// System wide package
1717-
vector<string> matchedPackIds = FindMatchingPackIdsInCbuildPack(packageEntry, resolvedPacks);
1718-
if (matchedPackIds.size()) {
1719-
// Cbuild pack content matches, so use it
1720-
for (const auto& resolvedPackId : matchedPackIds) {
1721-
PackageItem package;
1722-
package.origin = packageEntry.origin;
1723-
package.selectedBy = packageEntry.pack;
1724-
ProjMgrUtils::ConvertToPackInfo(resolvedPackId, package.pack);
1725-
context.userInputToResolvedPackIdMap[packageEntry.pack].insert(make_pair(resolvedPackId, package));
1726-
context.packRequirements.push_back(package);
1727-
}
1728-
} else {
1729-
// Not matching cbuild pack, add it unless a wildcard entry
1730-
PackageItem package;
1731-
ProjMgrUtils::ConvertToPackInfo(packageEntry.pack, package.pack);
1732-
package.selectedBy = packageEntry.pack;
1733-
// Store pack entries in separated vectors for later resolution in the right order
1734-
if (!package.pack.name.empty() && !WildCards::IsWildcardPattern(package.pack.name)) {
1735-
packEntries[ProjMgrUtils::GetVersionType(package.pack.version)].push_back(packageEntry);
1736-
}
1716+
// Store pack entries in separated vectors for later resolution in the right order, unless a wildcard entry
1717+
// TODO: store also the wildcard entries, expanding them but preserving origin and selectedBy for each resolved pack
1718+
PackageItem package;
1719+
ProjMgrUtils::ConvertToPackInfo(packageEntry.pack, package.pack);
1720+
package.selectedBy = packageEntry.pack;
1721+
if (!package.pack.name.empty() && !WildCards::IsWildcardPattern(package.pack.name)) {
1722+
packEntries[ProjMgrUtils::GetVersionType(package.pack.version)].push_back(packageEntry);
17371723
}
17381724
} else {
17391725
// Project local pack - add as-is
@@ -1762,7 +1748,7 @@ bool ProjMgrWorker::AddPackRequirements(ContextItem& context, const vector<PackI
17621748
for (const auto& versionType : { VersionType::FIXED, VersionType::EQUIVALENT, VersionType::COMPATIBLE,
17631749
VersionType::MINIMUM, VersionType::ANY }) {
17641750
for (const auto& packEntry : packEntries[versionType]) {
1765-
ResolvePackRequirement(context, packEntry);
1751+
ResolvePackRequirement(context, packEntry, ignoreCBuildPack);
17661752
}
17671753
}
17681754

@@ -1792,7 +1778,7 @@ bool ProjMgrWorker::AddPackRequirements(ContextItem& context, const vector<PackI
17921778
return true;
17931779
}
17941780

1795-
void ProjMgrWorker::ResolvePackRequirement(ContextItem& context, const PackItem& packageEntry) {
1781+
void ProjMgrWorker::ResolvePackRequirement(ContextItem& context, const PackItem& packageEntry, bool ignoreCBuildPack) {
17961782
// Resolve version range using installed/local packs
17971783
// Reuse already resolved pack when possible
17981784
PackageItem package;
@@ -1815,13 +1801,29 @@ void ProjMgrWorker::ResolvePackRequirement(ContextItem& context, const PackItem&
18151801
{"vendor", package.pack.vendor},
18161802
{"version", versionRange}
18171803
});
1818-
auto pdsc = m_kernel->GetEffectivePdscFile(attributes);
1804+
auto [packId, _] = m_kernel->GetEffectivePdscFile(attributes);
18191805
// Only remember the version of the pack if we had it installed or local
18201806
// Will be used when serializing the cbuild-pack.yml file later
1821-
if (!pdsc.first.empty()) {
1822-
string installedVersion = RtePackage::VersionFromId(pdsc.first);
1807+
if (!packId.empty()) {
1808+
string installedVersion = RtePackage::VersionFromId(packId);
18231809
package.pack.version = VersionCmp::RemoveVersionMeta(installedVersion);
1824-
context.userInputToResolvedPackIdMap[packageEntry.pack].insert(make_pair(pdsc.first, package));
1810+
1811+
// Check whether the packageEntry is already locked in cbuild-pack
1812+
if (!ignoreCBuildPack) {
1813+
vector<string> locked = FindMatchingPackIdsInCbuildPack(packageEntry, context.csolution->cbuildPack.packs);
1814+
if (!locked.empty()) {
1815+
// TODO: When wildcards will be fully stored in cbuild-pack there may be multiple matches
1816+
const auto& lockedId = locked.front();
1817+
if (lockedId != packId) {
1818+
// Save available version if different from locked
1819+
context.availablePackVersions[lockedId] = package.pack.version;
1820+
// Keep the locked pack
1821+
packId = lockedId;
1822+
package.pack.version = RtePackage::VersionFromId(lockedId);
1823+
}
1824+
}
1825+
}
1826+
context.userInputToResolvedPackIdMap[packageEntry.pack].insert(make_pair(packId, package));
18251827
} else {
18261828
// Remember that we had the user input, but it does not match any installed pack
18271829
context.userInputToResolvedPackIdMap[packageEntry.pack] = {};
@@ -3989,8 +3991,9 @@ bool ProjMgrWorker::ProcessContext(ContextItem& context, bool loadGenFiles, bool
39893991
return ret;
39903992
}
39913993

3992-
bool ProjMgrWorker::ListPacks(vector<string>&packs, bool bListMissingPacksOnly, const string& filter) {
3994+
bool ProjMgrWorker::ListPacks(vector<string>&packs, bool bListMissingPacksOnly, bool bLocked, const string& filter) {
39933995
map<string, string, RtePackageComparator> packsMap;
3996+
StrMap availablePackVersions;
39943997
list<string> pdscFiles;
39953998
if (!InitializeModel()) {
39963999
return false;
@@ -4052,6 +4055,13 @@ bool ProjMgrWorker::ListPacks(vector<string>&packs, bool bListMissingPacksOnly,
40524055
// check if additional dependencies must be added
40534056
CheckMissingPackRequirements(RteUtils::EMPTY_STRING);
40544057
}
4058+
// get available updates for locked packs
4059+
if (bLocked) {
4060+
for (const auto& selectedContext : m_selectedContexts) {
4061+
ContextItem& context = m_contexts[selectedContext];
4062+
availablePackVersions.merge(context.availablePackVersions);
4063+
}
4064+
}
40554065
}
40564066

40574067
if (!m_contextErrMap.empty()) {
@@ -4066,7 +4076,11 @@ bool ProjMgrWorker::ListPacks(vector<string>&packs, bool bListMissingPacksOnly,
40664076
packsVec.reserve(packsMap.size());
40674077
for (auto [id, fileName] : packsMap) {
40684078
string s = id;
4069-
if (!fileName.empty()) {
4079+
if (bLocked) {
4080+
if (!availablePackVersions[id].empty()) {
4081+
s += " (locked) available update " + availablePackVersions[id];
4082+
}
4083+
} else if (!fileName.empty()) {
40704084
string str = fileName;
40714085
if(m_relativePaths) {
40724086
if(str.find(m_packRoot) == 0) {

tools/projmgr/test/src/ProjMgrUnitTests.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,7 +2621,7 @@ TEST_F(ProjMgrUnitTests, ListPacks) {
26212621
vector<string> packs;
26222622
EXPECT_TRUE(m_worker.ParseContextSelection({}));
26232623
m_worker.SetLoadPacksPolicy(LoadPacksPolicy::ALL);
2624-
EXPECT_TRUE(m_worker.ListPacks(packs, false, "RTETest"));
2624+
EXPECT_TRUE(m_worker.ListPacks(packs, false, false, "RTETest"));
26252625
string allPacks;
26262626
for (auto& pack : packs) {
26272627
allPacks += pack + "\n";
@@ -2636,7 +2636,7 @@ TEST_F(ProjMgrUnitTests, ListPacksLatest) {
26362636
vector<string> packs;
26372637
EXPECT_TRUE(m_worker.ParseContextSelection({}));
26382638
m_worker.SetLoadPacksPolicy(LoadPacksPolicy::LATEST);
2639-
EXPECT_TRUE(m_worker.ListPacks(packs, false, "RTETest"));
2639+
EXPECT_TRUE(m_worker.ListPacks(packs, false, false, "RTETest"));
26402640
string latestPacks;
26412641
for (auto& pack : packs) {
26422642
latestPacks += pack + "\n";
@@ -6476,6 +6476,22 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_ListPacks_ContextSet) {
64766476
EXPECT_NE(outStr.find("ARM::RteTest_DFP@0.2.0"), string::npos);
64776477
}
64786478

6479+
TEST_F(ProjMgrUnitTests, RunProjMgr_ListPacks_LockedOption) {
6480+
char* argv[5];
6481+
StdStreamRedirect streamRedirect;
6482+
const string& csolution = testinput_folder + "/TestSolution/PackLocking/lock_pack_version.csolution.yml";
6483+
6484+
// list packs --locked
6485+
argv[1] = (char*)"list";
6486+
argv[2] = (char*)"packs";
6487+
argv[3] = (char*)csolution.c_str();
6488+
argv[4] = (char*)"--locked";
6489+
EXPECT_EQ(0, RunProjMgr(5, argv, 0));
6490+
6491+
auto outStr = streamRedirect.GetOutString();
6492+
EXPECT_NE(outStr.find("ARM::RteTest_DFP@0.1.1 (locked) available update 0.2.0"), string::npos);
6493+
}
6494+
64796495
TEST_F(ProjMgrUnitTests, RunProjMgr_ListBoards_ContextSet) {
64806496
char* argv[6];
64816497
StdStreamRedirect streamRedirect;

0 commit comments

Comments
 (0)