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#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test]
80    fn test_config_dir_exists() {
81        let dir = get_config_dir();
82        assert!(dir.is_some());
83        let path = dir.unwrap();
84        assert!(path.ends_with("opencode-cloud"));
85    }
86
87    #[test]
88    fn test_data_dir_exists() {
89        let dir = get_data_dir();
90        assert!(dir.is_some());
91        let path = dir.unwrap();
92        assert!(path.ends_with("opencode-cloud"));
93    }
94
95    #[test]
96    fn test_config_path_ends_with_config_json() {
97        let path = get_config_path();
98        assert!(path.is_some());
99        assert!(path.unwrap().ends_with("config.json"));
100    }
101
102    #[test]
103    fn test_pid_path_ends_with_pid() {
104        let path = get_pid_path();
105        assert!(path.is_some());
106        assert!(path.unwrap().ends_with("opencode-cloud.pid"));
107    }
108}