nix_query/
proc.rs

1use std::io;
2use std::io::BufRead;
3use std::process::{Command, ExitStatus};
4use std::string::FromUtf8Error;
5
6#[derive(Debug)]
7pub enum CommandError {
8    Io(Box<io::Error>),
9    Stderr(String),
10    De(serde_json::Error),
11    Encoding(FromUtf8Error),
12    ExitStatus(ExitStatus),
13}
14
15impl From<io::Error> for CommandError {
16    fn from(e: io::Error) -> Self {
17        CommandError::Io(Box::new(e))
18    }
19}
20
21impl From<serde_json::Error> for CommandError {
22    fn from(e: serde_json::Error) -> Self {
23        CommandError::De(e)
24    }
25}
26
27pub fn run_cmd<F, T>(c: &mut Command, f: F) -> Result<T, CommandError>
28where
29    F: FnOnce(Vec<u8>) -> T,
30{
31    let output = c.output().map_err(Box::new).map_err(CommandError::Io)?;
32
33    if !output.status.success() {
34        return Err(CommandError::ExitStatus(output.status));
35    }
36
37    if !output.stderr.is_empty() {
38        return Err(CommandError::Stderr(
39            String::from_utf8(output.stderr).map_err(CommandError::Encoding)?,
40        ));
41    }
42
43    Ok(f(output.stdout))
44}
45
46pub fn run_cmd_stdout(c: &mut Command) -> Result<String, CommandError> {
47    run_cmd(c, String::from_utf8)?.map_err(CommandError::Encoding)
48}
49
50pub fn run_cmd_stdout_lines_capacity(
51    c: &mut Command,
52    lines_hint: usize,
53) -> Result<Vec<String>, CommandError> {
54    let mut ret = Vec::with_capacity(lines_hint);
55    ret.extend(run_cmd(c, |stdout| {
56        stdout
57            .lines()
58            .collect::<Result<_, io::Error>>()
59            .map_err(Into::<CommandError>::into)
60    })?);
61    Ok(ret)
62}
63
64pub fn run_cmd_stdout_lines(c: &mut Command) -> Result<Vec<String>, CommandError> {
65    run_cmd_stdout_lines_capacity(c, 64)
66}