use std::ffi::OsString;
use std::path::Path;
use pmpx_plugin::Verb;
use super::Session;
use crate::error::{PmpxError, Result};
use crate::runtime::BackendError;
use crate::spawn;
pub fn run_verb(
session: &Session,
verb: Verb,
args: &[OsString],
allow_exec_fallback: bool,
) -> Result<u8> {
let root = match session.project_root() {
Some(r) => r.to_path_buf(),
None => {
if allow_exec_fallback {
let cwd = session.start_dir.clone();
return passthrough(&cwd, args, session.quiet);
}
return Err(session.no_project_error());
}
};
let selection = match session.select(&root) {
Ok(s) => s,
Err(failure) => {
if allow_exec_fallback {
return passthrough(&root, args, session.quiet);
}
return Err(failure.into());
}
};
session.emit_notes(&selection);
let backend = session.load_backend(&selection)?;
match backend.command(&root, &selection.matched, verb, args) {
Ok(Ok(spec)) => {
announce(session.quiet, &spec);
spawn::run(&spec, &root)
}
Ok(Err(BackendError::UnsupportedVerb)) if allow_exec_fallback => {
passthrough(&root, args, session.quiet)
}
Ok(Err(e)) => Err(PmpxError::Backend(
format!("{} cannot do `{verb}`: {e}", selection.name),
e.exit_code(),
)),
Err(e) => Err(e),
}
}
fn passthrough(cwd: &Path, args: &[OsString], quiet: bool) -> Result<u8> {
let Some((program, rest)) = args.split_first() else {
return Err(PmpxError::Usage(
"`pmpx exec` needs a command, for example `pmpx exec ls`".to_string(),
));
};
let spec = pmpx_plugin::CommandSpec {
program: program.clone(),
args: rest.to_vec(),
cwd: Some(cwd.to_path_buf()),
};
announce(quiet, &spec);
spawn::run(&spec, cwd)
}
fn announce(quiet: bool, spec: &pmpx_plugin::CommandSpec) {
if quiet {
return;
}
spawn::announce(spec);
}