use std::path::Path;
use anyhow::{Result, bail};
use crate::model::App;
use crate::store;
pub fn run(command_name: &str, app_name: Option<String>) -> Result<()> {
let apps = store::load_apps()?;
let app = resolve(&apps, app_name)?;
let Some(command_line) = app.commands.get(command_name) else {
bail!(
"app '{0}' has no '{1}' command - add it with `turnout app edit {0} --command {1}=CMD`",
app.name,
command_name
);
};
let dir = Path::new(&app.path);
if !dir.is_dir() {
bail!("project directory {} no longer exists", dir.display());
}
eprintln!("[{}] {command_line}", app.name);
let status = crate::utils::run_in_dir(command_line, dir)?;
std::process::exit(status.code().unwrap_or(1));
}
pub(crate) fn resolve(apps: &[App], name: Option<String>) -> Result<&App> {
match name {
Some(name) => apps
.iter()
.find(|a| a.name == name)
.ok_or_else(|| anyhow::anyhow!("no app named '{name}' - see `turnout app list`")),
None => {
let cwd = std::env::current_dir()?;
let cwd = std::fs::canonicalize(&cwd).unwrap_or(cwd);
apps.iter()
.filter(|a| {
let path = Path::new(&a.path);
let path = std::fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf());
cwd.starts_with(&path)
})
.max_by_key(|a| a.path.len())
.ok_or_else(|| anyhow::anyhow!("not inside a known app directory - pass the app name or see `turnout app list`"))
}
}
}