use std::path::Path;
use std::process::{Command, Stdio};
use pmpx_plugin::CommandSpec;
#[cfg(windows)]
use super::quoting::cmd_raw_command_line;
use super::resolve::{resolve, ProgramKind};
use crate::error::Result;
pub fn command_for(spec: &CommandSpec, cwd: &Path) -> Result<Command> {
let resolved = resolve(&spec.program)?;
let cwd = spec.cwd.as_deref().unwrap_or(cwd);
let mut cmd = match resolved.kind {
ProgramKind::Native => {
let mut c = Command::new(&resolved.program);
c.args(&spec.args);
c
}
ProgramKind::CmdShim => {
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
let mut c = Command::new("cmd");
c.raw_arg(cmd_raw_command_line(&resolved.program, &spec.args));
c
}
#[cfg(not(windows))]
{
let mut c = Command::new(&resolved.program);
c.args(&spec.args);
c
}
}
ProgramKind::PowerShellShim => {
let mut c = Command::new("pwsh");
c.arg("-NoProfile").arg("-File").arg(&resolved.program);
c.args(&spec.args);
c
}
};
cmd.current_dir(cwd);
cmd.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit());
Ok(cmd)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_missing_program_fails_before_spawning() {
let tmp = tempfile::tempdir().unwrap();
let spec = CommandSpec::new("pmpx-definitely-not-a-real-program-xyz");
assert!(command_for(&spec, tmp.path()).is_err());
}
#[test]
fn a_cwd_in_the_spec_overrides_the_callers_directory() {
let outer = tempfile::tempdir().unwrap();
let inner = tempfile::tempdir().unwrap();
let spec = CommandSpec::new("cargo").arg("--version").cwd(inner.path());
let cmd = command_for(&spec, outer.path()).unwrap();
assert_eq!(cmd.get_current_dir(), Some(inner.path()));
}
#[test]
fn without_a_cwd_in_the_spec_the_callers_directory_is_used() {
let outer = tempfile::tempdir().unwrap();
let spec = CommandSpec::new("cargo").arg("--version");
let cmd = command_for(&spec, outer.path()).unwrap();
assert_eq!(cmd.get_current_dir(), Some(outer.path()));
}
}