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