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
7 changes: 7 additions & 0 deletions libs/rtemodel/include/RteModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,13 @@ class RteGlobalModel : public RteModel
*/
void ClearModel() override;

/**
* @brief purges non-existing packs and optionally explicit packs; clears model and projects if at least one pack was removed
* @param purgeExplicit when true, remove all PackageState::PS_EXPLICIT_PATH packs
* @returns true if at least one pack has been removed
*/
bool PurgeModel(bool purgeExplicit);

/**
* @brief setter for RteCallback object
* @param callback given RteCallback object to set
Expand Down
5 changes: 3 additions & 2 deletions libs/rtemodel/include/RtePackage.h
Original file line number Diff line number Diff line change
Expand Up @@ -1336,10 +1336,11 @@ class RtePackRegistry
bool ErasePack(const std::string& pdscFile);

/**
* @brief removes all non-existing packs
* @brief removes all non-existing packs and optionally explicitly specified packs
* @param purgeExplicit flag to remove all PackageState::PS_EXPLICIT_PATH packs
* @return true if at least one pack was removed
*/
bool PurgePacks();
bool PurgePacks(bool purgeExplicit);

/**
* @brief get collection of loaded packs
Expand Down
8 changes: 1 addition & 7 deletions libs/rtemodel/src/RteKernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,6 @@ bool RteKernel::GetEffectivePdscFilesAsMap(map<string, string, RtePackageCompara

bool RteKernel::GetEffectivePdscFiles(std::list<std::string>& pdscFiles, bool latest) const
{
GetPackRegistry()->PurgePacks(); // remove non-existing files from the registry

map<string, string, RtePackageComparator> pdscMap;
if(!GetEffectivePdscFilesAsMap(pdscMap, latest)) {
return false;
Expand All @@ -477,11 +475,7 @@ bool RteKernel::LoadAndInsertPacks(std::list<RtePackage*>& packs, std::list<std:
if(!pack) {
return false;
}
// pack with explicit path must override installed pack
auto loadedPack = RtePackage::GetPackFromList(pack->GetID(), packs);
if(!loadedPack || (loadedPack->GetPackageState() == PS_INSTALLED && pack->GetPackageState() == PS_EXPLICIT_PATH)) {
newPacks.push_back(pack);
}
newPacks.push_back(pack);
}
globalModel->InsertPacks(newPacks);

Expand Down
21 changes: 10 additions & 11 deletions libs/rtemodel/src/RteModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,17 +392,9 @@ void RteModel::InsertPack(RtePackage* package)
}
auto state = package->GetPackageState();
if(insertedPack->GetPackageState() == state) {
string pdscPath = RteFsUtils::MakePathCanonical(package->GetAbsolutePackagePath());
if(pdscPath.find(m_rtePath) == 0) { // regular installed pack => error
// duplicate, kept it in a temporary collection till validate;
m_packageDuplicates.push_back(package);
return;
}
string insertedPdscPath = RteFsUtils::MakePathCanonical(insertedPack->GetAbsolutePackagePath());
if(insertedPdscPath.find(m_rtePath) == string::npos) { // inserted pack is also from outside => error
m_packageDuplicates.push_back(package);
return;
}
m_packageDuplicates.push_back(package);
return;
} else if(state != PS_EXPLICIT_PATH) {
return; // pack with explicit path must override installed pack
}
Expand Down Expand Up @@ -842,7 +834,14 @@ void RteGlobalModel::ClearModel()
{
ClearProjectTargets();
RteModel::ClearModel();
m_packRegistry->PurgePacks(); // pack loading is expensive, only remove deleted
}

bool RteGlobalModel::PurgeModel(bool purgeExplicit) {
if(m_packRegistry->PurgePacks(purgeExplicit)) {
Clear();
return true;
}
return false;
}


Expand Down
4 changes: 2 additions & 2 deletions libs/rtemodel/src/RtePackage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1525,13 +1525,13 @@ bool RtePackRegistry::ErasePack(const std::string& pdscFile)
return false;
}

bool RtePackRegistry::PurgePacks() {
bool RtePackRegistry::PurgePacks(bool purgeExplicit) {
ClearPdscMap(); // clear because packs can be added or removed after this call

set<string> toErase;
// collect packs that no longer exist
for(auto& [pdscFile, pack] : m_loadedPacks) {
if(!pack || !pack->Exists()) {
if(!pack || !pack->Exists() || (purgeExplicit && pack->GetPackageState() == PackageState::PS_EXPLICIT_PATH )) {
toErase.insert(pdscFile);
}
}
Expand Down
11 changes: 9 additions & 2 deletions libs/rtemodel/test/src/RteModelTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ TEST_F(RteModelTestConfig, PackRegistry) {
EXPECT_TRUE(packRegistry->AddPack(pack));
EXPECT_FALSE(packRegistry->AddPack(pack)); // not second time
EXPECT_EQ(packRegistry->GetPack("foo"), pack);
pack = new RtePackage(&testModel);
pack = new RtePackage(&testModel, PackageState::PS_EXPLICIT_PATH);
pack->SetAttribute("name", "bar");
pack->SetRootFileName("foo");
EXPECT_TRUE(packRegistry->AddPack(pack, true));
EXPECT_EQ(packRegistry->GetPack("foo"), pack);
EXPECT_EQ(packRegistry->GetLoadedPacks().size(), 1);

EXPECT_TRUE(packRegistry->PurgePacks());
EXPECT_TRUE(packRegistry->PurgePacks(false)); // deleted because not exists
EXPECT_EQ(packRegistry->GetPack("foo"), nullptr);
EXPECT_FALSE(packRegistry->ErasePack("foo")); // already erased via Purge
EXPECT_EQ(packRegistry->GetLoadedPacks().size(), 0);
Expand Down Expand Up @@ -128,6 +128,13 @@ TEST_F(RteModelTestConfig, PackRegistryLoadPacks) {
auto t1 = pack1->GetModificationTime();
EXPECT_NE(t, t1);
EXPECT_EQ(pack1->GetFirstChild("dummy_child"), nullptr); // pack got loaded again => no added child

// test RteGlobalModel::PurgeModel
pack1->SetPackageState(PackageState::PS_EXPLICIT_PATH); // simulate pack is explicit
auto globalModel = rteKernel.GetGlobalModel();

EXPECT_FALSE(globalModel->PurgeModel(false));
EXPECT_TRUE(globalModel->PurgeModel(true));
}

TEST(RteModelTest, LoadPacks) {
Expand Down
35 changes: 30 additions & 5 deletions tools/projmgr/src/ProjMgrRpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,10 @@ RpcArgs::SuccessResult RpcHandler::LoadPacks(void) {
m_manager.Clear();
m_solutionLoaded = false;
// clear project and global RTE data, packs stay loaded
ProjMgrKernel::Get()->GetGlobalModel()->Clear();
auto globalModel = ProjMgrKernel::Get()->GetGlobalModel();
globalModel->Clear();
globalModel->PurgeModel(true); // clears also explicit and non-existing packs

m_worker.InitializeModel();
m_worker.SetLoadPacksPolicy(LoadPacksPolicy::ALL);
result.success = m_worker.LoadAllRelevantPacks();
Expand All @@ -319,15 +322,30 @@ RpcArgs::SuccessResult RpcHandler::LoadPacks(void) {
RpcArgs::SuccessResult RpcHandler::LoadSolution(const string& solution, const string& activeTarget) {
m_bUseAllPacks = false; // loading solution will first use only listed packs
m_packReferences.clear(); // will be updated
m_manager.Clear();
m_solutionLoaded = false; // assume not loaded yet
// clear only projects, global RTE data and packs stay loaded
ProjMgrKernel::Get()->GetGlobalModel()->ClearProjects();
auto globalModel = ProjMgrKernel::Get()->GetGlobalModel();
// remove non-existing and explicit packs
// clear model and projects if at least one pack is deleted
bool purged = globalModel->PurgeModel(true);
if(!purged) {
// only projects, global RTE data and packs stay loaded
globalModel->ClearProjects();
Comment thread
Copilot marked this conversation as resolved.
}

RpcArgs::SuccessResult result = {false};
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(purged) {
// we need to add available packs to model again (the packs are already loaded)
m_worker.InitializeModel();
m_worker.SetLoadPacksPolicy(LoadPacksPolicy::ALL);
result.success = m_worker.LoadAllRelevantPacks();
m_worker.SetLoadPacksPolicy(LoadPacksPolicy::DEFAULT);
}
// we disregard return value of m_manager.LoadSolution() here, because we tolerate some errors
m_manager.LoadSolution(csolutionFile, activeTarget);
map<string, ContextItem>* contexts = nullptr;
Expand Down Expand Up @@ -870,8 +888,15 @@ RpcArgs::ConvertSolutionResult RpcHandler::ConvertSolution(const string& solutio
m_bUseAllPacks = false; // loading solution will first use only listed packs
m_packReferences.clear(); // will be updated
m_solutionLoaded = false; // assume not loaded
// clear only projects, RTE data and packs stay loaded
ProjMgrKernel::Get()->GetGlobalModel()->ClearProjects();
m_manager.Clear();
auto globalModel = ProjMgrKernel::Get()->GetGlobalModel();
// remove non-existing and explicit packs
// clear model and projects if at least one pack is deleted
bool purged = globalModel->PurgeModel(true);
if(!purged) {
// only projects, global RTE data and packs stay loaded
globalModel->ClearProjects();
Comment thread
Copilot marked this conversation as resolved.
}

if(!m_manager.RunConvert(csolutionFile, activeTarget, updateRte) || !ProjMgrLogger::Get().GetErrors().empty()) {
if(m_worker.HasVarDefineError()) {
Expand Down
13 changes: 13 additions & 0 deletions tools/projmgr/test/data/TestSolution/pack_path1.csolution.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json

solution:
target-types:
- type: CM0
device: RteTest_ARMCM0

packs:
- pack: ARM::RteTest_DFP
path: ../SolutionSpecificPack1

projects:
- project: pack_path.cproject.yml
Loading
Loading