Skip to main content

terraphim_hooks/
discovery.rs

1//! Binary discovery utilities for terraphim-agent.
2
3use std::path::{Path, PathBuf};
4
5/// Location where terraphim-agent was found.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum BinaryLocation {
8    /// Found in system PATH
9    Path,
10    /// Found in local target/release directory
11    LocalRelease(PathBuf),
12    /// Found in ~/.cargo/bin
13    CargoHome(PathBuf),
14}
15
16impl BinaryLocation {
17    /// Get the path to the binary.
18    pub fn path(&self) -> PathBuf {
19        match self {
20            BinaryLocation::Path => PathBuf::from("terraphim-agent"),
21            BinaryLocation::LocalRelease(p) | BinaryLocation::CargoHome(p) => p.clone(),
22        }
23    }
24}
25
26/// Discover terraphim-agent binary location.
27///
28/// Searches in order:
29/// 1. System PATH
30/// 2. ./target/release/terraphim-agent (local build)
31/// 3. ~/.cargo/bin/terraphim-agent (cargo install)
32///
33/// Returns `None` if binary not found in any location.
34pub fn discover_binary() -> Option<BinaryLocation> {
35    // Check PATH first
36    if which_in_path("terraphim-agent") {
37        return Some(BinaryLocation::Path);
38    }
39
40    // Check local release build
41    let local_release = PathBuf::from("./target/release/terraphim-agent");
42    if local_release.exists() && is_executable(&local_release) {
43        return Some(BinaryLocation::LocalRelease(local_release));
44    }
45
46    // Check cargo home
47    if let Some(home) = dirs::home_dir() {
48        let cargo_bin = home.join(".cargo/bin/terraphim-agent");
49        if cargo_bin.exists() && is_executable(&cargo_bin) {
50            return Some(BinaryLocation::CargoHome(cargo_bin));
51        }
52    }
53
54    None
55}
56
57fn which_in_path(binary: &str) -> bool {
58    std::process::Command::new("which")
59        .arg(binary)
60        .output()
61        .map(|o| o.status.success())
62        .unwrap_or(false)
63}
64
65#[cfg(unix)]
66fn is_executable(path: &Path) -> bool {
67    use std::os::unix::fs::PermissionsExt;
68    path.metadata()
69        .map(|m| m.permissions().mode() & 0o111 != 0)
70        .unwrap_or(false)
71}
72
73#[cfg(not(unix))]
74fn is_executable(path: &Path) -> bool {
75    path.exists()
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_discover_returns_some_or_none() {
84        // This test just verifies the function doesn't panic
85        let _ = discover_binary();
86    }
87
88    #[test]
89    fn test_binary_location_path() {
90        let loc = BinaryLocation::Path;
91        assert_eq!(loc.path(), PathBuf::from("terraphim-agent"));
92    }
93
94    #[test]
95    fn test_binary_location_local_release() {
96        let path = PathBuf::from("/some/path/terraphim-agent");
97        let loc = BinaryLocation::LocalRelease(path.clone());
98        assert_eq!(loc.path(), path);
99    }
100}