vx_paths/
lib.rs

1//! Cross-platform path management for vx tool installations
2//!
3//! This crate provides a unified interface for managing tool installation paths
4//! across different platforms, ensuring consistent directory structures and
5//! proper handling of executable file extensions.
6
7use anyhow::Result;
8use std::path::{Path, PathBuf};
9
10pub mod config;
11pub mod manager;
12pub mod resolver;
13
14pub use config::PathConfig;
15pub use manager::PathManager;
16pub use resolver::PathResolver;
17
18/// Standard vx directory structure
19#[derive(Debug, Clone)]
20pub struct VxPaths {
21    /// Base vx directory (~/.vx)
22    pub base_dir: PathBuf,
23    /// Tools installation directory (~/.vx/tools)
24    pub tools_dir: PathBuf,
25    /// Cache directory (~/.vx/cache)
26    pub cache_dir: PathBuf,
27    /// Configuration directory (~/.vx/config)
28    pub config_dir: PathBuf,
29    /// Temporary directory (~/.vx/tmp)
30    pub tmp_dir: PathBuf,
31}
32
33impl VxPaths {
34    /// Create VxPaths with default locations
35    pub fn new() -> Result<Self> {
36        let home_dir = dirs::home_dir()
37            .ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
38
39        let base_dir = home_dir.join(".vx");
40
41        Ok(Self {
42            tools_dir: base_dir.join("tools"),
43            cache_dir: base_dir.join("cache"),
44            config_dir: base_dir.join("config"),
45            tmp_dir: base_dir.join("tmp"),
46            base_dir,
47        })
48    }
49
50    /// Create VxPaths with custom base directory
51    pub fn with_base_dir<P: AsRef<Path>>(base_dir: P) -> Self {
52        let base_dir = base_dir.as_ref().to_path_buf();
53
54        Self {
55            tools_dir: base_dir.join("tools"),
56            cache_dir: base_dir.join("cache"),
57            config_dir: base_dir.join("config"),
58            tmp_dir: base_dir.join("tmp"),
59            base_dir,
60        }
61    }
62
63    /// Ensure all directories exist
64    pub fn ensure_dirs(&self) -> Result<()> {
65        std::fs::create_dir_all(&self.base_dir)?;
66        std::fs::create_dir_all(&self.tools_dir)?;
67        std::fs::create_dir_all(&self.cache_dir)?;
68        std::fs::create_dir_all(&self.config_dir)?;
69        std::fs::create_dir_all(&self.tmp_dir)?;
70        Ok(())
71    }
72}
73
74impl Default for VxPaths {
75    fn default() -> Self {
76        Self::new().unwrap_or_else(|_| {
77            // Fallback to current directory if home directory is not available
78            Self::with_base_dir(".vx")
79        })
80    }
81}
82
83/// Get the executable file extension for the current platform
84pub fn executable_extension() -> &'static str {
85    if cfg!(target_os = "windows") {
86        ".exe"
87    } else {
88        ""
89    }
90}
91
92/// Add executable extension to a tool name if needed
93pub fn with_executable_extension(tool_name: &str) -> String {
94    format!("{}{}", tool_name, executable_extension())
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_vx_paths_creation() {
103        let paths = VxPaths::with_base_dir("/tmp/test-vx");
104
105        assert_eq!(paths.base_dir, PathBuf::from("/tmp/test-vx"));
106        assert_eq!(paths.tools_dir, PathBuf::from("/tmp/test-vx/tools"));
107        assert_eq!(paths.cache_dir, PathBuf::from("/tmp/test-vx/cache"));
108        assert_eq!(paths.config_dir, PathBuf::from("/tmp/test-vx/config"));
109        assert_eq!(paths.tmp_dir, PathBuf::from("/tmp/test-vx/tmp"));
110    }
111
112    #[test]
113    fn test_executable_extension() {
114        if cfg!(target_os = "windows") {
115            assert_eq!(executable_extension(), ".exe");
116            assert_eq!(with_executable_extension("node"), "node.exe");
117        } else {
118            assert_eq!(executable_extension(), "");
119            assert_eq!(with_executable_extension("node"), "node");
120        }
121    }
122}