#[cfg(windows)]
use crate::error;
use crate::error::{Error, Result};
#[cfg(windows)]
use snafu::ResultExt;
use std::{ffi::OsString, path::Path, process::Command};
pub fn run(bin_path: &Path, args: &[OsString]) -> Result<()> {
#[cfg(unix)]
{
exec_replace(bin_path, args)
}
#[cfg(windows)]
{
spawn_and_wait_windows(bin_path, args)
}
#[cfg(not(any(unix, windows)))]
{
spawn_and_wait_fallback(bin_path, args)
}
}
#[cfg(unix)]
fn exec_replace(bin_path: &Path, args: &[OsString]) -> Result<()> {
use std::os::unix::process::CommandExt;
let mut cmd = Command::new(bin_path);
cmd.args(args);
let err = cmd.exec();
Err(err).map_err(|source| Error::ExecFailed {
path: bin_path.to_owned(),
source,
})
}
#[cfg(windows)]
fn spawn_and_wait_windows(bin_path: &Path, args: &[OsString]) -> Result<()> {
ctrlc::set_handler(|| {
})
.context(error::ConsoleHandlerFailedSnafu)?;
let mut child = Command::new(bin_path)
.args(args)
.spawn()
.map_err(|source| Error::SpawnFailed {
path: bin_path.to_owned(),
source,
})?;
let status = child.wait().map_err(|source| Error::WaitFailed { source })?;
let exit_code = status.code().unwrap_or(1);
#[allow(clippy::exit)]
std::process::exit(exit_code)
}
#[cfg(not(any(unix, windows)))]
fn spawn_and_wait_fallback(bin_path: &Path, args: &[OsString]) -> Result<()> {
let mut child = Command::new(bin_path)
.args(args)
.spawn()
.map_err(|source| Error::SpawnFailed {
path: bin_path.to_owned(),
source,
})?;
let status = child.wait().map_err(|source| Error::WaitFailed { source })?;
let exit_code = status.code().unwrap_or(1);
#[allow(clippy::exit)]
std::process::exit(exit_code)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_run_nonexistent_binary() {
let result = run(Path::new("/nonexistent/binary"), &[]);
assert!(result.is_err());
}
#[test]
fn test_run_with_args() {
let _: fn(&Path, &[OsString]) -> Result<()> = run;
}
}