Skip to content

Commit b8312c0

Browse files
Tracking Include Files
1 parent a122b52 commit b8312c0

File tree

11 files changed

+474
-91
lines changed

11 files changed

+474
-91
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ add_library(runcpp2 STATIC
145145
"${CMAKE_CURRENT_LIST_DIR}/Src/runcpp2/runcpp2.cpp"
146146
"${CMAKE_CURRENT_LIST_DIR}/Src/runcpp2/BuildsManager.cpp"
147147
"${CMAKE_CURRENT_LIST_DIR}/Src/runcpp2/PipelineSteps.cpp"
148+
"${CMAKE_CURRENT_LIST_DIR}/Src/runcpp2/IncludeManager.cpp"
148149
)
149150

150151
target_include_directories(runcpp2 PUBLIC "${CMAKE_CURRENT_LIST_DIR}/Include")

Include/runcpp2/IncludeManager.hpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#ifndef RUNCPP2_INCLUDE_MANAGER_HPP
2+
#define RUNCPP2_INCLUDE_MANAGER_HPP
3+
4+
#include "ghc/filesystem.hpp"
5+
#include <unordered_map>
6+
#include <vector>
7+
8+
namespace runcpp2
9+
{
10+
class IncludeManager
11+
{
12+
public:
13+
IncludeManager() = default;
14+
~IncludeManager() = default;
15+
16+
bool Initialize(const ghc::filesystem::path& buildDir);
17+
18+
bool WriteIncludeRecord(const ghc::filesystem::path& sourceFile,
19+
const std::vector<ghc::filesystem::path>& includes);
20+
21+
bool ReadIncludeRecord( const ghc::filesystem::path& sourceFile,
22+
std::vector<ghc::filesystem::path>& outIncludes,
23+
ghc::filesystem::file_time_type& outRecordTime);
24+
25+
bool NeedsUpdate( const ghc::filesystem::path& sourceFile,
26+
const std::vector<ghc::filesystem::path>& includes,
27+
const ghc::filesystem::file_time_type& recordTime) const;
28+
29+
private:
30+
ghc::filesystem::path GetRecordPath(const ghc::filesystem::path& sourceFile) const;
31+
32+
ghc::filesystem::path IncludeRecordDir;
33+
};
34+
}
35+
36+
#endif

Include/runcpp2/ParseUtil.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ namespace runcpp2
3636
std::string GetValue(ryml::ConstNodeRef node);
3737
std::string GetKey(ryml::ConstNodeRef node);
3838
std::string GetEscapedYAMLString(const std::string& input);
39+
40+
bool ParseIncludes(const std::string& line, std::string& outIncludePath);
3941
}
4042

4143
#endif

Include/runcpp2/PipelineSteps.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
#include "runcpp2/Data/CmdOptions.hpp"
99

1010
#include "runcpp2/BuildsManager.hpp"
11+
#include "runcpp2/IncludeManager.hpp"
1112

1213
#include "ghc/filesystem.hpp"
1314

1415
#include <string>
1516
#include <vector>
17+
#include <unordered_map>
1618

1719
namespace runcpp2
1820
{
@@ -50,7 +52,8 @@ namespace runcpp2
5052
const ghc::filesystem::path& absoluteScriptPath,
5153
bool useLocalBuildDir,
5254
BuildsManager& outBuildsManager,
53-
ghc::filesystem::path& outBuildDir);
55+
ghc::filesystem::path& outBuildDir,
56+
IncludeManager& outIncludeManager);
5457

5558
PipelineResult CheckScriptInfoChanges( const ghc::filesystem::path& buildDir,
5659
const Data::ScriptInfo& scriptInfo,
@@ -116,6 +119,12 @@ namespace runcpp2
116119
const Data::Profile& currentProfile,
117120
const std::vector<Data::DependencyInfo*>& dependencies,
118121
std::vector<ghc::filesystem::path>& outIncludePaths);
122+
123+
using SourceIncludeMap = std::unordered_map<std::string, std::vector<ghc::filesystem::path>>;
124+
125+
bool GatherFilesIncludes( const std::vector<ghc::filesystem::path>& files,
126+
const std::vector<ghc::filesystem::path>& includePaths,
127+
SourceIncludeMap& outSourceIncludes);
119128
}
120129

121130

Include/runcpp2/runcpp2.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ namespace runcpp2
2525

2626
void SetLogLevel(const std::string& logLevel);
2727

28-
PipelineResult GetLatestSourceWriteTime(const std::string& scriptPath,
28+
PipelineResult CheckSourcesNeedUpdate( const std::string& scriptPath,
2929
const std::vector<Data::Profile>& profiles,
3030
const std::string& configPreferredProfile,
3131
const Data::ScriptInfo& scriptInfo,
32-
int64_t& outWriteTime);
32+
const std::unordered_map<CmdOptions, std::string>& currentOptions,
33+
bool& outNeedsUpdate);
3334

