use std::path::PathBuf;
use std::process::Command;
pub mod git;
pub mod tmux;
#[derive(Debug)]
pub enum Error {
CommandNotFound(String),
CommandFailed { cmd: String, detail: String },
Tmux(String),
Io(std::io::Error),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::CommandNotFound(s) => write!(f, "command not found: {s}"),
Self::CommandFailed { cmd, detail } => {
write!(f, "command failed: {cmd} — {detail}")
}
Self::Tmux(s) => write!(f, "tmux error: {s}"),
Self::Io(e) => write!(f, "io error: {e}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
_ => None,
}
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
pub fn which(cmd: &str) -> Option<PathBuf> {
::which::which(cmd).ok()
}
pub fn require(cmd: &str) -> Result<PathBuf, Error> {
::which::which(cmd).map_err(|_| Error::CommandNotFound(cmd.to_string()))
}
pub fn run(program: &str, args: &[&str]) -> Result<String, Error> {
run_with_env(program, args, &[])
}
pub fn run_with_env(program: &str, args: &[&str], env: &[(&str, &str)]) -> Result<String, Error> {
require(program)?;
let mut command = Command::new(program);
command.args(args);
for (k, v) in env {
command.env(k, v);
}
let output = command.output()?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
return Err(Error::CommandFailed {
cmd: format!("{program} {}", args.first().unwrap_or(&"")),
detail: stderr,
});
}
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
}