use anyhow::{bail, Result};
use std::process::Output;
fn spawn(name: &str, args: &[&str], install: &str) -> Result<Output> {
match std::process::Command::new(name).args(args).output() {
Ok(output) => Ok(output),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => bail!(
"`{name}` is required for this gate but is not installed \
(install it: `{install}`)"
),
Err(error) => bail!("`{name}` could not be run: {error}"),
}
}
const ATLAS_INSTALL: &str = "brew install ariga/tap/atlas";
const SUPABASE_INSTALL: &str = "brew install supabase/tap/supabase";
const BUN_INSTALL: &str = "curl -fsSL https://bun.sh/install | bash";
pub fn atlas(args: &[&str]) -> Result<Output> {
spawn("atlas", args, ATLAS_INSTALL)
}
pub fn supabase(args: &[&str]) -> Result<Output> {
spawn("supabase", args, SUPABASE_INSTALL)
}
pub fn bun_emit(script: &str, envs: &[(&str, &str)]) -> Result<Output> {
let mut command = std::process::Command::new("bun");
command.arg("-e").arg(script);
for (key, value) in envs {
command.env(key, value);
}
match command.output() {
Ok(output) => Ok(output),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => bail!(
"`bun` is required for Zod authoring (spec §4.2) but is not installed \
(install it: `{BUN_INSTALL}`)"
),
Err(error) => bail!("`bun` could not be run: {error}"),
}
}