summaryrefslogtreecommitdiff
path: root/src/cmd.rs
blob: 28f21c555fdc14888ac085326ed56a4c61a88be9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use anyhow::{Context, Result};
use std::{io::Read, path::Path, process::Command};

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}``"))?;

    let writer_clone = writer.try_clone().with_context(|| {
        format!("Failed to clone the pipe writer for the command `{description}`")
    })?;

    let mut handle = cmd
        .stdout(writer_clone)
        .stderr(writer)
        .spawn()
        .with_context(|| format!("Failed to run the command `{description}`"))?;

    // Prevent pipe deadlock.
    drop(cmd);

    reader
        .read_to_end(output)
        .with_context(|| format!("Failed to read the output of the command `{description}`"))?;

    output.push(b'\n');

    handle
        .wait()
        .with_context(|| format!("Failed to wait on the command `{description}` to exit"))
        .map(|status| status.success())
}

pub struct CargoCmd<'a> {
    pub subcommand: &'a str,
    pub args: &'a [&'a str],
    pub exercise_name: &'a str,
    pub description: &'a str,
    pub hide_warnings: bool,
    pub target_dir: &'a Path,
    pub output: &'a mut Vec<u8>,
    pub dev: bool,
}

impl<'a> CargoCmd<'a> {
    pub fn run(&mut self) -> Result<bool> {
        let mut cmd = Command::new("cargo");
        cmd.arg(self.subcommand);

        // A hack to make `cargo run` work when developing Rustlings.
        if self.dev {
            cmd.arg("--manifest-path")
                .arg("dev/Cargo.toml")
                .arg("--target-dir")
                .arg(self.target_dir);
        }

        cmd.arg("--color")
            .arg("always")
            .arg("-q")
            .arg("--bin")
            .arg(self.exercise_name)
            .args(self.args);

        if self.hide_warnings {
            cmd.env("RUSTFLAGS", "-A warnings");
        }

        run_cmd(cmd, self.description, self.output)
    }
}