Skip to main content

gbm/cmds/
install.rs

1use std::path::Path;
2
3use owo_colors::OwoColorize;
4use rootcause::prelude::ResultExt;
5
6pub fn run() -> rootcause::Result<()> {
7    let zshrc = std::env::var("HOME")
8        .context("error missing HOME environment variable")
9        .map(|home| Path::new(&home).join(".zshrc"))?;
10
11    install_zsh_wrapper_at(&zshrc)?;
12    println!("{} gbm in {}", "Patched".green().bold(), zshrc.display());
13
14    Ok(())
15}
16
17fn install_zsh_wrapper_at(path: &Path) -> rootcause::Result<bool> {
18    let content = std::fs::read_to_string(path)
19        .context("error reading zshrc")
20        .attach_with(|| format!("path={}", path.display()))?;
21
22    if content.lines().any(|line| line.trim() == super::ZSHRC_INSTALL_LINE) {
23        return Ok(false);
24    }
25
26    let mut updated = content;
27    if !updated.is_empty() && !updated.ends_with('\n') {
28        updated.push('\n');
29    }
30    updated.push_str(super::ZSHRC_INSTALL_LINE);
31    updated.push('\n');
32
33    std::fs::write(path, updated)
34        .context("error installing zshrc")
35        .attach_with(|| format!("path={}", path.display()))?;
36
37    Ok(true)
38}
39
40#[cfg(test)]
41mod tests {
42    use test_that::prelude::*;
43
44    use super::*;
45
46    #[test]
47    fn test_install_zsh_wrapper_at_appends_guarded_line_and_is_idempotent() {
48        let dir = tempfile::tempdir().unwrap();
49        let zshrc = dir.path().join(".zshrc");
50        std::fs::write(&zshrc, "source ~/.zshrc.local\n").unwrap();
51
52        assert_that!(install_zsh_wrapper_at(&zshrc), ok(eq(true)));
53        let first = std::fs::read_to_string(&zshrc).unwrap();
54        assert_that!(install_zsh_wrapper_at(&zshrc), ok(eq(false)));
55        let second = std::fs::read_to_string(&zshrc).unwrap();
56
57        assert_that!(first, eq(second));
58        assert_that!(
59            first,
60            eq(format!("source ~/.zshrc.local\n{}\n", super::super::ZSHRC_INSTALL_LINE))
61        );
62        assert_that!(first.matches(super::super::ZSHRC_INSTALL_LINE).count(), eq(1));
63    }
64
65    #[test]
66    fn test_install_zsh_wrapper_at_fails_when_zshrc_is_missing() {
67        let dir = tempfile::tempdir().unwrap();
68        let zshrc = dir.path().join(".zshrc");
69
70        assert_that!(
71            install_zsh_wrapper_at(&zshrc),
72            err(displays_as(contains_substring("error reading zshrc")))
73        );
74    }
75}