use {
clap::Parser,
clap_cargo::style::CLAP_STYLING,
cocomo::{Cocomo, OutputFormat, ProjectType},
};
#[derive(Parser)]
#[command(
about = "\
COCOMO (Constructive Cost Model) CLI utility and library
<https://crates.io/crates/cocomo> / <https://github.com/qtfkwk/cocomo>
See also: <https://en.wikipedia.org/wiki/COCOMO>
---",
version,
max_term_width = 80,
styles = CLAP_STYLING,
)]
struct Cli {
#[arg(long, value_name = "N", conflicts_with = "paths")]
sloc: Option<f64>,
#[arg(long, value_name = "f64", default_value = "56286.0")]
average_wage: f64,
#[arg(long, value_name = "f64", default_value = "1.0")]
inflation_multiplier: f64,
#[arg(long, value_name = "usize")]
inflation_year: Option<usize>,
#[arg(long, value_name = "f64", default_value = "2.4")]
overhead: f64,
#[arg(long, value_name = "f64", default_value = "1.0")]
eaf: f64,
#[arg(long, value_name = "TYPE", default_value = "organic")]
project_type: ProjectType,
#[arg(long, value_name = "f64,f64,f64", conflicts_with = "project_type")]
custom: Option<String>,
#[arg(long, value_name = "f64", default_value = "2.5")]
development_time: f64,
#[arg(long, value_name = "STRING", default_value = "$")]
currency_symbol: String,
#[arg(short, long, value_name = "FORMAT", default_value = "markdown-table")]
output_format: OutputFormat,
#[arg(value_name = "PATH", default_value = ".")]
paths: Vec<std::path::PathBuf>,
}
fn main() {
let cli = Cli::parse();
let params = if let Some(custom) = cli.custom {
let s: Vec<f64> = custom
.split(',')
.map(|x| {
x.parse::<f64>().unwrap_or_else(|e| {
eprintln!("{e}: {x:?}");
std::process::exit(1);
})
})
.collect();
if s.len() == 3 {
(s[0], s[1], s[2])
} else {
eprintln!("Invalid custom project parameters: {custom:?}");
std::process::exit(1);
}
} else {
cli.project_type.to_params()
};
let project = Cocomo::new(
&cli.currency_symbol,
cli.eaf,
cli.average_wage,
cli.overhead,
¶ms,
cli.development_time,
&cli.paths,
&cli.sloc,
cli.inflation_multiplier,
&cli.inflation_year,
);
println!("{}", project.report(&cli.output_format));
}