use std::fmt::Debug;
use std::path::PathBuf;
use std::process::Stdio;
use clap::Args;
use itertools::Itertools;
use miette::IntoDiagnostic;
use usage::Spec;
#[derive(Debug, Args)]
#[clap(disable_help_flag = true, verbatim_doc_comment)]
pub struct Shell {
script: PathBuf,
#[clap(allow_hyphen_values = true)]
args: Vec<String>,
#[clap(short)]
h: bool,
#[clap(long)]
help: bool,
}
impl Shell {
pub fn run(&mut self, shell: &str) -> miette::Result<()> {
let spec = Spec::parse_file(&self.script)?;
let mut args = self.args.clone();
args.insert(0, spec.bin.clone());
if self.h {
return self.help(&spec, &args, false);
}
if self.help {
return self.help(&spec, &args, true);
}
let parsed = usage::parse::parse(&spec, &args)?;
debug!("{parsed:?}");
let mut cmd = std::process::Command::new(shell);
cmd.stdin(Stdio::inherit());
cmd.stdout(Stdio::inherit());
cmd.stderr(Stdio::inherit());
let script_path = self
.script
.to_str()
.ok_or_else(|| miette::miette!("Invalid file path: {}", self.script.display()))?;
let args = std::iter::once(script_path.to_string())
.chain(self.args.clone())
.collect_vec();
cmd.args(&args);
for (key, val) in &parsed.as_env() {
cmd.env(key, val);
}
let result = cmd.spawn().into_diagnostic()?.wait().into_diagnostic()?;
if !result.success() {
std::process::exit(result.code().unwrap_or(1));
}
Ok(())
}
pub fn help(&self, spec: &Spec, args: &[String], long: bool) -> miette::Result<()> {
let parsed = usage::parse::parse_partial(spec, args)?;
println!("{}", usage::docs::cli::render_help(spec, &parsed.cmd, long));
Ok(())
}
}