Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion tools/projmgr/include/ProjMgr.h
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -198,6 +198,7 @@ class ProjMgr {
bool m_cbuildgen;
bool m_updateIdx;
bool m_rpcMode = false;
bool m_locked;
GroupNode m_files;
std::vector<ContextItem*> m_processedContexts;
std::vector<ContextItem*> m_allContexts;
Expand Down
7 changes: 5 additions & 2 deletions tools/projmgr/include/ProjMgrWorker.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ struct VariablesConfiguration {
* west on flag
* layer variables configurations
* unresolved components
* map of available packs for locked packs
*/
struct ContextItem {
CdefaultItem* cdefault = nullptr;
Expand Down Expand Up @@ -553,6 +554,7 @@ struct ContextItem {
bool westOn = false;
std::vector<VariablesConfiguration> variablesConfigurations;
std::set<RteComponentInstance*> unresolvedComponents;
StrMap availablePackVersions;
};

/**
Expand Down Expand Up @@ -627,10 +629,11 @@ class ProjMgrWorker {
* @brief list available packs
* @param reference to list of packs
* @param bListMissingPacksOnly only missing packs
* @param bLocked print available update version for locked packs
* @param filter words to filter results
* @return true if executed successfully
*/
bool ListPacks(std::vector<std::string>& packs, bool bListMissingPacksOnly, const std::string& filter = RteUtils::EMPTY_STRING);
bool ListPacks(std::vector<std::string>& packs, bool bListMissingPacksOnly, bool bLocked = false, const std::string& filter = RteUtils::EMPTY_STRING);

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

Expand Down
11 changes: 7 additions & 4 deletions tools/projmgr/src/ProjMgr.cpp
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -170,14 +170,15 @@ int ProjMgr::ParseCommandLine(int argc, char** argv) {
cxxopts::Option cbuildgen("cbuildgen", "Generate legacy *.cprj files", cxxopts::value<bool>()->default_value("false"));
cxxopts::Option contentLength("content-length", "Prepend 'Content-Length' header to JSON RPC requests and responses", cxxopts::value<bool>()->default_value("false"));
cxxopts::Option activeTargetSet("a,active", "Select active target-set: <target-type>[@<set>]", cxxopts::value<string>());
cxxopts::Option locked("locked", "Print available update version for locked packs", cxxopts::value<bool>()->default_value("false"));

// command options dictionary
map<string, std::pair<bool, vector<cxxopts::Option>>> optionsDict = {
// command, optional args, options
{"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}}},
{"list packs", { true, {context, contextSet, activeTargetSet, debug, filter, load, missing, quiet, schemaCheck, toolchain, 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}}},
{"list configs", { false, {context, contextSet, activeTargetSet, debug, filter, load, quiet, schemaCheck, toolchain, verbose}}},
Expand All @@ -201,7 +202,8 @@ int ProjMgr::ParseCommandLine(int argc, char** argv) {
solution, context, contextSet, filter, generator,
load, clayerSearchPath, missing, schemaCheck, noUpdateRte, output, outputAlt,
help, version, verbose, debug, dryRun, exportSuffix, toolchain, ymlOrder,
relativePaths, frozenPacks, updateIdx, quiet, cbuildgen, contentLength, activeTargetSet
relativePaths, frozenPacks, updateIdx, quiet, cbuildgen, contentLength,
activeTargetSet, locked
});
options.parse_positional({ "positional" });

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

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

vector<string> packs;
bool ret = m_worker.ListPacks(packs, m_missingPacks, m_filter);
bool ret = m_worker.ListPacks(packs, m_missingPacks, m_locked, m_filter);
for (const auto& pack : packs) {
ProjMgrLogger::out() << pack << endl;
}
Expand Down
72 changes: 43 additions & 29 deletions tools/projmgr/src/ProjMgrWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1713,27 +1713,13 @@
if (!specifiedMetadata.empty()) {
m_packMetadata[RteUtils::ExtractPrefix(packageEntry.pack, "+")] = specifiedMetadata;
}
// System wide package
vector<string> matchedPackIds = FindMatchingPackIdsInCbuildPack(packageEntry, resolvedPacks);
if (matchedPackIds.size()) {
// Cbuild pack content matches, so use it
for (const auto& resolvedPackId : matchedPackIds) {
PackageItem package;
package.origin = packageEntry.origin;
package.selectedBy = packageEntry.pack;
ProjMgrUtils::ConvertToPackInfo(resolvedPackId, package.pack);
context.userInputToResolvedPackIdMap[packageEntry.pack].insert(make_pair(resolvedPackId, package));
context.packRequirements.push_back(package);
}
} else {
// Not matching cbuild pack, add it unless a wildcard entry
PackageItem package;
ProjMgrUtils::ConvertToPackInfo(packageEntry.pack, package.pack);
package.selectedBy = packageEntry.pack;
// Store pack entries in separated vectors for later resolution in the right order
if (!package.pack.name.empty() && !WildCards::IsWildcardPattern(package.pack.name)) {
packEntries[ProjMgrUtils::GetVersionType(package.pack.version)].push_back(packageEntry);
}
// Store pack entries in separated vectors for later resolution in the right order, unless a wildcard entry
// TODO: store also the wildcard entries, expanding them but preserving origin and selectedBy for each resolved pack
PackageItem package;
ProjMgrUtils::ConvertToPackInfo(packageEntry.pack, package.pack);
package.selectedBy = packageEntry.pack;
if (!package.pack.name.empty() && !WildCards::IsWildcardPattern(package.pack.name)) {
packEntries[ProjMgrUtils::GetVersionType(package.pack.version)].push_back(packageEntry);
}
} else {
// Project local pack - add as-is
Expand Down Expand Up @@ -1762,7 +1748,7 @@
for (const auto& versionType : { VersionType::FIXED, VersionType::EQUIVALENT, VersionType::COMPATIBLE,
VersionType::MINIMUM, VersionType::ANY }) {
for (const auto& packEntry : packEntries[versionType]) {
ResolvePackRequirement(context, packEntry);
ResolvePackRequirement(context, packEntry, ignoreCBuildPack);
}
}

Expand Down Expand Up @@ -1792,7 +1778,7 @@
return true;
}

void ProjMgrWorker::ResolvePackRequirement(ContextItem& context, const PackItem& packageEntry) {
void ProjMgrWorker::ResolvePackRequirement(ContextItem& context, const PackItem& packageEntry, bool ignoreCBuildPack) {
// Resolve version range using installed/local packs
// Reuse already resolved pack when possible
PackageItem package;
Expand All @@ -1815,13 +1801,29 @@
{"vendor", package.pack.vendor},
{"version", versionRange}
});
auto pdsc = m_kernel->GetEffectivePdscFile(attributes);
auto [packId, _] = m_kernel->GetEffectivePdscFile(attributes);
// Only remember the version of the pack if we had it installed or local
// Will be used when serializing the cbuild-pack.yml file later
if (!pdsc.first.empty()) {
string installedVersion = RtePackage::VersionFromId(pdsc.first);
if (!packId.empty()) {
string installedVersion = RtePackage::VersionFromId(packId);
package.pack.version = VersionCmp::RemoveVersionMeta(installedVersion);
context.userInputToResolvedPackIdMap[packageEntry.pack].insert(make_pair(pdsc.first, package));

// Check whether the packageEntry is already locked in cbuild-pack
if (!ignoreCBuildPack) {
vector<string> locked = FindMatchingPackIdsInCbuildPack(packageEntry, context.csolution->cbuildPack.packs);
if (!locked.empty()) {
// TODO: When wildcards will be fully stored in cbuild-pack there may be multiple matches
const auto& lockedId = locked.front();
if (lockedId != packId) {
// Save available version if different from locked
context.availablePackVersions[lockedId] = package.pack.version;
// Keep the locked pack
packId = lockedId;
package.pack.version = RtePackage::VersionFromId(lockedId);
}
}
}
context.userInputToResolvedPackIdMap[packageEntry.pack].insert(make_pair(packId, package));
} else {
// Remember that we had the user input, but it does not match any installed pack
context.userInputToResolvedPackIdMap[packageEntry.pack] = {};
Expand Down Expand Up @@ -3989,8 +3991,9 @@
return ret;
}

bool ProjMgrWorker::ListPacks(vector<string>&packs, bool bListMissingPacksOnly, const string& filter) {
bool ProjMgrWorker::ListPacks(vector<string>&packs, bool bListMissingPacksOnly, bool bLocked, const string& filter) {
map<string, string, RtePackageComparator> packsMap;
StrMap availablePackVersions;
list<string> pdscFiles;
if (!InitializeModel()) {
return false;
Expand Down Expand Up @@ -4052,6 +4055,13 @@
// check if additional dependencies must be added
CheckMissingPackRequirements(RteUtils::EMPTY_STRING);
}
// get available updates for locked packs
if (bLocked) {
for (const auto& selectedContext : m_selectedContexts) {
ContextItem& context = m_contexts[selectedContext];
availablePackVersions.merge(context.availablePackVersions);
}
}
}

if (!m_contextErrMap.empty()) {
Expand All @@ -4066,7 +4076,11 @@
packsVec.reserve(packsMap.size());
for (auto [id, fileName] : packsMap) {
string s = id;
if (!fileName.empty()) {
if (bLocked) {
if (!availablePackVersions[id].empty()) {
s += " (locked) available update " + availablePackVersions[id];
}
} else if (!fileName.empty()) {
string str = fileName;
if(m_relativePaths) {
if(str.find(m_packRoot) == 0) {
Expand Down
20 changes: 18 additions & 2 deletions tools/projmgr/test/src/ProjMgrUnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2621,7 +2621,7 @@ TEST_F(ProjMgrUnitTests, ListPacks) {
vector<string> packs;
EXPECT_TRUE(m_worker.ParseContextSelection({}));
m_worker.SetLoadPacksPolicy(LoadPacksPolicy::ALL);
EXPECT_TRUE(m_worker.ListPacks(packs, false, "RTETest"));
EXPECT_TRUE(m_worker.ListPacks(packs, false, false, "RTETest"));
string allPacks;
for (auto& pack : packs) {
allPacks += pack + "\n";
Expand All @@ -2636,7 +2636,7 @@ TEST_F(ProjMgrUnitTests, ListPacksLatest) {
vector<string> packs;
EXPECT_TRUE(m_worker.ParseContextSelection({}));
m_worker.SetLoadPacksPolicy(LoadPacksPolicy::LATEST);
EXPECT_TRUE(m_worker.ListPacks(packs, false, "RTETest"));
EXPECT_TRUE(m_worker.ListPacks(packs, false, false, "RTETest"));
string latestPacks;
for (auto& pack : packs) {
latestPacks += pack + "\n";
Expand Down Expand Up @@ -6476,6 +6476,22 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_ListPacks_ContextSet) {
EXPECT_NE(outStr.find("ARM::RteTest_DFP@0.2.0"), string::npos);
}

TEST_F(ProjMgrUnitTests, RunProjMgr_ListPacks_LockedOption) {
char* argv[5];
StdStreamRedirect streamRedirect;
const string& csolution = testinput_folder + "/TestSolution/PackLocking/lock_pack_version.csolution.yml";

// list packs --locked
argv[1] = (char*)"list";
argv[2] = (char*)"packs";
argv[3] = (char*)csolution.c_str();
argv[4] = (char*)"--locked";
EXPECT_EQ(0, RunProjMgr(5, argv, 0));

auto outStr = streamRedirect.GetOutString();
EXPECT_NE(outStr.find("ARM::RteTest_DFP@0.1.1 (locked) available update 0.2.0"), string::npos);
}

TEST_F(ProjMgrUnitTests, RunProjMgr_ListBoards_ContextSet) {
char* argv[6];
StdStreamRedirect streamRedirect;
Expand Down
Loading