Skip to main content

opencode_cloud_core/config/
paths.rs

1//! XDG-compliant path resolution for opencode-cloud
2//!
3//! Provides consistent path resolution across platforms:
4//! - Linux/macOS: ~/.config/opencode-cloud/ and ~/.local/share/opencode-cloud/
5//! - Windows: %APPDATA%\opencode-cloud\ and %LOCALAPPDATA%\opencode-cloud\
6
7use std::path::PathBuf;
8
9/// Get the configuration directory path
10///
11/// Returns the directory where config.json should be stored:
12/// - Linux: `~/.config/opencode-cloud/`
13/// - macOS: `~/.config/opencode-cloud/` (XDG-style, not ~/Library)
14/// - Windows: `%APPDATA%\opencode-cloud\`
15pub fn get_config_dir() -> Option<PathBuf> {
16    #[cfg(any(target_os = "linux", target_os = "macos"))]
17    {
18        directories::BaseDirs::new()
19            .map(|dirs| dirs.home_dir().join(".config").join("opencode-cloud"))
20    }
21    #[cfg(target_os = "windows")]
22    {
23        directories::BaseDirs::new()
24            .and_then(|dirs| dirs.config_dir().map(|d| d.to_path_buf()))
25            .map(|d| d.join("opencode-cloud"))
26    }
27    #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
28    {
29        None
30    }
31}
32
33/// Get the data directory path
34///
35/// Returns the directory where runtime data (PID file, logs, etc.) should be stored:
36/// - Linux: `~/.local/share/opencode-cloud/`
37/// - macOS: `~/.local/share/opencode-cloud/` (XDG-style, not ~/Library)
38/// - Windows: `%LOCALAPPDATA%\opencode-cloud\`
39pub fn get_data_dir() -> Option<PathBuf> {
40    #[cfg(any(target_os = "linux", target_os = "macos"))]
41    {
42        directories::BaseDirs::new().map(|dirs| {
43            dirs.home_dir()
44                .join(".local")
45                .join("share")
46                .join("opencode-cloud")
47        })
48    }
49    #[cfg(target_os = "windows")]
50    {
51        directories::BaseDirs::new()
52            .and_then(|dirs| dirs.data_local_dir().map(|d| d.to_path_buf()))
53            .map(|d| d.join("opencode-cloud"))
54    }
55    #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
56    {
57        None
58    }
59}
60
61/// Get the full path to the config file
62///
63/// Returns: `{config_dir}/config.json`
64pub fn get_config_path() -> Option<PathBuf> {
65    get_config_dir().map(|d| d.join("config.json"))
66}
67
68/// Get the full path to the PID lock file
69///
70/// Returns: `{data_dir}/opencode-cloud.pid`
71pub fn get_pid_path() -> Option<PathBuf> {
72    get_data_dir().map(|d| d.join("opencode-cloud.pid"))
73}
74
75/// Get the full path to the hosts configuration file
76///
77/// Returns: `{config_dir}/hosts.json`
78pub fn get_hosts_path() -> Option<PathBuf> {
79    get_config_dir().map(|d| d.join("hosts.json"))
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_config_dir_exists() {
88        let dir = get_config_dir();
89        assert!(dir.is_some());
90        let path = dir.unwrap();
91        assert!(path.ends_with("opencode-cloud"));
92    }
93
94    #[test]
95    fn test_data_dir_exists() {
96        let dir = get_data_dir();
97        assert!(dir.is_some());
98        let path = dir.unwrap();
99        assert!(path.ends_with("opencode-cloud"));
100    }
101
102    #[test]
103    fn test_config_path_ends_with_config_json() {
104        let path = get_config_path();
105        assert!(path.is_some());
106        assert!(path.unwrap().ends_with("config.json"));
107    }
108
109    #[test]
110    fn test_pid_path_ends_with_pid() {
111        let path = get_pid_path();
112        assert!(path.is_some());
113        assert!(path.unwrap().ends_with("opencode-cloud.pid"));
114    }
115
116    #[test]
117    fn test_hosts_path_ends_with_hosts_json() {
118        let path = get_hosts_path();
119        assert!(path.is_some());
120        assert!(path.unwrap().ends_with("hosts.json"));
121    }
122}