use crate::bs_safe::{BridgeStanError, Result};
use log::info;
use path_absolutize::Absolutize;
use std::path::{Path, PathBuf};
const MAKE: &str = "make";
pub fn compile_model(
bs_path: &Path,
stan_file: &Path,
stanc_args: &[&str],
make_args: &[&str],
) -> Result<PathBuf> {
let stan_file = stan_file
.absolutize()
.map_err(|e| BridgeStanError::ModelCompilingFailed(e.to_string()))?;
let includir_stan_file_dir = stan_file
.parent()
.and_then(Path::to_str)
.map(|x| format!("--include-paths={x}"))
.unwrap_or_default();
let includir_stan_file_dir = includir_stan_file_dir.as_str();
if stan_file.extension().unwrap_or_default() != "stan" {
return Err(BridgeStanError::ModelCompilingFailed(
"File must be a .stan file".to_owned(),
));
}
let output = stan_file.with_extension("");
let output = output.with_file_name(format!(
"{}_model",
output.file_name().unwrap_or_default().to_string_lossy()
));
let output = output.with_extension("so");
let stanc_args = [&[includir_stan_file_dir], stanc_args].concat();
let stanc_args = stanc_args.join(" ");
let stanc_args = format!("STANCFLAGS={stanc_args}");
let stanc_args = [stanc_args.as_str()];
let cmd = [
&[output.to_str().unwrap_or_default()],
make_args,
stanc_args.as_slice(),
]
.concat();
info!(
"Compiling model with command: {} \"{}\"",
MAKE,
cmd.join("\" \"")
);
std::process::Command::new(MAKE)
.args(cmd)
.current_dir(bs_path)
.env("STAN_THREADS", "true")
.output()
.map_err(|e| e.to_string())
.and_then(|proc| {
if !proc.status.success() {
Err(format!(
"{} {}",
String::from_utf8_lossy(proc.stdout.as_slice()).into_owned(),
String::from_utf8_lossy(proc.stderr.as_slice()).into_owned(),
))
} else {
Ok(())
}
})
.map_err(|e| BridgeStanError::ModelCompilingFailed(e.to_string()))?;
info!("Finished compiling model");
Ok(output)
}