Skip to content

Commit 40b6564

Browse files
grasci-armedriouk
andauthored
Modify pack handling: reload only modified packs (#2375)
Co-authored-by: Evgueni Driouk <edriouk@arm.com>
1 parent 676c9ee commit 40b6564

File tree

8 files changed

+167
-17
lines changed

8 files changed

+167
-17
lines changed

libs/rtefsutils/include/RteFsUtils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,21 @@ class RteFsUtils
409409
* @return true if file is found successfully, false otherwise
410410
*/
411411
static bool FindFileWithPattern(const std::string& searchPath, const std::string& pattern, std::string& file);
412+
413+
/**
414+
* @brief returns file/dir modification time
415+
* @param path absolute file/directory path
416+
* @return fs::file_time_type
417+
*/
418+
static fs::file_time_type GetModificationTime(const std::string& path);
419+
420+
421+
/**
422+
* @brief converts time to string
423+
* @param timeStamp fs::file_time_type to convert
424+
* @return string representing time
425+
*/
426+
static std::string FileTimeToString(const fs::file_time_type& timeStamp);
412427
};
413428

414429
#endif // RteFsUtils_H

libs/rtefsutils/src/RteFsUtils.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,4 +906,37 @@ bool RteFsUtils::FindFileWithPattern(const std::string& searchDir,
906906
return false; // No matching file found
907907
}
908908

909+
fs::file_time_type RteFsUtils::GetModificationTime(const std::string& path) {
910+
911+
if(path.empty()) {
912+
return fs::file_time_type{}; // return default time
913+
}
914+
std::error_code ec;
915+
auto modificationTime = fs::last_write_time(path, ec);
916+
if(ec) {
917+
return fs::file_time_type{}; // return default time
918+
}
919+
return modificationTime;
920+
}
921+
922+
std::string RteFsUtils::FileTimeToString(const fs::file_time_type& timeStamp) {
923+
std::string strTime;
924+
if(timeStamp != fs::file_time_type{}) { // default value, return empty string
925+
// Convert file_time_type to system_clock (C++ 17 compatible version)
926+
auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
927+
timeStamp - fs::file_time_type::clock::now() + std::chrono::system_clock::now());
928+
std::time_t t = std::chrono::system_clock::to_time_t(sctp);
929+
std::tm tm{};
930+
#if defined(_WIN32)
931+
localtime_s(&tm, &t); // Windows secure version
932+
#else
933+
localtime_r(&t, &tm); // POSIX thread-safe version
934+
#endif
935+
std::ostringstream oss;
936+
oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
937+
strTime = oss.str();
938+
}
939+
return strTime;
940+
}
941+
909942
// End of RteFsUtils.cpp