3435
PipelineResult StartPipeline( const std::string& scriptPath,
3536
const std::vector<Data::Profile>& profiles,

Src/runcpp2/IncludeManager.cpp

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#include "runcpp2/IncludeManager.hpp"
2+
#include "runcpp2/Data/ParseCommon.hpp"
3+
#include "ssLogger/ssLog.hpp"
4+
5+
#include <fstream>
6+
7+
namespace runcpp2
8+
{
9+
bool IncludeManager::Initialize(const ghc::filesystem::path& buildDir)
10+
{
11+
INTERNAL_RUNCPP2_SAFE_START();
12+
ssLOG_FUNC_DEBUG();
13+
14+
IncludeRecordDir = buildDir / "IncludeMaps";
15+
16+
std::error_code e;
17+
if(!ghc::filesystem::exists(IncludeRecordDir, e))
18+
{
19+
if(!ghc::filesystem::create_directories(IncludeRecordDir, e))
20+
{
21+
ssLOG_ERROR("Failed to create IncludeMaps directory: " << IncludeRecordDir);
22+
return false;
23+
}
24+
}
25+
26+
return true;
27+
INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(false);
28+
}
29+
30+
bool IncludeManager::WriteIncludeRecord(const ghc::filesystem::path& sourceFile,
31+
const std::vector<ghc::filesystem::path>& includes)
32+
{
33+
INTERNAL_RUNCPP2_SAFE_START();
34+
ssLOG_FUNC_DEBUG();
35+
36+
if(!sourceFile.is_absolute())
37+
{
38+
ssLOG_ERROR("Source file is not absolute: " << sourceFile);
39+
return false;
40+
}
41+
42+
ghc::filesystem::path recordPath = GetRecordPath(sourceFile);
43+
44+
std::ofstream recordFile(recordPath);
45+
if(!recordFile.is_open())
46+
{
47+
ssLOG_ERROR("Failed to open include record file: " << recordPath);
48+
return false;
49+
}
50+
51+
for(const ghc::filesystem::path& include : includes)
52+
recordFile << include.string() << "\n";
53+
54+
return true;
55+
INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(false);
56+
}
57+
58+
bool IncludeManager::ReadIncludeRecord( const ghc::filesystem::path& sourceFile,
59+
std::vector<ghc::filesystem::path>& outIncludes,
60+
ghc::filesystem::file_time_type& outRecordTime)
61+
{
62+
INTERNAL_RUNCPP2_SAFE_START();
63+
ssLOG_FUNC_DEBUG();
64+
65+
if(!sourceFile.is_absolute())
66+
{
67+
ssLOG_ERROR("Source file is not absolute: " << sourceFile);
68+
return false;
69+
}
70+
71+
outIncludes.clear();
72+
ghc::filesystem::path recordPath = GetRecordPath(sourceFile);
73+
74+
std::error_code e;
75+
if(!ghc::filesystem::exists(recordPath, e))
76+
return false;
77+
78+
outRecordTime = ghc::filesystem::last_write_time(recordPath, e);
79+
80+
std::ifstream recordFile(recordPath);
81+
if(!recordFile.is_open())
82+
{
83+
ssLOG_ERROR("Failed to open include record file: " << recordPath);
84+
return false;
85+
}
86+
87+
std::string line;
88+
while(std::getline(recordFile, line))
89+
{
90+
if(!line.empty())
91+
outIncludes.push_back(ghc::filesystem::path(line));
92+
}
93+
94+
return true;
95+
INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(false);
96+
}
97+
98+
bool IncludeManager::NeedsUpdate( const ghc::filesystem::path& sourceFile,
99+
const std::vector<ghc::filesystem::path>& includes,
100+
const ghc::filesystem::file_time_type& recordTime) const
101+
{
102+
INTERNAL_RUNCPP2_SAFE_START();
103+
ssLOG_FUNC_DEBUG();
104+
105+
std::error_code e;
106+
ghc::filesystem::file_time_type sourceTime = ghc::filesystem::last_write_time(sourceFile, e);
107+
108+
if(sourceTime > recordTime)
109+
return true;
110+
111+
for(const ghc::filesystem::path& include : includes)
112+
{
113+
if(ghc::filesystem::exists(include, e))
114+
{
115+
ghc::filesystem::file_time_type includeTime =
116+
ghc::filesystem::last_write_time(include, e);
117+
if(includeTime > recordTime)
118+
return true;
119+
}
120+
}
121+
122+
return false;
123+
INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(true);
124+
}
125+
126+
ghc::filesystem::path IncludeManager::GetRecordPath(const ghc::filesystem::path& sourceFile) const
127+
{
128+
std::size_t pathHash = std::hash<std::string>{}(sourceFile.string());
129+
return IncludeRecordDir / (std::to_string(pathHash) + ".Includes");
130+
}
131+
}

Src/runcpp2/ParseUtil.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,29 @@ std::string runcpp2::GetEscapedYAMLString(const std::string& input)
358358
output += "\"";
359359
return output;
360360
}
361+
362+
bool runcpp2::ParseIncludes(const std::string& line, std::string& outIncludePath)
363+
{
364+
//Skip if not an include line
365+
if(line.find("#include") == std::string::npos)
366+
return false;
367+
368+
size_t firstQuote = line.find('\"');
369+
size_t firstBracket = line.find('<');
370+
371+
//Skip if no valid include format found
372+
if(firstQuote == std::string::npos && firstBracket == std::string::npos)
373+
return false;
374+
375+
bool isQuoted = firstQuote != std::string::npos &&
376+
(firstBracket == std::string::npos || firstQuote < firstBracket);
377+
378+
size_t start = isQuoted ? firstQuote + 1 : firstBracket + 1;
379+
size_t end = line.find(isQuoted ? '\"' : '>', start);
380+
381+
if(end == std::string::npos)
382+
return false;
383+
384+
outIncludePath = line.substr(start, end - start);
385+
return true;
386+
}

