From c115e18c447e6ab8d4e9271f41ef47be13487107 Mon Sep 17 00:00:00 2001 From: Daniel Brondani Date: Wed, 25 Feb 2026 16:08:02 +0100 Subject: [PATCH] [projmgr] Update `cbuild-idx` also in case of early convert errors (#1425) --- tools/projmgr/src/ProjMgr.cpp | 44 +++++++++++-------- tools/projmgr/src/ProjMgrCbuildIdx.cpp | 23 ++++++---- tools/projmgr/src/ProjMgrWorker.cpp | 9 +++- .../ref/test_missing_project.cbuild-idx.yml | 4 ++ tools/projmgr/test/src/ProjMgrUnitTests.cpp | 31 +++++++------ 5 files changed, 68 insertions(+), 43 deletions(-) create mode 100644 tools/projmgr/test/data/TestSolution/ref/test_missing_project.cbuild-idx.yml diff --git a/tools/projmgr/src/ProjMgr.cpp b/tools/projmgr/src/ProjMgr.cpp index af0b6a532..41e58778c 100644 --- a/tools/projmgr/src/ProjMgr.cpp +++ b/tools/projmgr/src/ProjMgr.cpp @@ -474,6 +474,8 @@ bool ProjMgr::SetLoadPacksPolicy(void) { } bool ProjMgr::PopulateContexts(void) { + bool result = true; + if (!m_csolutionFile.empty()) { // Parse csolution if (!m_parser.ParseCsolution(m_csolutionFile, m_checkSchema, m_frozenPacks)) { @@ -517,10 +519,10 @@ bool ProjMgr::PopulateContexts(void) { string const& cprojectFile = fs::canonical(m_rootDir + "/" + cproject, ec).generic_string(); if (cprojectFile.empty()) { ProjMgrLogger::Get().Error("cproject file was not found", "", cproject); - return false; + result = false; } - if (!m_parser.ParseCproject(cprojectFile, m_checkSchema)) { - return false; + else if (!m_parser.ParseCproject(cprojectFile, m_checkSchema)) { + result = false; } } } else { @@ -547,13 +549,13 @@ bool ProjMgr::PopulateContexts(void) { const string& cprojectFile = fs::path(descriptor.cproject).is_absolute() ? descriptor.cproject : fs::canonical(m_rootDir + "/" + descriptor.cproject, ec).generic_string(); if (!m_worker.AddContexts(m_parser, descriptor, cprojectFile)) { - return false; + result = false; } } // Populate active target-set if (m_activeTargetSet.has_value() && !m_worker.PopulateActiveTargetSet(m_activeTargetSet.value())) { - return false; + result = false; } // Add image only context @@ -562,7 +564,7 @@ bool ProjMgr::PopulateContexts(void) { // Retrieve all context types m_worker.RetrieveAllContextTypes(); - return true; + return result; } bool ProjMgr::GenerateYMLConfigurationFiles(bool previousResult) { @@ -599,13 +601,13 @@ bool ProjMgr::GenerateYMLConfigurationFiles(bool previousResult) { } } + // Get executes + map executes; + m_worker.GetExecutes(executes); + // Generate cbuild index file - if (!m_allContexts.empty()) { - map executes; - m_worker.GetExecutes(executes); - if (!m_emitter.GenerateCbuildIndex(m_processedContexts, m_failedContext, executes)) { - return false; - } + if (!m_emitter.GenerateCbuildIndex(m_processedContexts, m_failedContext, executes)) { + return false; } return result; @@ -635,13 +637,15 @@ bool ProjMgr::ParseAndValidateContexts() { } bool ProjMgr::Configure() { + bool result = true; + // Parse all input files and populate contexts inputs if (!PopulateContexts()) { - return false; + result = false; } if (!ParseAndValidateContexts()) { - return false; + result = false; } if (m_worker.HasVarDefineError()) { @@ -654,24 +658,26 @@ bool ProjMgr::Configure() { } // Process contexts - bool error = !ProcessContexts(); + if (!ProcessContexts()) { + result = false; + } if (m_worker.HasToolchainErrors()) { - error = true; + result = false; } m_selectedToolchain = m_worker.GetSelectedToochain(); // Process solution level executes if (!m_worker.ProcessSolutionExecutes()) { - error = true; + result = false; } // Process executes dependencies m_worker.ProcessExecutesDependencies(); // Check missing files if (!m_worker.CheckMissingFiles()) { - error = true; + result = false; } // Collect unused packs @@ -692,7 +698,7 @@ bool ProjMgr::Configure() { } } - return !error; + return result; } bool ProjMgr::ProcessContexts() { diff --git a/tools/projmgr/src/ProjMgrCbuildIdx.cpp b/tools/projmgr/src/ProjMgrCbuildIdx.cpp index 098026048..7d84927ca 100644 --- a/tools/projmgr/src/ProjMgrCbuildIdx.cpp +++ b/tools/projmgr/src/ProjMgrCbuildIdx.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 */ @@ -44,15 +44,17 @@ ProjMgrCbuildIdx::ProjMgrCbuildIdx(YAML::Node node, SetNodeValue(node[YAML_OUTPUT_TMPDIR], FormatPath(parser->GetCsolution().directories.tmpdir, directory)); // Image Only flag - bool imageOnlySolution = true; - for (const auto& processedContext : processedContexts) { - if (!processedContext->imageOnly) { - imageOnlySolution = false; - break; + if (!processedContexts.empty()) { + bool imageOnlySolution = true; + for (const auto& processedContext : processedContexts) { + if (!processedContext->imageOnly) { + imageOnlySolution = false; + break; + } + } + if (imageOnlySolution) { + node[YAML_IMAGE_ONLY] = true; } - } - if (imageOnlySolution) { - node[YAML_IMAGE_ONLY] = true; } // Generate layer info for each target @@ -95,6 +97,9 @@ ProjMgrCbuildIdx::ProjMgrCbuildIdx(YAML::Node node, [&](const pair& elem) { return (fs::path(elem.first).filename().string() == fs::path(cprojectFile).filename().string()); }); + if (itr == cprojects.end()) { + continue; + } auto cproject = itr->second; YAML::Node cprojectNode; const string& cprojectFilename = fs::relative(cproject.path, directory, ec).generic_string(); diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index fae591045..7a5e90b61 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -5006,7 +5006,9 @@ bool ProjMgrWorker::ParseContextSelection( else { m_selectedContexts.clear(); //first context in yml ordered context should be processed - m_selectedContexts.push_back(ymlOrderedContexts.front()); + if (!ymlOrderedContexts.empty()) { + m_selectedContexts.push_back(ymlOrderedContexts.front()); + } } } else { @@ -5036,6 +5038,11 @@ bool ProjMgrWorker::ParseContextSelection( string errMsg = "unknown selected context(s):"; for (const auto& context : unknownContexts) { errMsg += "\n " + context; + // 'remove' shifts unwanted element to the end, 'erase' actually shrinks the vector + m_selectedContexts.erase( + remove(m_selectedContexts.begin(), m_selectedContexts.end(), context), + m_selectedContexts.end() + ); } ProjMgrLogger::Get().Error(errMsg); return false; diff --git a/tools/projmgr/test/data/TestSolution/ref/test_missing_project.cbuild-idx.yml b/tools/projmgr/test/data/TestSolution/ref/test_missing_project.cbuild-idx.yml new file mode 100644 index 000000000..870d2e5c4 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/ref/test_missing_project.cbuild-idx.yml @@ -0,0 +1,4 @@ +build-idx: + generated-by: csolution version 0.0.0 + csolution: ../data/TestSolution/test_missing_project.csolution.yml + tmpdir: tmp diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index 4f43a3f53..fba60458a 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -2863,6 +2863,10 @@ TEST_F(ProjMgrUnitTests, RunProjMgrLayers_missing_project_file) { for (const auto& expected : expectedVec) { EXPECT_TRUE(errStr.find(expected) != string::npos) << "Missing Expected: " + expected; } + + // Check generated cbuild-idx + ProjMgrTestEnv::CompareFile(testoutput_folder + "/test_missing_project.cbuild-idx.yml", + testinput_folder + "/TestSolution/ref/test_missing_project.cbuild-idx.yml"); } TEST_F(ProjMgrUnitTests, RunProjMgrLayers_pname) { @@ -6202,7 +6206,7 @@ TEST_F(ProjMgrUnitTests, FailCreatedFor) { argv[4] = (char*)testoutput_folder.c_str(); EXPECT_EQ(1, RunProjMgr(5, argv, 0)); auto errMsg = streamRedirect.GetErrorString(); - EXPECT_TRUE(regex_match(errMsg, regex(expectedErrMsg))); + EXPECT_TRUE(regex_search(errMsg, regex(expectedErrMsg))); } TEST_F(ProjMgrUnitTests, RunProjMgr_FailedConvertShouldCreateRteDirInProjectFolder) { @@ -6987,20 +6991,19 @@ TEST_F(ProjMgrUnitTests, Test_Check_Define_Value) { //Test2: Check Parsing errors streamRedirect.ClearStringStreams(); - expected = "\ -error csolution: invalid define: \\\"No_ending_escape_quotes, improper quotes\n\ -error csolution: invalid define: Escape_quotes_in_\\\"middle\\\", improper quotes\n\ -error csolution: invalid define: \\\"Invalid_ending\"\\, improper quotes\n\ -error csolution: invalid define: \\\"No_ending_escape_quotes, improper quotes\n\ -error csolution: invalid define: \\\"sam.h\\, improper quotes\n\ -error csolution: invalid define: \\\"Invalid_ending\"\\, improper quotes\n\ -error csolution: invalid define: No_Starting_escaped_quotes\\\", improper quotes\n\ -error csolution: invalid define: \\\"Mixed_quotes\", improper quotes\n\ -"; + expected = R"(error csolution: invalid define: \\\"No_ending_escape_quotes, improper quotes +error csolution: invalid define: Escape_quotes_in_\\\"middle\\\", improper quotes +error csolution: invalid define: \\\"Invalid_ending\"\\, improper quotes +error csolution: invalid define: \\\"No_ending_escape_quotes, improper quotes +error csolution: invalid define: \\\"sam.h\\, improper quotes +error csolution: invalid define: \\\"Invalid_ending\"\\, improper quotes +error csolution: invalid define: No_Starting_escaped_quotes\\\", improper quotes +error csolution: invalid define: \\\"Mixed_quotes\", improper quotes +)"; argv[5] = (char*)"-n"; EXPECT_EQ(1, RunProjMgr(6, argv, m_envp)); errStr = streamRedirect.GetErrorString(); - EXPECT_EQ(errStr, expected); + EXPECT_TRUE(regex_search(errStr, regex(expected))); } TEST_F(ProjMgrUnitTests, ComponentVersions) { @@ -7228,13 +7231,13 @@ TEST_F(ProjMgrUnitTests, ConvertActiveTargetSet) { argv[4] = (char*)"Type1@Unknown"; EXPECT_EQ(1, RunProjMgr(5, argv, 0)); auto errStr = streamRedirect.GetErrorString(); - EXPECT_STREQ(errStr.c_str(), "error csolution: 'Type1@Unknown' is not selectable as active target-set\n"); + EXPECT_TRUE(errStr.find("error csolution: 'Type1@Unknown' is not selectable as active target-set\n") != string::npos); streamRedirect.ClearStringStreams(); argv[4] = (char*)"TypeUnknown"; EXPECT_EQ(1, RunProjMgr(5, argv, 0)); errStr = streamRedirect.GetErrorString(); - EXPECT_STREQ(errStr.c_str(), "error csolution: 'TypeUnknown' is not selectable as active target-set\n"); + EXPECT_TRUE(errStr.find("error csolution: 'TypeUnknown' is not selectable as active target-set\n") != string::npos); streamRedirect.ClearStringStreams(); argv[4] = (char*)"Type1";