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 self.inherit_stdio();25 let out = self.output()?;26 if !out.status.success() {27 anyhow::bail!("command ({:?}) failed with status {}", self, out.status);28 }29 Ok(())30 }3132 fn run_json<T: DeserializeOwned>(&mut self) -> Result<T> {33 let str = self.run_string()?;34 serde_json::from_str(&str).with_context(|| format!("{:?}", str))35 }3637 fn run_string(&mut self) -> Result<String> {38 self.inherit_stdio();39 let out = self.output()?;40 if !out.status.success() {41 anyhow::bail!("command ({:?}) failed with status {}", self, out.status);42 }43 Ok(String::from_utf8(out.stdout)?)44 }4546 fn ssh_on(host: impl AsRef<OsStr>, command: impl AsRef<OsStr>) -> Self {47 let mut cmd = Command::new("ssh");48 cmd.arg(host).arg("--").arg(command);49 cmd50 }51}