use crate::graph::save_commodity_graphs_for_model;
use crate::input::{load_commodity_graphs, load_model};
use crate::log;
use crate::output::{create_output_directory, get_graphs_dir, get_output_dir};
use crate::settings::Settings;
use ::log::{info, warn};
use anyhow::{Context, Result};
use clap::{Args, CommandFactory, Parser, Subcommand};
use std::path::{Path, PathBuf};
pub mod example;
use example::ExampleSubcommands;
pub mod settings;
use settings::SettingsSubcommands;
#[derive(Parser)]
#[command(version, about)]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
#[arg(long, hide = true)]
markdown_help: bool,
}
#[derive(Args)]
pub struct RunOpts {
#[arg(short, long)]
pub output_dir: Option<PathBuf>,
#[arg(long)]
pub overwrite: bool,
#[arg(long)]
pub debug_model: bool,
}
#[derive(Args)]
pub struct GraphOpts {
#[arg(short, long)]
pub output_dir: Option<PathBuf>,
#[arg(long)]
pub overwrite: bool,
}
#[derive(Subcommand)]
enum Commands {
Run {
model_dir: PathBuf,
#[command(flatten)]
opts: RunOpts,
},
Example {
#[command(subcommand)]
subcommand: ExampleSubcommands,
},
Validate {
model_dir: PathBuf,
},
SaveGraphs {
model_dir: PathBuf,
#[command(flatten)]
opts: GraphOpts,
},
Settings {
#[command(subcommand)]
subcommand: SettingsSubcommands,
},
}
impl Commands {
fn execute(self) -> Result<()> {
match self {
Self::Run { model_dir, opts } => handle_run_command(&model_dir, &opts),
Self::Example { subcommand } => subcommand.execute(),
Self::Validate { model_dir } => handle_validate_command(&model_dir),
Self::SaveGraphs { model_dir, opts } => handle_save_graphs_command(&model_dir, &opts),
Self::Settings { subcommand } => subcommand.execute(),
}
}
}
pub fn run_cli() -> Result<()> {
let cli = Cli::parse();
if cli.markdown_help {
clap_markdown::print_help_markdown::<Cli>();
return Ok(());
}
if let Some(command) = cli.command {
command.execute()?;
} else {
Cli::command().print_long_help()?;
}
Ok(())
}
pub fn handle_run_command(model_path: &Path, opts: &RunOpts) -> Result<()> {
let mut settings = Settings::load_or_default().context("Failed to load settings.")?;
if opts.debug_model {
settings.debug_model = true;
}
if opts.overwrite {
settings.overwrite = true;
}
let pathbuf: PathBuf;
let output_path = if let Some(p) = opts.output_dir.as_deref() {
p
} else {
pathbuf = get_output_dir(model_path, settings.results_root)?;
&pathbuf
};
let overwrite =
create_output_directory(output_path, settings.overwrite).with_context(|| {
format!(
"Failed to create output directory: {}",
output_path.display()
)
})?;
log::init(&settings.log_level, Some(output_path)).context("Failed to initialise logging.")?;
info!("Starting MUSE2 v{}", env!("CARGO_PKG_VERSION"));
let model = load_model(model_path).context("Failed to load model.")?;
info!("Loaded model from {}", model_path.display());
info!("Output folder: {}", output_path.display());
if overwrite {
warn!("Output folder will be overwritten");
}
crate::simulation::run(&model, output_path, settings.debug_model)?;
info!("Simulation complete!");
Ok(())
}
pub fn handle_validate_command(model_path: &Path) -> Result<()> {
let settings = Settings::load_or_default().context("Failed to load settings.")?;
log::init(&settings.log_level, None).context("Failed to initialise logging.")?;
load_model(model_path).context("Failed to validate model.")?;
info!("Model validation successful!");
Ok(())
}
pub fn handle_save_graphs_command(model_path: &Path, opts: &GraphOpts) -> Result<()> {
let mut settings = Settings::load_or_default().context("Failed to load settings.")?;
if opts.overwrite {
settings.overwrite = true;
}
let pathbuf: PathBuf;
let output_path = if let Some(p) = opts.output_dir.as_deref() {
p
} else {
pathbuf = get_graphs_dir(model_path, settings.graph_results_root)?;
&pathbuf
};
let overwrite =
create_output_directory(output_path, settings.overwrite).with_context(|| {
format!(
"Failed to create graphs directory: {}",
output_path.display()
)
})?;
log::init(&settings.log_level, None).context("Failed to initialise logging.")?;
if overwrite {
warn!("Graphs directory will be overwritten");
}
let commodity_graphs = load_commodity_graphs(model_path).context("Failed to build graphs.")?;
save_commodity_graphs_for_model(&commodity_graphs, output_path)?;
info!("Graphs saved to: {}", output_path.display());
Ok(())
}