use super::{Args, Fail};
use crate::iq::labfit::{
campaign_dir, resolve_paths, run_campaign_scenario, run_scenario, LabFitScenario,
};
use std::path::{Path, PathBuf};
pub(crate) fn run(args: &[String]) -> Result<String, Fail> {
let a = Args::parse(args, &[]).map_err(Fail::Usage)?;
a.need_pos(1, "labfit")?;
let path = Path::new(&a.pos[0]);
let src = std::fs::read_to_string(path)
.map_err(|e| Fail::Run(format!("cannot read {}: {e}", path.display())))?;
let mut scenario: LabFitScenario =
toml::from_str(&src).map_err(|e| Fail::Usage(format!("invalid labfit scenario: {e}")))?;
let base = path.parent().map(PathBuf::from).unwrap_or_default();
resolve_paths(&mut scenario, &base);
let prefix = match a.get("--out-prefix") {
Some(p) => PathBuf::from(p),
None => path.with_extension(""),
};
if campaign_dir(&scenario).is_some() {
return run_campaign(&scenario, &prefix);
}
let out = run_scenario(&scenario).map_err(Fail::Run)?;
let written = write_all(
&prefix,
[
("labfit.json", &out.json),
("residuals.csv", &out.residuals_csv),
("predictions.csv", &out.predictions_csv),
("labfit.md", &out.markdown),
],
)?;
Ok(format!(
"fitted {} run(s); wrote {}",
scenario.runs.len(),
written.join(", ")
))
}
fn run_campaign(scenario: &LabFitScenario, prefix: &Path) -> Result<String, Fail> {
let out = run_campaign_scenario(scenario).map_err(Fail::Run)?;
let written = write_all(
prefix,
[
("labfit-iq.json", &out.json),
("residuals.csv", &out.residuals_csv),
("predictions.csv", &out.predictions_csv),
("labfit-iq.md", &out.markdown),
],
)?;
Ok(format!(
"fitted {} unit(s) from campaign; wrote {}",
out.report.fit_units.len(),
written.join(", ")
))
}
fn write_all(prefix: &Path, files: [(&str, &String); 4]) -> Result<Vec<String>, Fail> {
let mut written = Vec::new();
for (ext, body) in files {
let target = PathBuf::from(format!("{}.{ext}", prefix.display()));
std::fs::write(&target, body)
.map_err(|e| Fail::Run(format!("cannot write {}: {e}", target.display())))?;
written.push(target.display().to_string());
}
Ok(written)
}