nils_common/provider_runtime/
paths.rs1use std::env;
2use std::path::{Path, PathBuf};
3
4use super::profile::{HomePathSelection, ProviderProfile};
5
6pub fn resolve_secret_dir(profile: &ProviderProfile) -> Option<PathBuf> {
7 if let Some(dir) = resolve_secret_dir_from_env(profile) {
8 return Some(dir);
9 }
10
11 if let Some(home) = home_dir() {
12 return Some(resolve_home_path(&home, profile.paths.secret_dir_home));
13 }
14
15 let feature_dir = resolve_feature_dir(profile)?;
16 if feature_dir.join("init.zsh").is_file()
17 || feature_dir
18 .join(profile.paths.feature_tool_script)
19 .is_file()
20 {
21 return Some(feature_dir.join("secrets"));
22 }
23 Some(feature_dir)
24}
25
26pub fn resolve_secret_dir_from_env(profile: &ProviderProfile) -> Option<PathBuf> {
27 env_path(profile.env.secret_dir)
28}
29
30pub fn resolve_auth_file(profile: &ProviderProfile) -> Option<PathBuf> {
31 if let Some(path) = env_path(profile.env.auth_file) {
32 return Some(path);
33 }
34
35 let home = home_dir()?;
36 Some(resolve_home_path(&home, profile.paths.auth_file_home))
37}
38
39pub fn resolve_secret_cache_dir(profile: &ProviderProfile) -> Option<PathBuf> {
40 if let Some(path) = env_path(profile.env.secret_cache_dir) {
41 return Some(path);
42 }
43
44 if let Some(path) = env_path("ZSH_CACHE_DIR") {
45 return Some(path.join(profile.paths.feature_name).join("secrets"));
46 }
47
48 if let Some(home_segments) = profile.paths.secret_cache_home
49 && let Some(home) = home_dir()
50 {
51 return Some(join_segments(home, home_segments));
52 }
53
54 Some(
55 resolve_zdotdir()?
56 .join("cache")
57 .join(profile.paths.feature_name)
58 .join("secrets"),
59 )
60}
61
62pub fn resolve_feature_dir(profile: &ProviderProfile) -> Option<PathBuf> {
63 let script_dir = resolve_script_dir()?;
64 let feature_dir = script_dir
65 .join("_features")
66 .join(profile.paths.feature_name);
67 if feature_dir.is_dir() {
68 Some(feature_dir)
69 } else {
70 None
71 }
72}
73
74pub fn resolve_script_dir() -> Option<PathBuf> {
75 if let Some(path) = env_path("ZSH_SCRIPT_DIR") {
76 return Some(path);
77 }
78 Some(resolve_zdotdir()?.join("scripts"))
79}
80
81pub fn resolve_zdotdir() -> Option<PathBuf> {
82 if let Some(path) = env_path("ZDOTDIR") {
83 return Some(path);
84 }
85
86 if let Some(preload) = env_path("_ZSH_BOOTSTRAP_PRELOAD_PATH")
87 && let Some(parent) = parent_dir(&preload, 2)
88 {
89 return Some(parent);
90 }
91
92 let home = home_dir()?;
93 Some(home.join(".config").join("zsh"))
94}
95
96fn resolve_home_path(home: &Path, selection: HomePathSelection) -> PathBuf {
97 match selection {
98 HomePathSelection::ModernOnly(segments) => join_segments(home.to_path_buf(), segments),
99 }
100}
101
102fn join_segments(mut base: PathBuf, segments: &[&str]) -> PathBuf {
103 for segment in segments {
104 base.push(segment);
105 }
106 base
107}
108
109fn env_path(key: &str) -> Option<PathBuf> {
110 let raw = env::var_os(key)?;
111 if raw.is_empty() {
112 return None;
113 }
114 Some(PathBuf::from(raw))
115}
116
117fn home_dir() -> Option<PathBuf> {
118 env_path("HOME")
119}
120
121fn parent_dir(path: &Path, levels: usize) -> Option<PathBuf> {
122 let mut current = path;
123 for _ in 0..levels {
124 current = current.parent()?;
125 }
126 Some(current.to_path_buf())
127}