use std::{
ffi::{OsStr, OsString},
process::Command,
};
use crate::runner::shell_quote;
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Args {
quoted_args: Vec<OsString>,
}
impl Args {
pub fn push<S: Into<OsString>>(&mut self, arg: S) {
self.quoted_args.push(shell_quote(&arg.into()));
}
pub fn arg<S: Into<OsString>>(mut self, arg: S) -> Self {
self.push(arg);
self
}
fn quoted_args(&self) -> impl Iterator<Item = &OsStr> {
self.quoted_args.iter().map(|s| s.as_os_str())
}
}
impl<S> FromIterator<S> for Args
where
S: Into<OsString>,
{
fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Self {
let mut args = Args::default();
for arg in iter.into_iter() {
args.push(arg.into());
}
args
}
}
impl From<Vec<&str>> for Args {
fn from(args: Vec<&str>) -> Self {
let mut new = Self::default();
for arg in args.iter() {
new.push(*arg);
}
new
}
}
pub struct Ssh {
ssh_target: String,
argv: Args,
}
impl Ssh {
pub fn new<S: Into<String>>(ssh_target: S, argv: Args) -> Self {
Self {
ssh_target: ssh_target.into(),
argv,
}
}
pub fn command(&self) -> Command {
let mut cmd = Command::new("ssh");
cmd.arg("--");
cmd.arg(&self.ssh_target);
for arg in self.argv.quoted_args() {
cmd.arg(arg);
}
cmd
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn from_iter() {
let args = Args::from_iter(["foo", "bar"]);
let quoted: Vec<&OsStr> = args.quoted_args().collect();
assert_eq!(quoted, ["foo", "bar"]);
}
}