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