1use std::process::{Command, Stdio};
4
5use cargo_metadata::Metadata;
6use eyre::eyre;
7
8use crate::{fs::ToRelative, Result};
9
10pub trait CommandExt {
12 fn workspace_spawn(&mut self, workspace: &Metadata) -> Result<()>;
15
16 fn workspace_stdout_raw(&mut self, workspace: &Metadata) -> Result<Vec<u8>>;
20
21 fn workspace_stdout(&mut self, workspace: &Metadata) -> Result<String>;
25}
26
27impl CommandExt for Command {
28 fn workspace_spawn(&mut self, workspace: &Metadata) -> Result<()> {
29 let workspace_root = &workspace.workspace_root;
30
31 self.current_dir(workspace_root);
32
33 let program = self.get_program();
34 let args = self.get_args();
35 tracing::info!(
36 "[{}]$ {}{}",
37 workspace.workspace_root.to_relative(),
38 program.to_string_lossy(),
39 args.fold(String::new(), |mut s, a| {
40 s.push(' ');
41 s.push_str(a.to_string_lossy().as_ref());
42 s
43 })
44 );
45
46 let status = self.status()?;
47 if !status.success() {
48 tracing::error!(
49 "Command for {} failed with status {}",
50 workspace_root.to_relative(),
51 status,
52 );
53 return Err(eyre!(
54 "command for {} failed with status {}",
55 workspace_root.to_relative(),
56 status,
57 ));
58 }
59 Ok(())
60 }
61
62 fn workspace_stdout_raw(&mut self, workspace: &Metadata) -> Result<Vec<u8>> {
63 let workspace_root = &workspace.workspace_root;
64
65 self.current_dir(workspace_root).stdout(Stdio::piped());
66
67 let program = self.get_program();
68 let args = self.get_args();
69 tracing::info!(
70 "[{}]$ {}{}",
71 workspace.workspace_root.to_relative(),
72 program.to_string_lossy(),
73 args.fold(String::new(), |mut s, a| {
74 s.push(' ');
75 s.push_str(a.to_string_lossy().as_ref());
76 s
77 })
78 );
79
80 let output = self.spawn()?.wait_with_output()?;
81
82 if !output.status.success() {
83 tracing::error!(
84 "Command for {} failed with status {}",
85 workspace_root.to_relative(),
86 output.status.code().unwrap()
87 );
88 return Err(eyre!(
89 "command for {} failed with status {}",
90 workspace_root.to_relative(),
91 output.status.code().unwrap()
92 ));
93 }
94
95 Ok(output.stdout)
96 }
97
98 fn workspace_stdout(&mut self, workspace: &Metadata) -> Result<String> {
99 let output = self.workspace_stdout_raw(workspace)?;
100 Ok(String::from_utf8(output)?)
101 }
102}