nix-query 1.0.2

A cached fuzzy searcher for Nix packages
Documentation
use std::io;
use std::io::BufRead;
use std::process::{Command, ExitStatus};
use std::string::FromUtf8Error;

#[derive(Debug)]
pub enum CommandError {
    Io(Box<io::Error>),
    Stderr(String),
    De(serde_json::Error),
    Encoding(FromUtf8Error),
    ExitStatus(ExitStatus),
}

impl From<io::Error> for CommandError {
    fn from(e: io::Error) -> Self {
        CommandError::Io(Box::new(e))
    }
}

impl From<serde_json::Error> for CommandError {
    fn from(e: serde_json::Error) -> Self {
        CommandError::De(e)
    }
}

pub fn run_cmd<F, T>(c: &mut Command, f: F) -> Result<T, CommandError>
where
    F: FnOnce(Vec<u8>) -> T,
{
    let output = c.output().map_err(Box::new).map_err(CommandError::Io)?;

    if !output.status.success() {
        return Err(CommandError::ExitStatus(output.status));
    }

    if !output.stderr.is_empty() {
        return Err(CommandError::Stderr(
            String::from_utf8(output.stderr).map_err(CommandError::Encoding)?,
        ));
    }

    Ok(f(output.stdout))
}

pub fn run_cmd_stdout(c: &mut Command) -> Result<String, CommandError> {
    run_cmd(c, String::from_utf8)?.map_err(CommandError::Encoding)
}

pub fn run_cmd_stdout_lines_capacity(
    c: &mut Command,
    lines_hint: usize,
) -> Result<Vec<String>, CommandError> {
    let mut ret = Vec::with_capacity(lines_hint);
    ret.extend(run_cmd(c, |stdout| {
        stdout
            .lines()
            .collect::<Result<_, io::Error>>()
            .map_err(Into::<CommandError>::into)
    })?);
    Ok(ret)
}

pub fn run_cmd_stdout_lines(c: &mut Command) -> Result<Vec<String>, CommandError> {
    run_cmd_stdout_lines_capacity(c, 64)
}