Src/runcpp2/PipelineSteps.cpp

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include "ghc/filesystem.hpp"
1212
#include "dylib.hpp"
1313

14+
#include <queue>
15+
1416
namespace
1517
{
1618
bool RunCompiledScript( const ghc::filesystem::path& executable,
@@ -412,7 +414,8 @@ runcpp2::InitializeBuildDirectory( const ghc::filesystem::path& configDir,
412414
const ghc::filesystem::path& absoluteScriptPath,
413415
bool useLocalBuildDir,
414416
BuildsManager& outBuildsManager,
415-
ghc::filesystem::path& outBuildDir)
417+
ghc::filesystem::path& outBuildDir,
418+
IncludeManager& outIncludeManager)
416419
{
417420
//Create build directory
418421
ghc::filesystem::path buildDirPath = useLocalBuildDir ?
@@ -447,6 +450,13 @@ runcpp2::InitializeBuildDirectory( const ghc::filesystem::path& configDir,
447450
return PipelineResult::INVALID_BUILD_DIR;
448451
}
449452

453+
outIncludeManager = IncludeManager();
454+
if(!outIncludeManager.Initialize(outBuildDir))
455+
{
456+
ssLOG_FATAL("Failed to initialize include manager");
457+
return PipelineResult::INVALID_BUILD_DIR;
458+
}
459+
450460
return PipelineResult::SUCCESS;
451461
}
452462

@@ -1068,3 +1078,83 @@ bool runcpp2::GatherIncludePaths( const ghc::filesystem::path& scriptDirectory
10681078

10691079
return true;
10701080
}
1081+
1082+
bool runcpp2::GatherFilesIncludes( const std::vector<ghc::filesystem::path>& files,
1083+
const std::vector<ghc::filesystem::path>& includePaths,
1084+
SourceIncludeMap& outSourceIncludes)
1085+
{
1086+
INTERNAL_RUNCPP2_SAFE_START();
1087+
ssLOG_FUNC_DEBUG();
1088+
1089+
outSourceIncludes.clear();
1090+
std::unordered_set<std::string> visitedFiles;
1091+
1092+
for(const ghc::filesystem::path& file : files)
1093+
{
1094+
std::vector<ghc::filesystem::path>& currentIncludes = outSourceIncludes[file.string()];
1095+
std::queue<ghc::filesystem::path> filesToProcess;
1096+
filesToProcess.push(file);
1097+
1098+
while(!filesToProcess.empty())
1099+
{
1100+
ghc::filesystem::path currentFile = filesToProcess.front();
1101+
filesToProcess.pop();
1102+
1103+
if(visitedFiles.count(currentFile.string()) > 0)
1104+
continue;
1105+
1106+
visitedFiles.insert(currentFile.string());
1107+
1108+
std::ifstream fileStream(currentFile);
1109+
if(!fileStream.is_open())
1110+
{
1111+
ssLOG_ERROR("Failed to open file: " << currentFile);
1112+
return false;
1113+
}
1114+
1115+
std::string line;
1116+
while(std::getline(fileStream, line))
1117+
{
1118+
std::string includePath;
1119+
if(!ParseIncludes(line, includePath))
1120+
continue;
1121+
1122+
ghc::filesystem::path resolvedInclude;
1123+
bool found = false;
1124+
1125+
//For quoted includes, first check relative to source file
1126+
if(line.find('\"') != std::string::npos)
1127+
{
1128+
resolvedInclude = currentFile.parent_path() / includePath;
1129+
std::error_code ec;
1130+
if(ghc::filesystem::exists(resolvedInclude, ec))
1131+
found = true;
1132+
}
1133+
1134+
//Search in include paths if not found
1135+
if(!found)
1136+
{
1137+
for(const ghc::filesystem::path& searchPath : includePaths)
1138+
{
1139+
resolvedInclude = searchPath / includePath;
1140+
std::error_code ec;
1141+
if(ghc::filesystem::exists(resolvedInclude, ec))
1142+
{
1143+
found = true;
1144+
break;
1145+
}
1146+
}
1147+
}
1148+
1149+
if(found)
1150+
{
1151+
currentIncludes.push_back(resolvedInclude);
1152+
filesToProcess.push(resolvedInclude);
1153+
}
1154+
}
1155+
}
1156+
}
1157+
1158+
return true;
1159+
INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(false);
1160+
}

0 commit comments

Comments
 (0)