libs/rtefsutils/test/src/RteFsUtilsTest.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,4 +1295,47 @@ TEST_F(RteFsUtilsTest, FindFileWithPattern_InvalidSearchPath) {
12951295
RteFsUtils::RemoveDir(testdir);
12961296
EXPECT_TRUE(discoveredFile.empty());
12971297
}
1298+
1299+
1300+
TEST_F(RteFsUtilsTest, GetModificationTime) {
1301+
1302+
EXPECT_EQ(fs::file_time_type{}, RteFsUtils::GetModificationTime(""));
1303+
1304+
auto filePath = dirnameBase + "/Test/TempTime.txt";
1305+
auto timeStamp0 = RteFsUtils::GetModificationTime(filePath);
1306+
EXPECT_EQ(fs::file_time_type{}, timeStamp0);
1307+
auto str0 = RteFsUtils::FileTimeToString(timeStamp0);
1308+
EXPECT_TRUE(str0.empty());
1309+
1310+
1311+
// create file
1312+
RteFsUtils::CreateTextFile(filePath, bufferFoo);
1313+
auto timeStamp1 = RteFsUtils::GetModificationTime(filePath);
1314+
EXPECT_NE(timeStamp0, timeStamp1);
1315+
auto str1 = RteFsUtils::FileTimeToString(timeStamp1);
1316+
EXPECT_FALSE(str1.empty());
1317+
1318+
auto timeStamp2 = RteFsUtils::GetModificationTime(filePath);
1319+
EXPECT_EQ(timeStamp1, timeStamp2);
1320+
auto str2 = RteFsUtils::FileTimeToString(timeStamp2);
1321+
EXPECT_EQ(str1, str2);
1322+
1323+
// modify file
1324+
RteFsUtils::CreateTextFile(filePath, bufferBar);
1325+
auto timeStamp3 = RteFsUtils::GetModificationTime(filePath);
1326+
EXPECT_TRUE(timeStamp3 >= timeStamp1); // some file systems have pure resolution
1327+
auto str3 = RteFsUtils::FileTimeToString(timeStamp3);
1328+
// string representation has resolution of 1 second, so we need some fuzzy compare
1329+
auto timeStamp31 = timeStamp3 + std::chrono::seconds(1);
1330+
auto str31 = RteFsUtils::FileTimeToString(timeStamp31);
1331+
EXPECT_TRUE(str3 != str1 || str3 != str31);
1332+
1333+
// delete file
1334+
RteFsUtils::DeleteFileAutoRetry(filePath);
1335+
auto timeStamp4 = RteFsUtils::GetModificationTime(filePath);
1336+
EXPECT_EQ(timeStamp0, timeStamp4);
1337+
auto str4 = RteFsUtils::FileTimeToString(timeStamp4);
1338+
EXPECT_EQ(str0, str4);
1339+
}
1340+
12981341
// end of RteFsUtilsTest.cpp

libs/rtemodel/include/RteItem.h

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "RteCallback.h"
1818

1919
#include "RteUtils.h"
20+
#include "RteFsUtils.h"
2021

2122
#include "XmlTreeItem.h"
2223

@@ -1014,25 +1015,54 @@ class RteRootItem : public RteItem
10141015
* @brief get absolute filename of the file for this root item
10151016
* @return filename this root element is read from
10161017
*/
1017-
const std::string& GetRootFileName() const override { return m_rootFileName; }
1018+
const std::string& GetRootFileName() const override { return m_rootFileName;}
10181019

10191020
/**
10201021
* @brief set filename associated with the root item this instance belongs to
10211022
* @param rootFileName absolute file name string
10221023
*/
1023-
void SetRootFileName(const std::string& rootFileName) override {
1024+
void SetRootFileName(const std::string& rootFileName) override {
10241025
m_rootFileName = rootFileName;
1026+
m_modificationTime = RteFsUtils::GetModificationTime(m_rootFileName);
1027+
}
1028+
1029+
/**
1030+
* @brief check if associated file time has been modified
1031+
* @return true if file has been modified and this item might represent outdated data
1032+
*/
1033+
bool IsFileTimeModified() const {
1034+
return GetModificationTime() != RteFsUtils::GetModificationTime(m_rootFileName);
1035+
}
1036+
1037+
/**
1038+
* @brief return stored modification time of associated file
1039+
* @return true if file has been modified and this item represents outdated data
1040+
*/
1041+
const fs::file_time_type& GetModificationTime() const { return m_modificationTime; }
1042+
1043+
/**
1044+
* @brief sets file modification time return stored modification time of associated file
1045+
* @param modificationTime time to set
1046+
* @return true if time is changed
1047+
*/
1048+
bool SetModificationTime(const fs::file_time_type& modificationTime) {
1049+
if(m_modificationTime != modificationTime) {
1050+
m_modificationTime = modificationTime;
1051+
return true;
1052+
}
1053+
return false;
10251054
}
10261055

10271056
/**
10281057
* @brief create a new instance of type RteItem
10291058
* @param tag name of tag
10301059
* @return pointer to instance of type RteItem
10311060
*/
1032-
RteItem* CreateItem(const std::string& tag) override;
1061+
RteItem* CreateItem(const std::string& tag) override;
10331062

10341063
protected:
10351064
std::string m_rootFileName; // absolute filename of this item's file
1065+
fs::file_time_type m_modificationTime;
10361066
};
10371067

