Skip to content

Commit 62be52f

Browse files
Adding symlink/hardlink for local dependency source
1 parent d78f206 commit 62be52f

File tree

15 files changed

+466
-22
lines changed

15 files changed

+466
-22
lines changed

DefaultYAMLs/DefaultScriptInfo.yaml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,14 @@ Dependencies:
155155
Local:
156156
# Path to the library directory
157157
Path: "./libs/LocalLibrary"
158-
158+
159+
# (Optional) How to handle copying files to build directory
160+
# Values:
161+
# - "Auto" (default): Try symlink first, then hardlink, then copy as fallback
162+
# - "Symlink": Create symbolic links only, fail if not possible
163+
# - "Hardlink": Create hard links only, fail if not possible
164+
# - "Copy": Copy files to build directory
165+
CopyMode: "Auto"
159166

160167
# Library Type (Static, Object, Shared, Header)
161168
LibraryType: Static

Examples/LocalDependency/NestedTestDirectory/localDep2.cpp

Whitespace-only changes.

Examples/LocalDependency/localDep.cpp

Whitespace-only changes.

Examples/testLocalDependency.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* runcpp2
2+
3+
Dependencies:
4+
- Name: LocalTest
5+
Platforms: [Windows, Linux, MacOS]
6+
Source:
7+
Local:
8+
Path: ./LocalDependency
9+
LibraryType: Header
10+
IncludePaths: []
11+
Build:
12+
Windows:
13+
DefaultProfile: ["dir", "dir .\\NestedTestDirectory"]
14+
Unix:
15+
DefaultProfile: ["ls -lah", "cd ./NestedTestDirectory && ls -lah"]
16+
*/
17+
18+
19+
#include <iostream>
20+
21+
int main(int argc, char* argv[])
22+
{
23+
return 0;
24+
}

Include/runcpp2/Data/LocalSource.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,20 @@ namespace runcpp2
88
{
99
namespace Data
1010
{
11+
enum class LocalCopyMode
12+
{
13+
Auto,
14+
Symlink,
15+
Hardlink,
16+
Copy,
17+
Count
18+
};
19+
1120
class LocalSource
1221
{
1322
public:
1423
std::string Path;
24+
LocalCopyMode CopyMode = LocalCopyMode::Auto;
1525

1626
bool ParseYAML_Node(ryml::ConstNodeRef& node);
1727
std::string ToString(std::string indentation) const;

Include/runcpp2/DependenciesHelper.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ namespace runcpp2
5151
bool ResolveImports(Data::ScriptInfo& scriptInfo,
5252
const ghc::filesystem::path& scriptPath,
5353
const ghc::filesystem::path& buildDir);
54+
55+
bool SyncLocalDependency( const Data::DependencyInfo& dependency,
56+
const ghc::filesystem::path& sourcePath,
57+
const ghc::filesystem::path& copyPath);
58+
59+
bool SyncLocalDependencies( const std::vector<Data::DependencyInfo*>& dependencies,
60+
const std::vector<std::string>& dependenciesSourcePaths,
61+
const std::vector<std::string>& dependenciesCopiesPaths);
5462
}
5563

5664
#endif

Jenkinsfile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,16 @@ pipeline
269269
"-c ../DefaultYAMLs/DefaultUserConfig.yaml " +
270270
"--log-level info ../Examples/test_static.cpp"
271271
bash "ls -lah ./Build"
272+
273+
274+
cleanWs()
275+
bash "ls -lah"
276+
unstash 'linux_build'
277+
bash "ls -lah"
278+
bash "ls -lah ./Build/Src/Tests"
279+
bash "cd ./Build && ./runcpp2 -l " +
280+
"-c ../DefaultYAMLs/DefaultUserConfig.yaml " +
281+
"--log-level info ../Examples/testLocalDependency.cpp"
272282
}
273283
post { failure { script { FAILED_STAGE = env.STAGE_NAME } } }
274284
}
@@ -314,6 +324,15 @@ pipeline
314324
"-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " +
315325
"--log-level info ..\\..\\Examples\\test_static.cpp"
316326
bat "dir .\\Build\\Debug"
327+
328+
329+
cleanWs()
330+
bat 'dir'
331+
unstash 'windows_build'
332+
bat 'dir'
333+
bat "cd .\\Build\\Debug && .\\runcpp2.exe -l " +
334+
"-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " +
335+
"--log-level info ..\\..\\Examples\\testLocalDependency.cpp"
317336
}
318337
post { failure { script { FAILED_STAGE = env.STAGE_NAME } } }
319338
}

