1
1
#include < iostream>
2
2
#include < filesystem>
3
+ #ifdef __cpp_lib_execution
4
+ # include < execution>
5
+ #endif
3
6
#include < boost/process.hpp>
4
7
#include < boost/program_options.hpp>
5
8
9
+ using namespace std ::string_literals;
6
10
namespace fs = std::filesystem;
7
11
namespace bp = boost::process;
8
12
namespace po = boost::program_options;
@@ -70,6 +74,32 @@ auto proc_stdout(auto&&... args) -> std::optional<std::string> {
70
74
return std::nullopt;
71
75
}
72
76
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
+
73
103
struct plugin_dir_info {
74
104
fs::path plugin_path;
75
105
std::string plugin_name;
@@ -90,13 +120,20 @@ auto get_plugin_dir_info( //
90
120
return std::nullopt;
91
121
}
92
122
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
+
93
129
auto main (int argc, char * argv[]) -> int {
94
130
auto desc = po::options_description{};
95
131
auto pos_desc = po::positional_options_description{};
96
132
97
133
// clang-format off
98
134
desc.add_options ()
99
135
(" help" , " show this help message" )
136
+ (" format" , " run clang-format on generated c/c++ files" )
100
137
(" engine-dir" , po::value<std::string>(), " the unreal engine directory this project uses" )
101
138
(" project-path" , po::value<std::string>(), " path to unreal project file or directory" );
102
139
// clang-format on
@@ -128,7 +165,8 @@ auto main(int argc, char* argv[]) -> int {
128
165
129
166
auto engine_dir = fs::path{vm.at (" engine-dir" ).as <std::string>()};
130
167
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 " ;
132
170
133
171
auto ecsact_plugin_info = std::optional<plugin_dir_info>{};
134
172
@@ -274,5 +312,63 @@ auto main(int argc, char* argv[]) -> int {
274
312
275
313
codegen_proc.wait ();
276
314
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 ;
278
374
}
0 commit comments