10381068

libs/rtemodel/src/RteKernel.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ RtePackage* RteKernel::LoadPack(const string& pdscFile, PackageState packState)
297297
}
298298
RtePackRegistry* packRegistry = GetPackRegistry();
299299
RtePackage* pack = packRegistry->GetPack(pdscFile);
300-
if(pack) {
300+
if(pack && !pack->IsFileTimeModified()) {
301301
return pack;
302302
}
303303
const string ext = RteUtils::ExtractFileExtension(pdscFile, true);
@@ -334,9 +334,9 @@ bool RteKernel::LoadPacks(const std::list<std::string>& pdscFiles, std::list<Rte
334334
auto rteItemBuilder = CreateUniqueRteItemBuilder(model, model->GetPackageState());
335335
xmlTree->SetXmlItemBuilder(rteItemBuilder.get());
336336
RtePackage* pack = packRegistry->GetPack(pdscFile);
337-
if(bReplace) {
337+
if(bReplace || !pack || pack->IsFileTimeModified()) {
338338
packRegistry->ErasePack(pdscFile);
339-
} else if(pack) {
339+
} else {
340340
packs.push_back(pack);
341341
continue;
342342
}

libs/rtemodel/src/RtePackage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1500,7 +1500,7 @@ bool RtePackRegistry::AddPack(RtePackage* pack, bool bReplace)
15001500
auto& fileName = pack->GetPackageFileName();
15011501
auto existing = GetPack(fileName);
15021502
if(existing) {
1503-
if(bReplace) {
1503+
if(bReplace || (pack->GetModificationTime() > existing->GetModificationTime())) {
15041504
delete existing;
15051505
} else {
15061506
return false;

libs/rtemodel/test/src/RteModelTest.cpp

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
using namespace std;
2525

26-
TEST(RteModelTest, PackRegistry) {
26+
TEST_F(RteModelTestConfig, PackRegistry) {
2727

2828
// tests for pack registry
2929
RteKernelSlim rteKernel; // here just to instantiate XMLTree parser
@@ -52,11 +52,11 @@ TEST(RteModelTest, PackRegistry) {
5252

5353
}
5454

55-
TEST(RteModelTest, PackRegistryLoadPacks) {
55+
TEST_F(RteModelTestConfig, PackRegistryLoadPacks) {
5656

5757
// tests for pack registry
5858
RteKernelSlim rteKernel; // here just to instantiate XMLTree parser
59-
rteKernel.SetCmsisPackRoot(RteModelTestConfig::CMSIS_PACK_ROOT);
59+
rteKernel.SetCmsisPackRoot(packsDir);
6060

6161
RtePackRegistry* packRegistry = rteKernel.GetPackRegistry();
6262
ASSERT_TRUE(packRegistry != nullptr);
@@ -65,24 +65,29 @@ TEST(RteModelTest, PackRegistryLoadPacks) {
6565
list<string> files;
6666
rteKernel.GetEffectivePdscFiles(files, false);
6767
EXPECT_FALSE(files.empty());
68-
list<RtePackage*> packs;
68+
const string& firstFile = *files.begin();
69+
list<RtePackage*> packs, packs1;
6970
EXPECT_TRUE(rteKernel.LoadPacks(files, packs, &testModel));
7071
EXPECT_FALSE(packs.empty());
7172
EXPECT_EQ(packs.size(), files.size());
7273
EXPECT_EQ(packRegistry->GetLoadedPacks().size(), packs.size());
73-
// to check if packs are the same or reloaded, modify the first pack
74+
// no reload by default
75+
EXPECT_TRUE(rteKernel.LoadPacks(files, packs1, &testModel));
76+
EXPECT_EQ(packs, packs1); // no new packs loaded
77+
packs1.clear();
78+
79+
// to check if packs are the same or reloaded, modify the first pack
7480
ASSERT_NE(packs.begin(), packs.end());
7581
RtePackage* pack = *(packs.begin());
7682
ASSERT_TRUE(pack != nullptr);
7783
RteItem* dummyChild = new RteItem("dummy_child", pack);
7884
pack->AddItem(dummyChild);
7985
// no reload of the same files by default
80-
list<RtePackage*> packs1;
8186
EXPECT_TRUE(rteKernel.LoadPacks(files, packs1, &testModel));
8287
EXPECT_EQ(packs1.size(), files.size());
8388
EXPECT_EQ(packs, packs1); // no new packs loaded
8489
ASSERT_NE(packs1.begin(), packs1.end());
85-
auto pack1 = *packs1.begin();
90+
RtePackage* pack1 = *(packs1.begin());
8691
ASSERT_TRUE(pack1 != nullptr);
8792

8893
EXPECT_EQ(pack1->GetFirstChild("dummy_child"), dummyChild);
@@ -94,8 +99,6 @@ TEST(RteModelTest, PackRegistryLoadPacks) {
9499
EXPECT_EQ(pack1->GetFirstChild("dummy_child"), nullptr); // pack got loaded again => no added child
95100

96101
EXPECT_EQ(packRegistry->GetLoadedPacks().size(), files.size());
97-
ASSERT_NE(files.begin(), files.end());
98-
const string& firstFile = *files.begin();
99102
pack = packRegistry->GetPack(firstFile);
100103
ASSERT_TRUE(pack != nullptr);
101104
EXPECT_EQ(pack->GetPackageState(), PackageState::PS_INSTALLED);
@@ -104,8 +107,25 @@ TEST(RteModelTest, PackRegistryLoadPacks) {
104107
EXPECT_FALSE(packRegistry->ErasePack(firstFile)); // already not in collection
105108
packs.clear();
106109
EXPECT_TRUE(rteKernel.LoadPacks(files, packs, &testModel));
107-
EXPECT_EQ(packs.size(), packs1.size()); //only one pack is loaded
110+
EXPECT_EQ(packs.size(), packs1.size()); // the pack is reloaded()
108111
packs.clear();
112+
packs1.clear();
113+
114+
EXPECT_TRUE(rteKernel.LoadPacks(files, packs, &testModel));
115+
// modify a file time stamp reloading
116+
string buf;
117+
pack = *(packs.begin());
118+
dummyChild = new RteItem("dummy_child", pack);
119+
pack->AddItem(dummyChild);
120+
auto t = pack->GetModificationTime() - std::chrono::seconds(5);
121+
EXPECT_TRUE(pack->SetModificationTime(t));
122+
EXPECT_FALSE(pack->SetModificationTime(t)); // to check return value
123+
124+
EXPECT_TRUE(rteKernel.LoadPacks(files, packs1, &testModel));
125+
pack1 = *(packs1.begin());
126+
auto t1 = pack1->GetModificationTime();
127+
EXPECT_NE(t, t1);
128+
EXPECT_EQ(pack1->GetFirstChild("dummy_child"), nullptr); // pack got loaded again => no added child
109129
}
110130

111131
TEST(RteModelTest, LoadPacks) {

tools/projmgr/test/src/ProjMgrRpcTests.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,15 @@ TEST_F(ProjMgrRpcTests, RpcGetVersionWithContent) {
135135
EXPECT_TRUE(responses.find(CrossPlatformUtils::Crlf() + CrossPlatformUtils::Crlf() + "{") != string::npos);
136136
}
137137

138+
TEST_F(ProjMgrRpcTests, RpcLoadPacks) {
139+
auto requests = CreateLoadRequests("");
140+
requests += FormatRequest(1, "LoadPacks"); // load for the second time
141+
const auto& responses = RunRpcMethods(requests);
142+
EXPECT_TRUE(responses[0]["result"]["success"]);
143+
EXPECT_TRUE(responses[1]["result"]["success"]);
144+
}
145+
146+
138147
TEST_F(ProjMgrRpcTests, RpcLoadSolution) {
139148
const auto& requests = CreateLoadRequests("/TestRpc/minimal.csolution.yml", "TestHW");
140149
const auto& responses = RunRpcMethods(requests);

0 commit comments

Comments
 (0)