mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-06-27 00:41:21 +02:00
Make the output optional
This commit is contained in:
54
src/cmd.rs
54
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");
|
||||
}
|
||||
|
Reference in New Issue
Block a user