1use std::ffi::OsStr;
6use std::path::PathBuf;
7
8pub trait CommandErrorContext {
10 fn output_with_context(
12 &mut self,
13 ) -> impl std::future::Future<Output = anyhow::Result<std::process::Output>>;
14}
15
16impl CommandErrorContext for tokio::process::Command {
17 async fn output_with_context(&mut self) -> anyhow::Result<std::process::Output> {
18 let prog = program_name(self.as_std());
19 self.output()
20 .await
21 .map_err(|e| anyhow::anyhow!("failed to execute `{prog}`: {e}"))
22 }
23}
24
25pub trait SyncCommandErrorContext {
27 fn output_with_context(&mut self) -> anyhow::Result<std::process::Output>;
28 fn status_with_context(&mut self) -> anyhow::Result<std::process::ExitStatus>;
29}
30
31impl SyncCommandErrorContext for std::process::Command {
32 fn output_with_context(&mut self) -> anyhow::Result<std::process::Output> {
33 let prog = program_name(self);
34 self.output()
35 .map_err(|e| anyhow::anyhow!("failed to execute `{prog}`: {e}"))
36 }
37
38 fn status_with_context(&mut self) -> anyhow::Result<std::process::ExitStatus> {
39 let prog = program_name(self);
40 self.status()
41 .map_err(|e| anyhow::anyhow!("failed to execute `{prog}`: {e}"))
42 }
43}
44
45fn program_name(cmd: &std::process::Command) -> String {
47 let prog: &OsStr = cmd.get_program();
48 let path = PathBuf::from(prog);
49 path.display().to_string()
50}