1use std::{
2 env,
3 process::{Command, ExitStatus, Stdio},
4 sync::mpsc::Sender,
5};
6
7use crate::{exec, Extension};
8use anyhow::Error;
9use fluentci_types::Output;
10
11#[derive(Default)]
12pub struct Hermit {}
13
14impl Hermit {
15 pub fn install(&self, pkgs: Vec<&str>) -> Result<ExitStatus, Error> {
16 self.setup()?;
17
18 Command::new("bash")
19 .arg("-c")
20 .arg("[ -f ./bin/activate-hermit ] || hermit init")
21 .stdout(Stdio::inherit())
22 .stderr(Stdio::inherit())
23 .spawn()?
24 .wait()?;
25
26 let mut child = Command::new("bash")
27 .arg("-c")
28 .arg(format!(
29 ". ./bin/activate-hermit && hermit install {}",
30 pkgs.join(" ")
31 ))
32 .stdin(Stdio::inherit())
33 .stdout(Stdio::inherit())
34 .stderr(Stdio::inherit())
35 .spawn()?;
36 child.wait().map_err(Error::from)
37 }
38}
39
40impl Extension for Hermit {
41 fn exec(
42 &mut self,
43 cmd: &str,
44 tx: Sender<String>,
45 out: Output,
46 last_cmd: bool,
47 work_dir: &str,
48 ) -> Result<ExitStatus, Error> {
49 self.setup()?;
50
51 if cmd.is_empty() {
52 return Ok(ExitStatus::default());
53 }
54
55 Command::new("bash")
56 .arg("-c")
57 .arg("[ -f ./bin/activate-hermit ] || hermit init")
58 .current_dir(work_dir)
59 .stdout(Stdio::inherit())
60 .stderr(Stdio::inherit())
61 .spawn()?
62 .wait()?;
63
64 let cmd = format!(". ./bin/activate-hermit && {}", cmd);
65 exec(&cmd, tx, out, last_cmd, work_dir)
66 }
67
68 fn setup(&self) -> Result<(), Error> {
69 let path = format!(
70 "{}:{}",
71 env::var("PATH")?,
72 format!("{}/bin", env::var("HOME")?)
73 );
74 env::set_var("PATH", &path);
75
76 let status = Command::new("sh")
77 .arg("-c")
78 .arg("type hermit > /dev/null")
79 .spawn()?
80 .wait()?;
81
82 if status.success() {
83 return Ok(());
84 }
85
86 Command::new("sh")
87 .arg("-c")
88 .arg("curl -fsSL https://github.com/cashapp/hermit/releases/download/stable/install.sh | /bin/bash")
89 .stdin(Stdio::inherit())
90 .stdout(Stdio::inherit())
91 .stderr(Stdio::inherit())
92 .spawn()?
93 .wait()?;
94 Ok(())
95 }
96}