33 * @brief CLI entrypoint for the HydroChrono YAML-based runner
44 */
55
6- #include < hydroc/hydrochrono_runner/run_hydrochrono_from_yaml .h>
6+ #include < hydroc/runner/run_from_yaml .h>
77#include < hydroc/version.h>
88#include " ../src/utils/misc_options.h"
99#include < hydroc/logging.h>
1010#include < string>
1111#include < filesystem>
12+ #include < iostream>
1213
1314#ifdef _WIN32
1415#include < windows.h>
@@ -75,15 +76,15 @@ struct CLIArgs {
7576 std::string sim_file;
7677 bool nogui = false ;
7778 bool log = false ;
78- bool nobanner = false ; // NEW: Disable banner display
79- bool quiet = false ; // NEW: Quiet mode (minimal output)
80- bool debug = false ; // NEW: Enable detailed simulation diagnostics
81- bool trace = false ; // NEW: Enable step-by-step simulation tracing
82- std::string output_h5; // NEW: Export HDF5 results path
83- bool h5_verbose = false ; // NEW: HDF5 verbose diagnostics
84- std::string h5_tag; // NEW: Optional tag appended to filename
85- bool fail_fast = false ; // NEW: Stop on first failure during sweep
86- bool profile = false ; // NEW: Enable runtime profiling summary
79+ bool nobanner = false ; // Disable banner display
80+ bool quiet = false ; // Quiet mode (minimal output)
81+ bool debug = false ; // Enable detailed simulation diagnostics
82+ bool trace = false ; // Enable step-by-step simulation tracing
83+ std::string output_h5; // Export HDF5 results path
84+ bool h5_verbose = false ; // HDF5 verbose diagnostics
85+ std::string h5_tag; // Optional tag appended to filename
86+ bool fail_fast = false ; // Stop on first failure during sweep
87+ bool profile = false ; // Enable runtime profiling summary
8788};
8889
8990static CLIArgs ParseArguments (int argc, char * argv[]) {
@@ -164,51 +165,60 @@ int main(int argc, char* argv[]) {
164165 // Configure UTF-8 console output on Windows (must be first!)
165166 // ---------------------------------------------------------------------
166167#ifdef _WIN32
167- // Enable UTF-8 console output on Windows
168168 SetConsoleOutputCP (CP_UTF8);
169- std::ios_base::sync_with_stdio (false );
170169#endif
171170
172171 // Check for hidden options first (before any other processing)
173172 if (hydroc::misc::HandleHiddenOptions (argc, argv)) {
174173 return 0 ;
175174 }
176175
176+ // -------------------------------------------------------------------------
177+ // Initialize logging early so all CLI output uses the nice formatting
178+ // Wrapped in try/catch to report initialization failures clearly
179+ // -------------------------------------------------------------------------
180+ try {
181+ hydroc::LoggingConfig cfg;
182+ cfg.enable_cli_output = true ;
183+ cfg.enable_file_output = false ;
184+ cfg.console_level = hydroc::LogLevel::Info;
185+ cfg.file_level = hydroc::LogLevel::Info;
186+ (void )hydroc::Initialize (cfg); // Ignore return value; failures throw
187+ } catch (const std::exception& e) {
188+ std::cerr << " FATAL: Exception during logging initialization: " << e.what () << std::endl;
189+ return 1 ;
190+ } catch (...) {
191+ std::cerr << " FATAL: Unknown exception during logging initialization" << std::endl;
192+ return 1 ;
193+ }
194+
177195 // Check for help/version/info flags first (before requiring input directory)
178196 for (int i = 1 ; i < argc; i++) {
179197 std::string arg = argv[i];
180198 if (arg == " --help" || arg == " -h" ) {
181- hydroc::LoggingConfig cfg;
182- cfg.enable_cli_output = true ;
183- cfg.enable_file_output = false ;
184- cfg.console_level = hydroc::LogLevel::Info;
185- cfg.file_level = hydroc::LogLevel::Info;
186- hydroc::Initialize (cfg);
187199 PrintHelp (argv[0 ]);
188200 hydroc::Shutdown ();
189201 return 0 ;
190202 } else if (arg == " --version" || arg == " -v" ) {
191- hydroc::LoggingConfig cfg;
192- cfg.enable_cli_output = true ;
193- cfg.enable_file_output = false ;
194- cfg.console_level = hydroc::LogLevel::Info;
195- cfg.file_level = hydroc::LogLevel::Info;
196- hydroc::Initialize (cfg);
197203 PrintVersion ();
198204 hydroc::Shutdown ();
199205 return 0 ;
200206 } else if (arg == " --info" || arg == " -i" ) {
201- hydroc::LoggingConfig cfg;
202- cfg.enable_cli_output = true ;
203- cfg.enable_file_output = false ;
204- cfg.console_level = hydroc::LogLevel::Info;
205- cfg.file_level = hydroc::LogLevel::Info;
206- hydroc::Initialize (cfg);
207207 PrintInfo ();
208208 hydroc::Shutdown ();
209209 return 0 ;
210210 }
211211 }
212+
213+ // Handle "no arguments" case
214+ if (argc == 1 ) {
215+ hydroc::cli::LogError (" ERROR: Input directory or setup file is required" );
216+ hydroc::cli::ShowEmptyLine ();
217+ hydroc::cli::LogInfo (std::string (" Usage: " ) + argv[0 ] + " [options] <input_directory_or_setup_file>" );
218+ hydroc::cli::LogInfo (" Use --help for more information." );
219+ hydroc::Shutdown ();
220+ return 1 ;
221+ }
212222
213223 // Parse command line arguments
214224 CLIArgs args = ParseArguments (argc, argv);
@@ -219,85 +229,61 @@ int main(int argc, char* argv[]) {
219229 hydroc::cli::ShowEmptyLine ();
220230 hydroc::cli::LogInfo (std::string (" Usage: " ) + argv[0 ] + " [options] <input_directory_or_setup_file>" );
221231 hydroc::cli::LogInfo (" Use --help for more information." );
232+ hydroc::Shutdown ();
222233 return 1 ;
223234 }
224235
225236 // Check if input is a setup file or directory
226237 std::filesystem::path input_path (args.input_directory );
227238 if (std::filesystem::exists (input_path)) {
228239 if (std::filesystem::is_regular_file (input_path)) {
229- // Check if it's a setup file
230240 if (input_path.extension () == " .yaml" ) {
231241 const std::string filename = input_path.filename ().string ();
232242 const std::string suffix = " .setup.yaml" ;
233243 if (filename.length () >= suffix.length () &&
234244 filename.compare (filename.length () - suffix.length (), suffix.length (), suffix) == 0 ) {
235- // Convert setup file path to directory path
236245 args.input_directory = input_path.parent_path ().string ();
237246 hydroc::cli::LogInfo (std::string (" Loaded setup file: " ) + input_path.string ());
238247 } else {
239248 hydroc::cli::LogError (" ERROR: File provided is not a valid .setup.yaml file" );
240249 hydroc::cli::LogInfo (std::string (" Path: " ) + args.input_directory );
241250 hydroc::cli::LogInfo (" Expected: Directory or any file ending in '.setup.yaml'" );
251+ hydroc::Shutdown ();
242252 return 1 ;
243253 }
244254 }
245255 } else if (!std::filesystem::is_directory (input_path)) {
246256 hydroc::cli::LogError (" ERROR: Path is neither a directory nor a regular file" );
247257 hydroc::cli::LogInfo (std::string (" Path: " ) + args.input_directory );
258+ hydroc::Shutdown ();
248259 return 1 ;
249260 }
250261 } else {
251262 hydroc::cli::LogError (" ERROR: Input path does not exist" );
252263 hydroc::cli::LogInfo (std::string (" Path: " ) + args.input_directory );
264+ hydroc::Shutdown ();
253265 return 1 ;
254266 }
255267
256- // Note: Banner will be rendered by the YAML runner
268+ // Shutdown logging - the runner will reinitialize it
269+ hydroc::Shutdown ();
257270
258271 // Prepare arguments for the YAML runner
259272 std::vector<std::string> runner_args;
260- runner_args.push_back (argv[0 ]); // program name
261-
262- // Add input directory
273+ runner_args.push_back (argv[0 ]);
263274 runner_args.push_back (args.input_directory );
264275
265- // Add optional flags
266- if (args.nogui ) {
267- runner_args.push_back (" --nogui" );
268- }
269-
270- // Add logging flag if requested
271- if (args.log ) {
272- runner_args.push_back (" --log" );
273- }
274-
275- // Add new CLI options
276- if (args.nobanner ) {
277- runner_args.push_back (" --nobanner" );
278- }
279-
280- if (args.quiet ) {
281- runner_args.push_back (" --quiet" );
282- }
283-
284- if (args.debug ) {
285- runner_args.push_back (" --debug" );
286- }
287-
288- if (args.trace ) {
289- runner_args.push_back (" --trace" );
290- }
291-
292- if (args.profile ) {
293- runner_args.push_back (" --profile" );
294- }
295-
276+ if (args.nogui ) runner_args.push_back (" --nogui" );
277+ if (args.log ) runner_args.push_back (" --log" );
278+ if (args.nobanner ) runner_args.push_back (" --nobanner" );
279+ if (args.quiet ) runner_args.push_back (" --quiet" );
280+ if (args.debug ) runner_args.push_back (" --debug" );
281+ if (args.trace ) runner_args.push_back (" --trace" );
282+ if (args.profile ) runner_args.push_back (" --profile" );
296283 if (!args.model_file .empty ()) {
297284 runner_args.push_back (" --model_file" );
298285 runner_args.push_back (args.model_file );
299286 }
300-
301287 if (!args.sim_file .empty ()) {
302288 runner_args.push_back (" --sim_file" );
303289 runner_args.push_back (args.sim_file );
@@ -306,9 +292,7 @@ int main(int argc, char* argv[]) {
306292 runner_args.push_back (" --output-h5" );
307293 runner_args.push_back (args.output_h5 );
308294 }
309- if (args.fail_fast ) {
310- runner_args.push_back (" --fail-fast" );
311- }
295+ if (args.fail_fast ) runner_args.push_back (" --fail-fast" );
312296
313297 // Convert to argc/argv format for the runner
314298 std::vector<char *> runner_argv;
0 commit comments