use std::{collections::HashMap, process::{Child, Command, Stdio}};
use std::io::{self, BufRead};
use anyhow::{anyhow, Result};
use crate::config::get_brew_bin;
#[derive(Debug, Clone)]
pub struct Brew {
cmd_: String,
env_: HashMap<String, String>,
}
impl Default for Brew {
fn default() -> Self{
let mut e = HashMap::new();
e.insert("HOMEBREW_NO_AUTO_UPDATE".to_string(), "1".to_string());
Self {
cmd_: String::new(),
env_: e,
}
}
}
impl Brew {
pub fn new<T: AsRef<str>>(cmd: T) -> Self {
Self {
cmd_: cmd.as_ref().to_string(),
env_: HashMap::new(),
}
}
pub fn set_cmd<S: AsRef<str>>(&mut self, cmd: S) -> &mut Self{
self.cmd_ = cmd.as_ref().to_string();
self
}
pub fn set_env<K: AsRef<str>, V: AsRef<str>>(&mut self, key: K, value: V) -> &mut Self{
self.env_.insert(key.as_ref().to_string(), value.as_ref().to_string());
self
}
pub fn set_env_no_auto_update(&mut self) -> &mut Self {
self.set_env("HOMEBREW_NO_AUTO_UPDATE", "1")
}
pub fn output(&self) -> Result<String> {
let bin = get_brew_bin()?;
let cmds = self.cmd_.split(' ');
let output = Command::new(bin)
.args(cmds)
.envs(&self.env_)
.output()?;
let outerr = String::from_utf8_lossy(&output.stderr);
if !outerr.is_empty() {
if let Some(e) = outerr.strip_suffix("\n") {
return Err(anyhow!("{e}"));
} else {
return Err(anyhow!("{outerr}"));
}
}
let out = String::from_utf8_lossy(&output.stdout);
if let Some(o) = out.strip_suffix("\n") {
return Ok(o.to_string());
}
Ok(out.to_string())
}
pub fn output_vec(&self) -> Result<Vec<String>> {
let out = self.output()?;
let res: Vec<String> = out.split('\n')
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect();
Ok(res)
}
pub fn spawn(&self) -> Result<()> {
let bin = get_brew_bin()?;
let cmds = self.cmd_.split(' ');
let mut child: Child = Command::new(bin)
.args(cmds)
.stdout(Stdio::piped()) .spawn()?;
let stdout = child.stdout.take().ok_or_else(|| anyhow!("Could not capture standard output"))?;
let reader = io::BufReader::new(stdout);
for line in reader.lines() {
let line = line?;
println!("{}", line);
}
let _ = child.wait()?;
Ok(())
}
}
pub fn brew(cmd: &str) -> Result<String> {
Brew::new(cmd)
.set_env_no_auto_update()
.output()
}
pub fn brew_spawn(cmd: &str) -> Result<()> {
Brew::new(cmd)
.set_env_no_auto_update()
.spawn()
}