Src/Tests/Data/DependencySourceTest.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ int main(int argc, char** argv)
8383
mpark::get_if<runcpp2::Data::LocalSource>(&dependencySource.Source);
8484
ssTEST_OUTPUT_ASSERT("Should be Local source", local != nullptr);
8585
ssTEST_OUTPUT_ASSERT("Path", local->Path == "../external/mylib");
86+
ssTEST_OUTPUT_ASSERT( "Default CopyMode",
87+
local->CopyMode == runcpp2::Data::LocalCopyMode::Auto);
8688

8789
//Test ToString() and Equals()
8890
ssTEST_OUTPUT_EXECUTION
@@ -99,6 +101,92 @@ int main(int argc, char** argv)
99101
dependencySource.Equals(parsedOutput));
100102
};
101103

104+
ssTEST("DependencySource Should Parse Local Source With CopyMode")
105+
{
106+
const std::vector<std::pair<std::string,
107+
runcpp2::Data::LocalCopyMode>> testCases =
108+
{
109+
{"Auto", runcpp2::Data::LocalCopyMode::Auto},
110+
{"Symlink", runcpp2::Data::LocalCopyMode::Symlink},
111+
{"Hardlink", runcpp2::Data::LocalCopyMode::Hardlink},
112+
{"Copy", runcpp2::Data::LocalCopyMode::Copy}
113+
};
114+
115+
for(const std::pair<std::string,
116+
runcpp2::Data::LocalCopyMode>& testCase : testCases)
117+
{
118+
ssTEST_OUTPUT("Test Copy Mode: " << testCase.first);
119+
ssTEST_OUTPUT_SETUP
120+
(
121+
std::string yamlStr = R"(
122+
Local:
123+
Path: ../external/mylib
124+
CopyMode: )" + testCase.first;
125+
126+
ryml::Tree tree = ryml::parse_in_arena(c4::to_csubstr(yamlStr));
127+
ryml::ConstNodeRef root = tree.rootref();
128+
runcpp2::Data::DependencySource dependencySource;
129+
);
130+
131+
ssTEST_OUTPUT_EXECUTION
132+
(
133+
ryml::ConstNodeRef nodeRef = root;
134+
bool parseResult = dependencySource.ParseYAML_Node(nodeRef);
135+
);
136+
137+
ssTEST_OUTPUT_ASSERT("ParseYAML_Node should succeed", parseResult);
138+
139+
const runcpp2::Data::LocalSource* local =
140+
mpark::get_if<runcpp2::Data::LocalSource>(&dependencySource.Source);
141+
ssTEST_OUTPUT_ASSERT("Should be Local source", local != nullptr);
142+
143+
if(!local)
144+
return;
145+
146+
ssTEST_OUTPUT_ASSERT("Path", local->Path, "../external/mylib");
147+
ssTEST_OUTPUT_ASSERT("CopyMode", local->CopyMode == testCase.second);
148+
149+
//Test ToString() and Equals()
150+
ssTEST_OUTPUT_EXECUTION
151+
(
152+
std::string yamlOutput = dependencySource.ToString("");
153+
ryml::Tree outputTree = ryml::parse_in_arena(ryml::to_csubstr(yamlOutput));
154+
155+
runcpp2::Data::DependencySource parsedOutput;
156+
nodeRef = outputTree.rootref();
157+
parsedOutput.ParseYAML_Node(nodeRef);
158+
);
159+
160+
ssTEST_OUTPUT_ASSERT( "Parsed output should equal original",
161+
dependencySource.Equals(parsedOutput));
162+
}
163+
};
164+
165+
ssTEST("DependencySource Should Handle Invalid CopyMode")
166+
{
167+
ssTEST_OUTPUT_SETUP
168+
(
169+
const char* yamlStr = R"(
170+
Local:
171+
Path: ../external/mylib
172+
CopyMode: InvalidMode
173+
)";
174+
175+
ryml::Tree tree = ryml::parse_in_arena(c4::to_csubstr(yamlStr));
176+
ryml::ConstNodeRef root = tree.rootref();
177+
178+
runcpp2::Data::DependencySource dependencySource;
179+
);
180+
181+
ssTEST_OUTPUT_EXECUTION
182+
(
183+
ryml::ConstNodeRef nodeRef = root;
184+
bool parseResult = dependencySource.ParseYAML_Node(nodeRef);
185+
);
186+
187+
ssTEST_OUTPUT_ASSERT("ParseYAML_Node should fail", !parseResult);
188+
};
189+
102190
ssTEST_END_TEST_GROUP();
103191
return 0;
104192
}

