Skip to content

Commit 3e0a1ea

Browse files
committed
[projmgr] Add ConvertSolution RPC method handling
1 parent d4df01d commit 3e0a1ea

File tree

8 files changed

+125
-37
lines changed

8 files changed

+125
-37
lines changed

tools/projmgr/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ include(FetchContent)
1717
FetchContent_Declare(
1818
rpc-interface
1919
DOWNLOAD_EXTRACT_TIMESTAMP ON
20-
URL https://github.com/brondani/csolution-rpc/releases/download/v0.0.4/csolution-rpc.zip
21-
URL_HASH SHA256=643ab30d25f47b55735bc6fecd3622ad1c7619d8fac901e2b19cd594a01df8b2
20+
URL https://github.com/Open-CMSIS-Pack/csolution-rpc/releases/download/v0.0.4/csolution-rpc.zip
21+
URL_HASH SHA256=ca9bfdacb35b44b6cadf29d87123adbfc1a5e944af7f2aefda0ccf7fd4bd216f
2222
)
2323
FetchContent_MakeAvailable(rpc-interface)
2424

tools/projmgr/include/ProjMgr.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ class ProjMgr {
7070
*/
7171
bool LoadSolution(const std::string& csolution, const std::string& activeTargetSet);
7272

73+
/**
74+
* @brief convert solution and generate yml files
75+
* @param path to <solution>.csolution.yml file
76+
* @param active target set in the format <target-type>[@<set>]
77+
* @param update-rte: create/update configuration files
78+
* @return processing status
79+
*/
80+
bool RunConvert(const std::string&csolution = RteUtils::EMPTY_STRING,
81+
const std::string& activeTargetSet = RteUtils::EMPTY_STRING, const bool& updateRte = false);
82+
7383
protected:
7484
/**
7585
* @brief parse command line options
@@ -185,7 +195,6 @@ class ProjMgr {
185195
std::set<std::string> m_failedContext;
186196

187197
bool RunConfigure();
188-
bool RunConvert();
189198
bool RunCodeGenerator();
190199
bool RunListPacks();
191200
bool RunListBoards();
@@ -212,6 +221,7 @@ class ProjMgr {
212221
bool ParseAndValidateContexts();
213222
bool ProcessContexts();
214223
bool IsSolutionImageOnly();
224+
void InitSolution(const std::string& csolution, const std::string& activeTargetSet, const bool& updateRte);
215225
};
216226

217227
#endif // PROJMGR_H

tools/projmgr/src/ProjMgr.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ bool ProjMgr::PopulateContexts(void) {
563563

564564
bool ProjMgr::GenerateYMLConfigurationFiles(bool previousResult) {
565565
// Generate cbuild pack file
566-
const bool isUsingContexts = m_contextSet || m_context.size() != 0;
566+
const bool isUsingContexts = m_contextSet || m_activeTargetSet.has_value() || m_context.size() != 0;
567567
if (!m_emitter.GenerateCbuildPack(m_processedContexts, isUsingContexts, m_frozenPacks)) {
568568
return false;
569569
}
@@ -750,7 +750,12 @@ bool ProjMgr::RunConfigure() {
750750
return success;
751751
}
752752

753-
bool ProjMgr::RunConvert(void) {
753+
bool ProjMgr::RunConvert(const std::string& csolution, const std::string& activeTargetSet, const bool& updateRte) {
754+
// Set csolution.yml file and options
755+
if (!csolution.empty()) {
756+
InitSolution(csolution, activeTargetSet, updateRte);
757+
}
758+
754759
// Configure
755760
bool Success = Configure();
756761

@@ -1286,19 +1291,22 @@ void ProjMgr::Clear() {
12861291
ProjMgrLogger::Get().Clear();
12871292
}
12881293

1289-
bool ProjMgr::LoadSolution(const std::string& csolution, const std::string& activeTargetSet) {
1294+
void ProjMgr::InitSolution(const std::string& csolution, const std::string& activeTargetSet, const bool& updateRte) {
12901295
Clear();
1291-
12921296
m_csolutionFile = csolution;
12931297
m_rootDir = RteUtils::ExtractFilePath(m_csolutionFile, false);
1294-
m_updateRteFiles = false;
1295-
1298+
m_updateRteFiles = updateRte;
12961299
if (activeTargetSet.empty()) {
12971300
// fallback to 'context-set' for backward compatibility
12981301
m_contextSet = true;
12991302
} else {
13001303
m_activeTargetSet = activeTargetSet;
13011304
}
1305+
}
1306+
1307+
bool ProjMgr::LoadSolution(const std::string& csolution, const std::string& activeTargetSet) {
1308+
1309+
InitSolution(csolution, activeTargetSet, false);
13021310

13031311
if (!PopulateContexts()) {
13041312
return false;

tools/projmgr/src/ProjMgrRpcServer.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class RpcHandler : public RpcMethods {
9595
RpcArgs::Results ValidateComponents(const string& context) override;
9696
RpcArgs::LogMessages GetLogMessages(void) override;
9797
RpcArgs::DraftProjectsInfo GetDraftProjects(const RpcArgs::DraftProjectsFilter& filter) override;
98+
RpcArgs::ConvertSolutionResult ConvertSolution(const string& solution, const string& activeTarget, const bool& updateRte) override;
9899

99100
protected:
100101
enum Exception
@@ -674,4 +675,28 @@ RpcArgs::DraftProjectsInfo RpcHandler::GetDraftProjects(const RpcArgs::DraftProj
674675
return applications;
675676
}
676677

678+
RpcArgs::ConvertSolutionResult RpcHandler::ConvertSolution(const string& solution, const string& activeTarget, const bool& updateRte) {
679+
RpcArgs::ConvertSolutionResult result = { false };
680+
const auto csolutionFile = RteFsUtils::MakePathCanonical(solution);
681+
if (!regex_match(csolutionFile, regex(".*\\.csolution\\.(yml|yaml)"))) {
682+
result.message = solution + " is not a *.csolution.yml file";
683+
return result;
684+
}
685+
if (!m_manager.RunConvert(csolutionFile, activeTarget, updateRte) || !ProjMgrLogger::Get().GetErrors().empty()) {
686+
if (m_worker.HasVarDefineError()) {
687+
const auto& vars = m_worker.GetUndefLayerVars();
688+
result.undefinedLayers = StrVec(vars.begin(), vars.end());
689+
result.message = "Layer variables undefined, names can be found under 'undefinedLayers'";
690+
} else if (m_worker.HasCompilerDefineError()) {
691+
result.selectCompiler = m_worker.GetSelectableCompilers();
692+
result.message = "Compiler undefined, selectable values can be found under 'selectCompiler'";
693+
} else {
694+
result.message = "Convert solution failed, see log messages";
695+
}
696+
return result;
697+
}
698+
result.success = true;
699+
return result;
700+
}
701+
677702
// end of ProkMgrRpcServer.cpp

tools/projmgr/test/src/ProjMgrRpcTests.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "CrossPlatformUtils.h"
1414
#include "ProductInfo.h"
15+
#include "RteFsUtils.h"
1516
#include "yaml-cpp/yaml.h"
1617

1718
#include <fstream>
@@ -72,7 +73,7 @@ vector<json> ProjMgrRpcTests::RunRpcMethods(const string& strIn) {
7273
StdStreamRedirect streamRedirect;
7374
streamRedirect.SetInString(strIn);
7475
char* argv[] = { (char*)"csolution", (char*)"rpc" };
75-
EXPECT_EQ(0, RunProjMgr(2, argv, 0));
76+
EXPECT_EQ(0, RunProjMgr(2, argv, m_envp));
7677
string line;
7778
vector<json> responses;
7879
istringstream iss(streamRedirect.GetOutString());
@@ -86,7 +87,7 @@ string ProjMgrRpcTests::RunRpcMethodsWithContent(const string& strIn) {
8687
StdStreamRedirect streamRedirect;
8788
streamRedirect.SetInString(strIn);
8889
char* argv[] = { (char*)"csolution", (char*)"rpc", (char*)"--content-length" };
89-
EXPECT_EQ(0, RunProjMgr(3, argv, 0));
90+
EXPECT_EQ(0, RunProjMgr(3, argv, m_envp));
9091
return streamRedirect.GetOutString();
9192
}
9293

@@ -704,4 +705,39 @@ TEST_F(ProjMgrRpcTests, RpcGetDraftProjects) {
704705
EXPECT_EQ(responses[0]["result"]["message"], "Packs must be loaded before retrieving draft projects");
705706
}
706707

708+
TEST_F(ProjMgrRpcTests, RpcConvertSolution) {
709+
auto csolutionPath = testinput_folder + "/TestRpc/minimal.csolution.yml";
710+
auto requests = FormatRequest(1, "ConvertSolution",
711+
json({ { "solution", csolutionPath }, { "activeTarget", "TestHW" }, { "updateRte", true } }));
712+
auto responses = RunRpcMethods(requests);
713+
EXPECT_TRUE(responses[0]["result"]["success"]);
714+
EXPECT_TRUE(RteFsUtils::Exists(testinput_folder + "/TestRpc/minimal.cbuild-idx.yml"));
715+
EXPECT_TRUE(RteFsUtils::Exists(testinput_folder + "/TestRpc/minimal.cbuild-pack.yml"));
716+
EXPECT_TRUE(RteFsUtils::Exists(testinput_folder + "/TestRpc/out/minimal+TestHW.cbuild-run.yml"));
717+
EXPECT_TRUE(RteFsUtils::Exists(testinput_folder + "/TestRpc/out/minimal/TestHW/minimal+TestHW.cbuild.yml"));
718+
719+
// convert fail
720+
csolutionPath = testinput_folder + "/TestRpc/unknown-component.csolution.yml";
721+
requests = FormatRequest(1, "ConvertSolution",
722+
json({ { "solution", csolutionPath }, { "activeTarget", "" }, { "updateRte", true } }));
723+
responses = RunRpcMethods(requests);
724+
EXPECT_FALSE(responses[0]["result"]["success"]);
725+
726+
// undefined compiler
727+
csolutionPath = testinput_folder + "/TestSolution/SelectableToolchains/select-compiler.csolution.yml";
728+
requests = FormatRequest(1, "ConvertSolution",
729+
json({ { "solution", csolutionPath }, { "activeTarget", "" }, { "updateRte", true } }));
730+
responses = RunRpcMethods(requests);
731+
EXPECT_FALSE(responses[0]["result"]["success"]);
732+
EXPECT_EQ(responses[0]["result"]["selectCompiler"][0], "AC6@>=6.0.0");
733+
EXPECT_EQ(responses[0]["result"]["selectCompiler"][1], "GCC@>=8.0.0");
734+
735+
// undefined layer
736+
csolutionPath = testinput_folder + "/TestLayers/variables-notdefined.csolution.yml";
737+
requests = FormatRequest(1, "ConvertSolution",
738+
json({ { "solution", csolutionPath }, { "activeTarget", "" }, { "updateRte", true } }));
739+
responses = RunRpcMethods(requests);
740+
EXPECT_FALSE(responses[0]["result"]["success"]);
741+
EXPECT_EQ(responses[0]["result"]["undefinedLayers"][0], "NotDefined");
742+
}
707743
// end of ProjMgrRpcTests.cpp

tools/projmgr/test/src/ProjMgrTestEnv.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ string schema_folder;
2323
string templates_folder;
2424
string etc_folder;
2525
string bin_folder;
26+
char* m_envp[4];
2627

2728
StdStreamRedirect::StdStreamRedirect() :
2829
m_outbuffer(""), m_cerrbuffer(""),
@@ -153,10 +154,13 @@ void ProjMgrTestEnv::SetUp() {
153154

154155
// copy linker script template files
155156
fs::copy(fs::path(templates_folder), fs::path(testcmsiscompiler_folder), fs::copy_options::recursive, ec);
157+
158+
// env vars
159+
SetUpEnvp();
156160
}
157161

158162
void ProjMgrTestEnv::TearDown() {
159-
// Reserved
163+
CleanUpEnvp();
160164
}
161165

162166
void ProjMgrTestEnv::CompareFile(const string& file1, const string& file2, LineReplaceFunc_t file2LineReplaceFunc) {
@@ -277,6 +281,31 @@ int ProjMgrTestEnv::CountOccurrences(const std::string input, const std::string
277281
return occurrences;
278282
}
279283

284+
void ProjMgrTestEnv::SetUpEnvp() {
285+
std::string ac6 = "AC6_TOOLCHAIN_6_18_0=" + testinput_folder;
286+
std::string gcc = "GCC_TOOLCHAIN_11_2_1=" + testinput_folder;
287+
std::string iar = "IAR_TOOLCHAIN_8_50_6=" + testinput_folder;
288+
289+
// Allocate memory for environment variables
290+
m_envp[0] = new char[ac6.size() + 1];
291+
m_envp[1] = new char[iar.size() + 1];
292+
m_envp[2] = new char[gcc.size() + 1];
293+
294+
// Copy strings to allocated memory
295+
strcpy(m_envp[0], ac6.c_str());
296+
strcpy(m_envp[1], iar.c_str());
297+
strcpy(m_envp[2], gcc.c_str());
298+
299+
// Null terminator
300+
m_envp[3] = nullptr;
301+
}
302+
303+
void ProjMgrTestEnv::CleanUpEnvp() {
304+
delete[] m_envp[0];
305+
delete[] m_envp[1];
306+
delete[] m_envp[2];
307+
}
308+
280309
int main(int argc, char **argv) {
281310
try {
282311
testing::InitGoogleTest(&argc, argv);

tools/projmgr/test/src/ProjMgrTestEnv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ extern std::string testcmsiscompiler_folder;
2020
extern std::string schema_folder;
2121
extern std::string etc_folder;
2222
extern std::string bin_folder;
23+
extern char* m_envp[4];
24+
2325
/**
2426
* @brief direct console output to string
2527
*/
@@ -66,6 +68,8 @@ class ProjMgrTestEnv : public ::testing::Environment {
6668
static bool FilterId(const std::string& id, const std::string& includeIds);
6769
static bool IsFileInCbuildFilesList(const std::vector<std::map<std::string, std::string>> files, const std::string file);
6870
static int CountOccurrences(const std::string input, const std::string substring);
71+
void SetUpEnvp();
72+
void CleanUpEnvp();
6973
};
7074

7175
#endif // PROJMGRTESTENV_H

tools/projmgr/test/src/ProjMgrUnitTests.cpp

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,32 +33,10 @@ class ProjMgrUnitTests : public ProjMgr, public ::testing::Test {
3333

3434
void SetUp() {
3535
m_context.clear();
36-
std::string ac6 = "AC6_TOOLCHAIN_6_18_0=" + testinput_folder;
37-
std::string gcc = "GCC_TOOLCHAIN_11_2_1=" + testinput_folder;
38-
std::string iar = "IAR_TOOLCHAIN_8_50_6=" + testinput_folder;
39-
40-
// Allocate memory for environment variables
41-
m_envp[0] = new char[ac6.size() + 1];
42-
m_envp[1] = new char[iar.size() + 1];
43-
m_envp[2] = new char[gcc.size() + 1];
44-
45-
// Copy strings to allocated memory
46-
std::strcpy(m_envp[0], ac6.c_str());
47-
std::strcpy(m_envp[1], iar.c_str());
48-
std::strcpy(m_envp[2], gcc.c_str());
49-
50-
// Null terminator
51-
m_envp[3] = nullptr;
5236
};
5337

5438
void TearDown() {
55-
cleanupEnvp();
56-
}
57-
58-
void cleanupEnvp() {
59-
delete[] m_envp[0];
60-
delete[] m_envp[1];
61-
delete[] m_envp[2];
39+
// reserved
6240
}
6341

6442
void GetFilesInTree(const string& dir, set<string>& files) {
@@ -98,8 +76,6 @@ class ProjMgrUnitTests : public ProjMgr, public ::testing::Test {
9876
fout.close();
9977
return csolutionFile;
10078
}
101-
102-
char* m_envp[4];
10379
};
10480

10581
TEST_F(ProjMgrUnitTests, Validate_Logger) {

0 commit comments

Comments
 (0)