1use std::{2 ffi::OsStr,3 process::{Command, Stdio},4};56use anyhow::{Context, Result};7use serde::de::DeserializeOwned;89pub trait CommandExt {10 fn run(&mut self) -> Result<()>;11 fn run_json<T: DeserializeOwned>(&mut self) -> Result<T>;12 fn run_string(&mut self) -> Result<String>;13 fn inherit_stdio(&mut self) -> &mut Self;14 fn ssh_on(host: impl AsRef<OsStr>, command: impl AsRef<OsStr>) -> Self;15}1617impl CommandExt for Command {18 fn inherit_stdio(&mut self) -> &mut Self {19 self.stderr(Stdio::inherit());20 self21 }2223 fn run(&mut self) -> Result<()> {24 let out = self.output()?;25 if !out.status.success() {26 anyhow::bail!("command failed");27 }28 Ok(())29 }3031 fn run_json<T: DeserializeOwned>(&mut self) -> Result<T> {32 let str = self.run_string()?;33 Ok(serde_json::from_str(&str).with_context(|| format!("{:?}", str))?)34 }3536 fn run_string(&mut self) -> Result<String> {37 let out = self.output()?;38 if !out.status.success() {39 anyhow::bail!("command failed");40 }41 Ok(String::from_utf8(out.stdout)?)42 }4344 fn ssh_on(host: impl AsRef<OsStr>, command: impl AsRef<OsStr>) -> Self {45 let mut cmd = Command::new("ssh");46 cmd.arg(host).arg("--").arg(command);47 cmd48 }49}