Skip to main content

git_cli/
util.rs

1use anyhow::{Context, Result};
2use nils_common::process;
3use std::process::Output;
4
5pub fn cmd_exists(cmd: &str) -> bool {
6    process::cmd_exists(cmd)
7}
8
9pub fn run_output(cmd: &str, args: &[&str]) -> Result<Output> {
10    process::run_output(cmd, args)
11        .map(|output| output.into_std_output())
12        .with_context(|| format!("spawn {cmd}"))
13}
14
15#[cfg(test)]
16mod tests {
17    use super::*;
18    use nils_test_support::{EnvGuard, GlobalStateLock, StubBinDir};
19    use tempfile::TempDir;
20
21    #[test]
22    fn run_output_returns_ok_for_nonzero_exit_status() {
23        let lock = GlobalStateLock::new();
24        let stubs = StubBinDir::new();
25        stubs.write_exe(
26            "git",
27            r#"#!/bin/bash
28set -euo pipefail
29if [[ "${1:-}" == "rev-parse" && "${2:-}" == "--is-inside-work-tree" ]]; then
30  exit 128
31fi
32exit 0
33"#,
34        );
35
36        let _path_guard = EnvGuard::set(&lock, "PATH", &stubs.path_str());
37        let output = run_output("git", &["rev-parse", "--is-inside-work-tree"]).expect("output");
38        assert!(!output.status.success());
39    }
40
41    #[test]
42    fn git_repo_probe_semantics_are_stable() {
43        fn probe() -> bool {
44            run_output("git", &["rev-parse", "--is-inside-work-tree"])
45                .map(|output| output.status.success())
46                .unwrap_or(false)
47        }
48
49        let lock = GlobalStateLock::new();
50
51        let success_stubs = StubBinDir::new();
52        success_stubs.write_exe(
53            "git",
54            r#"#!/bin/bash
55set -euo pipefail
56if [[ "${1:-}" == "rev-parse" && "${2:-}" == "--is-inside-work-tree" ]]; then
57  exit 0
58fi
59exit 1
60"#,
61        );
62        let success_path_guard = EnvGuard::set(&lock, "PATH", &success_stubs.path_str());
63        assert!(probe());
64        drop(success_path_guard);
65
66        let fail_stubs = StubBinDir::new();
67        fail_stubs.write_exe(
68            "git",
69            r#"#!/bin/bash
70set -euo pipefail
71if [[ "${1:-}" == "rev-parse" && "${2:-}" == "--is-inside-work-tree" ]]; then
72  exit 128
73fi
74exit 1
75"#,
76        );
77        let fail_path_guard = EnvGuard::set(&lock, "PATH", &fail_stubs.path_str());
78        assert!(!probe());
79        drop(fail_path_guard);
80
81        let empty = TempDir::new().expect("tempdir");
82        let empty_path = empty.path().to_string_lossy().to_string();
83        let _missing_path_guard = EnvGuard::set(&lock, "PATH", &empty_path);
84        assert!(!probe());
85    }
86}