summaryrefslogtreecommitdiff
path: root/src/cmd.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd.rs')
-rw-r--r--src/cmd.rs54
1 files changed, 33 insertions, 21 deletions
diff --git a/src/cmd.rs b/src/cmd.rs
index 6092f53..efeb598 100644
--- a/src/cmd.rs
+++ b/src/cmd.rs
@@ -1,30 +1,42 @@
use anyhow::{Context, Result};
-use std::{io::Read, path::Path, process::Command};
+use std::{
+ io::Read,
+ path::Path,
+ process::{Command, Stdio},
+};
/// Run a command with a description for a possible error and append the merged stdout and stderr.
/// The boolean in the returned `Result` is true if the command's exit status is success.
-pub fn run_cmd(mut cmd: Command, description: &str, output: &mut Vec<u8>) -> Result<bool> {
- let (mut reader, writer) = os_pipe::pipe()
- .with_context(|| format!("Failed to create a pipe to run the command `{description}``"))?;
+pub fn run_cmd(mut cmd: Command, description: &str, output: Option<&mut Vec<u8>>) -> Result<bool> {
+ let spawn = |mut cmd: Command| {
+ // NOTE: The closure drops `cmd` which prevents a pipe deadlock.
+ cmd.spawn()
+ .with_context(|| format!("Failed to run the command `{description}`"))
+ };
- let writer_clone = writer.try_clone().with_context(|| {
- format!("Failed to clone the pipe writer for the command `{description}`")
- })?;
+ let mut handle = if let Some(output) = output {
+ let (mut reader, writer) = os_pipe::pipe().with_context(|| {
+ format!("Failed to create a pipe to run the command `{description}``")
+ })?;
- let mut handle = cmd
- .stdout(writer_clone)
- .stderr(writer)
- .spawn()
- .with_context(|| format!("Failed to run the command `{description}`"))?;
+ let writer_clone = writer.try_clone().with_context(|| {
+ format!("Failed to clone the pipe writer for the command `{description}`")
+ })?;
- // Prevent pipe deadlock.
- drop(cmd);
+ cmd.stdout(writer_clone).stderr(writer);
+ let handle = spawn(cmd)?;
- reader
- .read_to_end(output)
- .with_context(|| format!("Failed to read the output of the command `{description}`"))?;
+ reader
+ .read_to_end(output)
+ .with_context(|| format!("Failed to read the output of the command `{description}`"))?;
- output.push(b'\n');
+ output.push(b'\n');
+
+ handle
+ } else {
+ cmd.stdout(Stdio::null()).stderr(Stdio::null());
+ spawn(cmd)?
+ };
handle
.wait()
@@ -42,14 +54,14 @@ pub struct CargoCmd<'a> {
/// Added as `--target-dir` if `Self::dev` is true.
pub target_dir: &'a Path,
/// The output buffer to append the merged stdout and stderr.
- pub output: &'a mut Vec<u8>,
+ pub output: Option<&'a mut Vec<u8>>,
/// true while developing Rustlings.
pub dev: bool,
}
impl<'a> CargoCmd<'a> {
/// Run `cargo SUBCOMMAND --bin EXERCISE_NAME … ARGS`.
- pub fn run(&mut self) -> Result<bool> {
+ pub fn run(self) -> Result<bool> {
let mut cmd = Command::new("cargo");
cmd.arg(self.subcommand);
@@ -86,7 +98,7 @@ mod tests {
cmd.arg("Hello");
let mut output = Vec::with_capacity(8);
- run_cmd(cmd, "echo …", &mut output).unwrap();
+ run_cmd(cmd, "echo …", Some(&mut output)).unwrap();
assert_eq!(output, b"Hello\n\n");
}