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
4 changes: 2 additions & 2 deletions tools/projmgr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ include(FetchContent)
FetchContent_Declare(
rpc-interface
DOWNLOAD_EXTRACT_TIMESTAMP ON
URL https://github.com/Open-CMSIS-Pack/csolution-rpc/releases/download/v0.0.3/csolution-rpc.zip
URL_HASH SHA256=edc762373b3b7dad5b966ecb271f03866b12841675e0967a809c10c9883f29f4
URL https://github.com/Open-CMSIS-Pack/csolution-rpc/releases/download/v0.0.4/csolution-rpc.zip
URL_HASH SHA256=ca9bfdacb35b44b6cadf29d87123adbfc1a5e944af7f2aefda0ccf7fd4bd216f
)
FetchContent_MakeAvailable(rpc-interface)

Expand Down
15 changes: 13 additions & 2 deletions tools/projmgr/include/ProjMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,20 @@ class ProjMgr {
/**
* @brief load solution
* @param path to <solution>.csolution.yml file
* @param active target set in the format <target-type>[@<set>]
* @return processing status
*/
bool LoadSolution(const std::string& csolution);
bool LoadSolution(const std::string& csolution, const std::string& activeTargetSet);

/**
* @brief convert solution and generate yml files
* @param path to <solution>.csolution.yml file
* @param active target set in the format <target-type>[@<set>]
* @param update-rte: create/update configuration files
* @return processing status
*/
bool RunConvert(const std::string&csolution = RteUtils::EMPTY_STRING,
const std::string& activeTargetSet = RteUtils::EMPTY_STRING, const bool& updateRte = false);

protected:
/**
Expand Down Expand Up @@ -184,7 +195,6 @@ class ProjMgr {
std::set<std::string> m_failedContext;

bool RunConfigure();
bool RunConvert();
bool RunCodeGenerator();
bool RunListPacks();
bool RunListBoards();
Expand All @@ -211,6 +221,7 @@ class ProjMgr {
bool ParseAndValidateContexts();
bool ProcessContexts();
bool IsSolutionImageOnly();
void InitSolution(const std::string& csolution, const std::string& activeTargetSet, const bool& updateRte);
};

#endif // PROJMGR_H
25 changes: 19 additions & 6 deletions tools/projmgr/src/ProjMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ bool ProjMgr::PopulateContexts(void) {

bool ProjMgr::GenerateYMLConfigurationFiles(bool previousResult) {
// Generate cbuild pack file
const bool isUsingContexts = m_contextSet || m_context.size() != 0;
const bool isUsingContexts = m_contextSet || m_activeTargetSet.has_value() || m_context.size() != 0;
if (!m_emitter.GenerateCbuildPack(m_processedContexts, isUsingContexts, m_frozenPacks)) {
return false;
}
Expand Down Expand Up @@ -750,7 +750,12 @@ bool ProjMgr::RunConfigure() {
return success;
}

bool ProjMgr::RunConvert(void) {
bool ProjMgr::RunConvert(const std::string& csolution, const std::string& activeTargetSet, const bool& updateRte) {
// Set csolution.yml file and options
if (!csolution.empty()) {
InitSolution(csolution, activeTargetSet, updateRte);
}

// Configure
bool Success = Configure();

Expand Down Expand Up @@ -1286,14 +1291,22 @@ void ProjMgr::Clear() {
ProjMgrLogger::Get().Clear();
}

bool ProjMgr::LoadSolution(const std::string& csolution) {
void ProjMgr::InitSolution(const std::string& csolution, const std::string& activeTargetSet, const bool& updateRte) {
Clear();

m_csolutionFile = csolution;
m_rootDir = RteUtils::ExtractFilePath(m_csolutionFile, false);
m_updateRteFiles = updateRte;
if (activeTargetSet.empty()) {
// fallback to 'context-set' for backward compatibility
m_contextSet = true;
} else {
m_activeTargetSet = activeTargetSet;
}
}

bool ProjMgr::LoadSolution(const std::string& csolution, const std::string& activeTargetSet) {

m_contextSet = true;
m_updateRteFiles = false;
InitSolution(csolution, activeTargetSet, false);

if (!PopulateContexts()) {
return false;
Expand Down
32 changes: 29 additions & 3 deletions tools/projmgr/src/ProjMgrRpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
RpcArgs::SuccessResult Apply(const string& context) override;
RpcArgs::SuccessResult Resolve(const string& context) override;
RpcArgs::SuccessResult LoadPacks(void) override;
RpcArgs::SuccessResult LoadSolution(const string& solution) override;
RpcArgs::SuccessResult LoadSolution(const string& solution, const string& activeTarget) override;
RpcArgs::UsedItems GetUsedItems(const string& context) override;
RpcArgs::PacksInfo GetPacksInfo(const string& context) override;
RpcArgs::DeviceList GetDeviceList(const string& context, const string& namePattern, const string& vendor) override;
Expand All @@ -95,6 +95,7 @@
RpcArgs::Results ValidateComponents(const string& context) override;
RpcArgs::LogMessages GetLogMessages(void) override;
RpcArgs::DraftProjectsInfo GetDraftProjects(const RpcArgs::DraftProjectsFilter& filter) override;
RpcArgs::ConvertSolutionResult ConvertSolution(const string& solution, const string& activeTarget, const bool& updateRte) override;

protected:
enum Exception
Expand Down Expand Up @@ -201,6 +202,7 @@
RpcArgs::GetVersionResult res = {{true}};
res.message = string("Running ") + INTERNAL_NAME + " " + VERSION_STRING;
res.version = VERSION_STRING;
res.apiVersion = RPC_API_VERSION;
return res;
}

Expand Down Expand Up @@ -279,7 +281,7 @@
return result;
}

RpcArgs::SuccessResult RpcHandler::LoadSolution(const string& solution) {
RpcArgs::SuccessResult RpcHandler::LoadSolution(const string& solution, const string& activeTarget) {
RpcArgs::SuccessResult result = {false};
const auto csolutionFile = RteFsUtils::MakePathCanonical(solution);
if (!regex_match(csolutionFile, regex(".*\\.csolution\\.(yml|yaml)"))) {
Expand All @@ -290,7 +292,7 @@
result.message = "Packs must be loaded before loading solution";
return result;
}
result.success = m_solutionLoaded = m_manager.LoadSolution(csolutionFile);
result.success = m_solutionLoaded = m_manager.LoadSolution(csolutionFile, activeTarget);
if (!m_solutionLoaded) {
result.message = "failed to load and process solution " + csolutionFile;
}
Expand Down Expand Up @@ -673,4 +675,28 @@
return applications;
}

RpcArgs::ConvertSolutionResult RpcHandler::ConvertSolution(const string& solution, const string& activeTarget, const bool& updateRte) {
RpcArgs::ConvertSolutionResult result = { false };

Check warning on line 679 in tools/projmgr/src/ProjMgrRpcServer.cpp

View workflow job for this annotation

GitHub Actions / build-swig (macos-13, darwin, amd64, csolution, publicRepo, true, true)

suggest braces around initialization of subobject [-Wmissing-braces]

Check warning on line 679 in tools/projmgr/src/ProjMgrRpcServer.cpp

View workflow job for this annotation

GitHub Actions / build-swig (macos-13, darwin, amd64, csolution, publicRepo, true, true)

suggest braces around initialization of subobject [-Wmissing-braces]

Check warning on line 679 in tools/projmgr/src/ProjMgrRpcServer.cpp

View workflow job for this annotation

GitHub Actions / build (macos-13, darwin, amd64, csolution, publicRepo, true, true)

suggest braces around initialization of subobject [-Wmissing-braces]

Check warning on line 679 in tools/projmgr/src/ProjMgrRpcServer.cpp

View workflow job for this annotation

GitHub Actions / unittest (macos-14, darwin, arm64, csolution, publicRepo, false, false)

suggest braces around initialization of subobject [-Wmissing-braces]

Check warning on line 679 in tools/projmgr/src/ProjMgrRpcServer.cpp

View workflow job for this annotation

GitHub Actions / build (macos-14, darwin, arm64, csolution, publicRepo, false, false)

suggest braces around initialization of subobject [-Wmissing-braces]

Check warning on line 679 in tools/projmgr/src/ProjMgrRpcServer.cpp

View workflow job for this annotation

GitHub Actions / unittest (macos-13, darwin, amd64, csolution, publicRepo, true, true)

suggest braces around initialization of subobject [-Wmissing-braces]
const auto csolutionFile = RteFsUtils::MakePathCanonical(solution);
if (!regex_match(csolutionFile, regex(".*\\.csolution\\.(yml|yaml)"))) {
result.message = solution + " is not a *.csolution.yml file";
return result;
}
if (!m_manager.RunConvert(csolutionFile, activeTarget, updateRte) || !ProjMgrLogger::Get().GetErrors().empty()) {
if (m_worker.HasVarDefineError()) {
const auto& vars = m_worker.GetUndefLayerVars();
result.undefinedLayers = StrVec(vars.begin(), vars.end());
result.message = "Layer variables undefined, names can be found under 'undefinedLayers'";
} else if (m_worker.HasCompilerDefineError()) {
result.selectCompiler = m_worker.GetSelectableCompilers();
result.message = "Compiler undefined, selectable values can be found under 'selectCompiler'";
} else {
result.message = "Convert solution failed, see log messages";
}
return result;
}
result.success = true;
return result;
}

// end of ProkMgrRpcServer.cpp
4 changes: 4 additions & 0 deletions tools/projmgr/test/data/TestRpc/minimal.csolution.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ solution:
target-types:
- type: TestHW
device: RteTest_ARMCM4_NOFP
target-set:
- set:
images:
- project-context: minimal

projects:
- project: minimal.cproject.yml
Expand Down
68 changes: 54 additions & 14 deletions tools/projmgr/test/src/ProjMgrRpcTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "CrossPlatformUtils.h"
#include "ProductInfo.h"
#include "RteFsUtils.h"
#include "yaml-cpp/yaml.h"

#include <fstream>
Expand All @@ -26,7 +27,10 @@ class ProjMgrRpcTests : public ProjMgr, public ::testing::Test {
vector<json> RunRpcMethods(const string& strIn);
string RunRpcMethodsWithContent(const string& strIn);

string CreateLoadRequests(const string& solution, const vector<string>& contextList = RteUtils::EMPTY_STRING_VECTOR);
string CreateLoadRequests(const string& solution,
const string& activeTarget = RteUtils::EMPTY_STRING,
const vector<string>& contextList = RteUtils::EMPTY_STRING_VECTOR
);

};

Expand All @@ -41,12 +45,12 @@ string ProjMgrRpcTests::FormatRequest(const int id, const string& method, const
return request.dump();
}

string ProjMgrRpcTests::CreateLoadRequests(const string& solution, const vector<string>& contextList)
string ProjMgrRpcTests::CreateLoadRequests(const string& solution, const string& activeTarget, const vector<string>& contextList)
{
string loadSolutionRequest;
if(!solution.empty()) {
auto csolutionPath = testinput_folder + solution;
loadSolutionRequest = FormatRequest(2, "LoadSolution", json({{ "solution", csolutionPath }}));
loadSolutionRequest = FormatRequest(2, "LoadSolution", json({{ "solution", csolutionPath }, { "activeTarget", activeTarget } }));
if(!contextList.empty()) {
YAML::Node cbuildset;
cbuildset["cbuild-set"]["generated-by"] = "ProjMrgUnitTests";
Expand All @@ -69,7 +73,7 @@ vector<json> ProjMgrRpcTests::RunRpcMethods(const string& strIn) {
StdStreamRedirect streamRedirect;
streamRedirect.SetInString(strIn);
char* argv[] = { (char*)"csolution", (char*)"rpc" };
EXPECT_EQ(0, RunProjMgr(2, argv, 0));
EXPECT_EQ(0, RunProjMgr(2, argv, m_envp));
string line;
vector<json> responses;
istringstream iss(streamRedirect.GetOutString());
Expand All @@ -83,7 +87,7 @@ string ProjMgrRpcTests::RunRpcMethodsWithContent(const string& strIn) {
StdStreamRedirect streamRedirect;
streamRedirect.SetInString(strIn);
char* argv[] = { (char*)"csolution", (char*)"rpc", (char*)"--content-length" };
EXPECT_EQ(0, RunProjMgr(3, argv, 0));
EXPECT_EQ(0, RunProjMgr(3, argv, m_envp));
return streamRedirect.GetOutString();
}

Expand All @@ -110,6 +114,7 @@ TEST_F(ProjMgrRpcTests, RpcGetVersion) {
EXPECT_EQ(1, responses[0]["id"]);
EXPECT_TRUE(responses[0]["result"]["success"]);
EXPECT_EQ(string(VERSION_STRING), responses[0]["result"]["version"]);
EXPECT_EQ(string(RPC_API_VERSION), responses[0]["result"]["apiVersion"]);
}

TEST_F(ProjMgrRpcTests, RpcGetVersionWithContent) {
Expand All @@ -119,7 +124,7 @@ TEST_F(ProjMgrRpcTests, RpcGetVersionWithContent) {
}

TEST_F(ProjMgrRpcTests, RpcLoadSolution) {
const auto& requests = CreateLoadRequests("/TestRpc/minimal.csolution.yml");
const auto& requests = CreateLoadRequests("/TestRpc/minimal.csolution.yml", "TestHW");
const auto& responses = RunRpcMethods(requests);
EXPECT_TRUE(responses[0]["result"]["success"]);
EXPECT_TRUE(responses[1]["result"]["success"]);
Expand All @@ -145,7 +150,7 @@ TEST_F(ProjMgrRpcTests, RpcLoadNotSolution) {

TEST_F(ProjMgrRpcTests, RpcLoadSolutionNoPacks) {
auto csolutionPath = testinput_folder + "/TestRpc/minimal.csolution.yml";
const auto& requests = FormatRequest(1, "LoadSolution", json({ { "solution", csolutionPath } }));
const auto& requests = FormatRequest(1, "LoadSolution", json({ { "solution", csolutionPath }, { "activeTarget", "TestHW" } }));
const auto& responses = RunRpcMethods(requests);
EXPECT_FALSE(responses[0]["result"]["success"]);
string msg = responses[0]["result"]["message"];
Expand Down Expand Up @@ -207,7 +212,7 @@ TEST_F(ProjMgrRpcTests, RpcDeviceListContext) {
vector<string> contextList = {
context
};
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", contextList);
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", "", contextList);
// all devices
requests += FormatRequest(3, "GetDeviceList", json({{"context", "selectable+CM0"},{ "namePattern", ""}, {"vendor", ""}}));
requests += FormatRequest(4, "GetDeviceList", json({{"context", "selectable+CM0"},{ "namePattern", "*Dual*"}, {"vendor", ""}}));
Expand Down Expand Up @@ -336,7 +341,7 @@ TEST_F(ProjMgrRpcTests, RpcBoardListContext) {
vector<string> contextList = {
context
};
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", contextList);
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", "", contextList);

// all boards
requests += FormatRequest(2, "GetBoardList", json({{"context", "selectable+CM0"},{ "namePattern", ""}, {"vendor", ""}}));
Expand Down Expand Up @@ -442,7 +447,7 @@ TEST_F(ProjMgrRpcTests, RpcValidateComponents) {
"incompatible+CM0",
"incompatible-variant+CM0",
};
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", contextList);
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", "", contextList);
int id = 3;
for (const auto& context : contextList) {
requests += FormatRequest(id++, "ValidateComponents", json({ { "context", context } }));
Expand Down Expand Up @@ -497,7 +502,7 @@ TEST_F(ProjMgrRpcTests, RpcResolveComponents) {
vector<string> contextList = {
context
};
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", contextList);
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", "", contextList);
requests += FormatRequest(3, "ValidateComponents", json({{ "context", context }}));
requests += FormatRequest(4, "Resolve", json({{ "context", context }}));
requests += FormatRequest(5, "ValidateComponents", json({{ "context", context }}));
Expand Down Expand Up @@ -528,7 +533,7 @@ TEST_F(ProjMgrRpcTests, RpcSelectComponent) {
param["count"] = 1;
param["options"] = json::object();

auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", contextList);
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", "", contextList);
requests += FormatRequest(3, "ValidateComponents", json({{ "context", context }}));
requests += FormatRequest(4, "GetComponentsTree", json({{ "context", context }, {"all", false}}));
requests += FormatRequest(5, "SelectComponent", param);
Expand Down Expand Up @@ -561,7 +566,7 @@ TEST_F(ProjMgrRpcTests, RpcSelectVariant) {
param["id"] = "ARM::RteTest:Dependency:Variant";
param["variant"] = "Compatible";

auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", contextList);
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", "", contextList);
requests += FormatRequest(3, "ValidateComponents", json({{ "context", context }}));
requests += FormatRequest(4, "SelectVariant", param);
requests += FormatRequest(5, "ValidateComponents", json({{ "context", context }}));
Expand Down Expand Up @@ -598,7 +603,7 @@ TEST_F(ProjMgrRpcTests, RpcGetUsedItems) {
param["count"] = 1;
RpcArgs::to_json(param["options"], opt);

auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", contextList);
auto requests = CreateLoadRequests("/Validation/dependencies.csolution.yml", "", contextList);
requests += FormatRequest(3, "GetUsedItems", json({{ "context", context }}));
requests += FormatRequest(4, "SelectComponent", param);
requests += FormatRequest(5, "Apply", param);
Expand Down Expand Up @@ -700,4 +705,39 @@ TEST_F(ProjMgrRpcTests, RpcGetDraftProjects) {
EXPECT_EQ(responses[0]["result"]["message"], "Packs must be loaded before retrieving draft projects");
}

TEST_F(ProjMgrRpcTests, RpcConvertSolution) {
auto csolutionPath = testinput_folder + "/TestRpc/minimal.csolution.yml";
auto requests = FormatRequest(1, "ConvertSolution",
json({ { "solution", csolutionPath }, { "activeTarget", "TestHW" }, { "updateRte", true } }));
auto responses = RunRpcMethods(requests);
EXPECT_TRUE(responses[0]["result"]["success"]);
EXPECT_TRUE(RteFsUtils::Exists(testinput_folder + "/TestRpc/minimal.cbuild-idx.yml"));
EXPECT_TRUE(RteFsUtils::Exists(testinput_folder + "/TestRpc/minimal.cbuild-pack.yml"));
EXPECT_TRUE(RteFsUtils::Exists(testinput_folder + "/TestRpc/out/minimal+TestHW.cbuild-run.yml"));
EXPECT_TRUE(RteFsUtils::Exists(testinput_folder + "/TestRpc/out/minimal/TestHW/minimal+TestHW.cbuild.yml"));

// convert fail
csolutionPath = testinput_folder + "/TestRpc/unknown-component.csolution.yml";
requests = FormatRequest(1, "ConvertSolution",
json({ { "solution", csolutionPath }, { "activeTarget", "" }, { "updateRte", true } }));
responses = RunRpcMethods(requests);
EXPECT_FALSE(responses[0]["result"]["success"]);

// undefined compiler
csolutionPath = testinput_folder + "/TestSolution/SelectableToolchains/select-compiler.csolution.yml";
requests = FormatRequest(1, "ConvertSolution",
json({ { "solution", csolutionPath }, { "activeTarget", "" }, { "updateRte", true } }));
responses = RunRpcMethods(requests);
EXPECT_FALSE(responses[0]["result"]["success"]);
EXPECT_EQ(responses[0]["result"]["selectCompiler"][0], "AC6@>=6.0.0");
EXPECT_EQ(responses[0]["result"]["selectCompiler"][1], "GCC@>=8.0.0");

// undefined layer
csolutionPath = testinput_folder + "/TestLayers/variables-notdefined.csolution.yml";
requests = FormatRequest(1, "ConvertSolution",
json({ { "solution", csolutionPath }, { "activeTarget", "" }, { "updateRte", true } }));
responses = RunRpcMethods(requests);
EXPECT_FALSE(responses[0]["result"]["success"]);
EXPECT_EQ(responses[0]["result"]["undefinedLayers"][0], "NotDefined");
}
// end of ProjMgrRpcTests.cpp
Loading
Loading