use crate::error::{Error, Result};
use std::process::Command as OsCommand;
const DEFAULT_SHELL: &str = "sh";
#[derive(Debug)]
pub struct TtyCommand;
impl TtyCommand {
#[allow(clippy::new_ret_no_self)]
pub fn new(command: &str) -> Result<OsCommand> {
Self::new_with_shell(command, None)
}
pub fn new_with_shell(cmd: &str, shell: Option<&str>) -> Result<OsCommand> {
if cfg!(any(target_os = "linux", target_os = "android")) {
let mut command = OsCommand::new("script");
command.args(["-q", "-e", "-c", cmd, "/dev/null"]);
if let Some(shell) = shell {
command.env("SHELL", shell.trim());
}
Ok(command)
} else if cfg!(any(target_os = "macos", target_os = "freebsd")) {
let mut command = OsCommand::new("script");
command.args([
"-q",
"/dev/null",
shell.unwrap_or(DEFAULT_SHELL).trim(),
"-c",
cmd,
]);
Ok(command)
} else if cfg!(target_os = "windows") {
let mut command = OsCommand::new("cmd");
command.args(["/C", cmd]);
Ok(command)
} else {
Err(Error::UnsupportedPlatformError)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use std::process::Stdio;
fn run_command(cmd: &str, shell: Option<&str>) -> Result<String> {
let command = TtyCommand::new_with_shell(cmd, shell)?
.stderr(Stdio::inherit())
.output()?;
Ok(String::from_utf8_lossy(&command.stdout).replace("\r\n", "\n"))
}
#[test]
fn run_echo() -> Result<()> {
assert_eq!("hello world\n", run_command("echo hello world", None)?);
Ok(())
}
#[test]
fn run_seq() -> Result<()> {
assert_eq!("1\n2\n3\n", run_command("seq 3", None)?);
Ok(())
}
#[test]
fn run_echo_quotes() -> Result<()> {
assert_eq!(
"Hello $`' world!\n",
run_command(r#"echo "Hello \$\`' world!""#, None)?
);
Ok(())
}
}