Skip to content

Commit ef1fd3b

Browse files
committed
feat: added format to codegen
1 parent 06dcbd9 commit ef1fd3b

File tree

2 files changed

+102
-3
lines changed

2 files changed

+102
-3
lines changed

Tools/EcsactUnrealCodegen/BUILD.bazel

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ load("@rules_cc//cc:defs.bzl", "cc_binary")
44
cc_binary(
55
name = "EcsactUnrealCodegen",
66
srcs = ["EcsactUnrealCodegen.cpp"],
7-
copts = ["-std=c++20"],
7+
copts = [
8+
"-std=c++20",
9+
"-fexperimental-library",
10+
],
811
linkopts = select({
912
"//conditions:default": [],
1013
"@platforms//os:windows": [

Tools/EcsactUnrealCodegen/EcsactUnrealCodegen.cpp

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
#include <iostream>
22
#include <filesystem>
3+
#ifdef __cpp_lib_execution
4+
# include <execution>
5+
#endif
36
#include <boost/process.hpp>
47
#include <boost/program_options.hpp>
58

9+
using namespace std::string_literals;
610
namespace fs = std::filesystem;
711
namespace bp = boost::process;
812
namespace po = boost::program_options;
@@ -70,6 +74,32 @@ auto proc_stdout(auto&&... args) -> std::optional<std::string> {
7074
return std::nullopt;
7175
}
7276

77+
auto proc_stdout_list(auto&&... args) -> std::vector<std::string> {
78+
auto stdout_stream = bp::ipstream{};
79+
auto proc = bp::child{
80+
args...,
81+
bp::std_out > stdout_stream,
82+
bp::std_err > stderr,
83+
};
84+
85+
auto lines = std::vector<std::string>{};
86+
auto line = std::string{};
87+
while(std::getline(stdout_stream, line)) {
88+
if(line.ends_with("\r")) {
89+
line.pop_back();
90+
}
91+
lines.emplace_back(line);
92+
}
93+
94+
proc.wait();
95+
96+
if(proc.exit_code() == 0) {
97+
return lines;
98+
}
99+
100+
return {};
101+
}
102+
73103
struct plugin_dir_info {
74104
fs::path plugin_path;
75105
std::string plugin_name;
@@ -90,13 +120,20 @@ auto get_plugin_dir_info( //
90120
return std::nullopt;
91121
}
92122

123+
auto is_clang_formattable(const fs::path& p) -> bool {
124+
auto ext = p.extension();
125+
return ext == ".cpp" || ext == ".c" || ext == ".h" || ext == ".cc" ||
126+
ext == ".hh" || ext == ".hpp";
127+
}
128+
93129
auto main(int argc, char* argv[]) -> int {
94130
auto desc = po::options_description{};
95131
auto pos_desc = po::positional_options_description{};
96132

97133
// clang-format off
98134
desc.add_options()
99135
("help", "show this help message")
136+
("format", "run clang-format on generated c/c++ files")
100137
("engine-dir", po::value<std::string>(), "the unreal engine directory this project uses")
101138
("project-path", po::value<std::string>(), "path to unreal project file or directory");
102139
// clang-format on
@@ -128,7 +165,8 @@ auto main(int argc, char* argv[]) -> int {
128165

129166
auto engine_dir = fs::path{vm.at("engine-dir").as<std::string>()};
130167
auto engine_plugins_dir = engine_dir / "Plugins" / "Marketplace";
131-
std::cout << "INFO: engine directory is '" << engine_dir << "'\n";
168+
std::cout //
169+
<< "INFO: engine directory is '" << engine_dir.generic_string() << "'\n";
132170

133171
auto ecsact_plugin_info = std::optional<plugin_dir_info>{};
134172

@@ -274,5 +312,63 @@ auto main(int argc, char* argv[]) -> int {
274312

275313
codegen_proc.wait();
276314

277-
return codegen_proc.exit_code();
315+
if(auto exit_code = codegen_proc.exit_code(); exit_code != 0) {
316+
std::cerr //
317+
<< "ERROR: ecsact codegen failed with exit code " << exit_code << "\n";
318+
return exit_code;
319+
}
320+
321+
if(vm.count("format")) {
322+
auto clang_format = bp::search_path("clang-format");
323+
324+
if(clang_format.empty()) {
325+
std::cerr //
326+
<< "ERROR: --format specified but clang-format was not found on PATH\n";
327+
return 1;
328+
}
329+
330+
ecsact_codegen_args.emplace_back("--print-output-files");
331+
auto output_files = proc_stdout_list( //
332+
bp::exe(ecsact_cli->string()),
333+
bp::args(ecsact_codegen_args)
334+
);
335+
336+
auto formattable_output_files = std::vector<fs::path>{};
337+
for(fs::path output_path : output_files) {
338+
if(is_clang_formattable(output_path)) {
339+
formattable_output_files.emplace_back(output_path);
340+
}
341+
}
342+
343+
if(!formattable_output_files.empty()) {
344+
std::cout << "INFO: formatting code generated files\n";
345+
std::for_each(
346+
#ifdef __cpp_lib_execution
347+
std::execution::par,
348+
#endif
349+
formattable_output_files.begin(),
350+
formattable_output_files.end(),
351+
[&](fs::path p) {
352+
auto format_proc = bp::child{
353+
bp::exe(clang_format),
354+
bp::args({"-i"s, fs::absolute(p).string()}),
355+
bp::start_dir(project_dir.string()),
356+
};
357+
358+
format_proc.wait();
359+
360+
auto format_exit_code = format_proc.exit_code();
361+
if(format_exit_code != 0) {
362+
std::cerr //
363+
<< "ERROR: failed to format '" << p.generic_string() << "'\n"
364+
<< "ERROR: clang-format exit code " << format_exit_code << "\n";
365+
}
366+
}
367+
);
368+
}
369+
}
370+
371+
std::cout << "SUCCESS: ecsact codegen finished\n";
372+
373+
return 0;
278374
}

0 commit comments

Comments
 (0)