1use crate::input::load_model;
3use crate::log;
4use crate::output::{create_output_directory, get_output_dir};
5use crate::settings::Settings;
6use ::log::info;
7use anyhow::{Context, Result};
8use clap::{CommandFactory, Parser, Subcommand};
9use std::path::{Path, PathBuf};
10
11pub mod example;
12use example::ExampleSubcommands;
13
14#[derive(Parser)]
16#[command(version, about)]
17struct Cli {
18 #[command(subcommand)]
20 command: Option<Commands>,
21 #[arg(long, hide = true)]
23 markdown_help: bool,
24}
25
26#[derive(Subcommand)]
28enum Commands {
29 Run {
31 model_dir: PathBuf,
33 #[arg(short, long)]
35 output_dir: Option<PathBuf>,
36 #[arg(long)]
38 debug_model: bool,
39 },
40 Example {
42 #[command(subcommand)]
44 subcommand: ExampleSubcommands,
45 },
46}
47
48impl Commands {
49 fn execute(self) -> Result<()> {
51 match self {
52 Self::Run {
53 model_dir,
54 output_dir,
55 debug_model,
56 } => handle_run_command(&model_dir, output_dir.as_deref(), debug_model, None),
57 Self::Example { subcommand } => subcommand.execute(),
58 }
59 }
60}
61
62pub fn run_cli() -> Result<()> {
64 let cli = Cli::parse();
65
66 if cli.markdown_help {
68 clap_markdown::print_help_markdown::<Cli>();
69 return Ok(());
70 }
71
72 let Some(command) = cli.command else {
73 let help_str = Cli::command().render_long_help().to_string();
75 println!("{help_str}");
76 return Ok(());
77 };
78
79 command.execute()
80}
81
82pub fn handle_run_command(
84 model_path: &Path,
85 output_path: Option<&Path>,
86 debug_model: bool,
87 settings: Option<Settings>,
88) -> Result<()> {
89 let mut settings = if let Some(settings) = settings {
91 settings
92 } else {
93 Settings::load().context("Failed to load settings.")?
94 };
95
96 if debug_model {
98 settings.debug_model = true;
99 }
100
101 let output_path = match output_path {
103 Some(p) => p.to_owned(),
104 None => get_output_dir(model_path)?,
105 };
106 create_output_directory(&output_path).context("Failed to create output directory.")?;
107
108 log::init(settings.log_level.as_deref(), &output_path)
110 .context("Failed to initialise logging.")?;
111
112 let (model, assets) = load_model(model_path).context("Failed to load model.")?;
114 info!("Loaded model from {}", model_path.display());
115 info!("Output data will be written to {}", output_path.display());
116
117 crate::simulation::run(model, assets, &output_path, settings.debug_model)?;
119
120 Ok(())
121}