Src/runcpp2/Data/LocalSource.cpp

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,62 @@
22
#include "runcpp2/Data/ParseCommon.hpp"
33
#include "runcpp2/ParseUtil.hpp"
44
#include "ssLogger/ssLog.hpp"
5+
#include <optional>
6+
7+
namespace
8+
{
9+
static_assert( static_cast<int>(runcpp2::Data::LocalCopyMode::Count) == 4,
10+
"Update CopyModeToString when adding new LocalCopyMode values");
11+
12+
std::string CopyModeToString(runcpp2::Data::LocalCopyMode mode)
13+
{
14+
switch(mode)
15+
{
16+
case runcpp2::Data::LocalCopyMode::Auto:
17+
return "Auto";
18+
case runcpp2::Data::LocalCopyMode::Symlink:
19+
return "Symlink";
20+
case runcpp2::Data::LocalCopyMode::Hardlink:
21+
return "Hardlink";
22+
case runcpp2::Data::LocalCopyMode::Copy:
23+
return "Copy";
24+
default:
25+
ssLOG_ERROR("Unknown LocalCopyMode value");
26+
return "Auto";
27+
}
28+
}
29+
30+
static_assert( static_cast<int>(runcpp2::Data::LocalCopyMode::Count) == 4,
31+
"Update StringToCopyMode when adding new LocalCopyMode values");
32+
33+
runcpp2::Data::LocalCopyMode StringToCopyMode(const std::string& str, bool& outSuccess)
34+
{
35+
if(str == "Auto")
36+
{
37+
outSuccess = true;
38+
return runcpp2::Data::LocalCopyMode::Auto;
39+
}
40+
else if(str == "Symlink")
41+
{
42+
outSuccess = true;
43+
return runcpp2::Data::LocalCopyMode::Symlink;
44+
}
45+
else if(str == "Hardlink")
46+
{
47+
outSuccess = true;
48+
return runcpp2::Data::LocalCopyMode::Hardlink;
49+
}
50+
else if(str == "Copy")
51+
{
52+
outSuccess = true;
53+
return runcpp2::Data::LocalCopyMode::Copy;
54+
}
55+
56+
ssLOG_ERROR("Invalid LocalCopyMode value: " << str);
57+
outSuccess = false;
58+
return runcpp2::Data::LocalCopyMode::Auto;
59+
}
60+
}
561

662
bool runcpp2::Data::LocalSource::ParseYAML_Node(ryml::ConstNodeRef& node)
763
{
@@ -19,6 +75,17 @@ bool runcpp2::Data::LocalSource::ParseYAML_Node(ryml::ConstNodeRef& node)
1975
}
2076

2177
node["Path"] >> Path;
78+
79+
if(ExistAndHasChild(node, "CopyMode"))
80+
{
81+
std::string modeStr;
82+
node["CopyMode"] >> modeStr;
83+
bool success = false;
84+
CopyMode = StringToCopyMode(modeStr, success);
85+
if (!success)
86+
return false;
87+
}
88+
2289
return true;
2390

2491
INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(false);
@@ -29,10 +96,11 @@ std::string runcpp2::Data::LocalSource::ToString(std::string indentation) const
2996
std::string out;
3097
out += indentation + "Local:\n";
3198
out += indentation + " Path: " + GetEscapedYAMLString(Path) + "\n";
99+
out += indentation + " CopyMode: " + CopyModeToString(CopyMode) + "\n";
32100
return out;
33101
}
34102

35103
bool runcpp2::Data::LocalSource::Equals(const LocalSource& other) const
36104
{
37-
return Path == other.Path;
38-
}
105+
return Path == other.Path && CopyMode == other.CopyMode;
106+
}

0 commit comments

Comments
 (0)