upstream_rs/utils/
static_paths.rs1use anyhow::{Context, Result};
2use std::path::PathBuf;
3
4pub struct AppDirs {
6 pub user_dir: PathBuf,
7 pub config_dir: PathBuf,
8 pub data_dir: PathBuf,
9 pub packages_dir: PathBuf,
10 pub cache_dir: PathBuf,
11 pub metadata_dir: PathBuf,
12}
13
14impl Default for AppDirs {
15 fn default() -> Self {
16 Self::new().expect("failed to determine upstream app directories")
17 }
18}
19
20impl AppDirs {
21 pub fn new() -> Result<Self> {
22 let user_dir =
23 dirs::home_dir().context("Failed to determine the current user's home directory")?;
24 let config_dir = dirs::config_dir()
25 .context("Failed to determine the current user's config directory")?
26 .join("upstream");
27
28 let data_dir = user_dir.join(".upstream");
29 let packages_dir = data_dir.join("packages");
30 let cache_dir = data_dir.join("cache");
31 let metadata_dir = data_dir.join("metadata");
32
33 Ok(Self {
34 user_dir,
35 config_dir,
36 data_dir,
37 packages_dir,
38 cache_dir,
39 metadata_dir,
40 })
41 }
42}
43
44pub struct ConfigPaths {
46 pub config_file: PathBuf,
47 pub packages_file: PathBuf,
48 pub metadata_file: PathBuf,
49 pub paths_file: PathBuf,
50 pub paths_nu_file: PathBuf,
51}
52
53impl ConfigPaths {
54 pub fn new(dirs: &AppDirs) -> Self {
55 Self {
56 config_file: dirs.config_dir.join("config.toml"),
57 packages_file: dirs.metadata_dir.join("packages.json"),
58 metadata_file: dirs.metadata_dir.join("metadata.json"),
59 paths_file: dirs.metadata_dir.join("paths.sh"),
60 paths_nu_file: dirs.metadata_dir.join("paths.nu"),
61 }
62 }
63}
64
65pub struct InstallPaths {
67 pub appimages_dir: PathBuf,
68 pub binaries_dir: PathBuf,
69 pub archives_dir: PathBuf,
70 pub rollback_dir: PathBuf,
71 pub tmp_dir: PathBuf,
72}
73
74impl InstallPaths {
75 pub fn new(dirs: &AppDirs) -> Self {
76 Self {
77 appimages_dir: dirs.packages_dir.join("appimages"),
78 binaries_dir: dirs.packages_dir.join("binaries"),
79 archives_dir: dirs.packages_dir.join("archives"),
80 rollback_dir: dirs.data_dir.join("rollback"),
81 tmp_dir: dirs.data_dir.join("tmp"),
82 }
83 }
84}
85
86pub struct IntegrationPaths {
88 pub symlinks_dir: PathBuf,
89 pub xdg_applications_dir: PathBuf,
90 pub icons_dir: PathBuf,
91 pub bash_completions_dir: PathBuf,
92 pub fish_completions_dir: PathBuf,
93 pub zsh_completions_dir: PathBuf,
94}
95
96impl IntegrationPaths {
97 pub fn new(dirs: &AppDirs) -> Self {
98 Self {
99 symlinks_dir: dirs.data_dir.join("symlinks"),
100 icons_dir: dirs.data_dir.join("icons"),
101 xdg_applications_dir: dirs.user_dir.join(".local/share/applications"),
102 bash_completions_dir: dirs
103 .user_dir
104 .join(".local/share/bash-completion/completions"),
105 fish_completions_dir: dirs.user_dir.join(".config/fish/completions"),
106 zsh_completions_dir: dirs.user_dir.join(".local/share/zsh/site-functions"),
107 }
108 }
109}
110
111pub struct UpstreamPaths {
113 pub dirs: AppDirs,
114 pub config: ConfigPaths,
115 pub install: InstallPaths,
116 pub integration: IntegrationPaths,
117}
118
119impl Default for UpstreamPaths {
120 fn default() -> Self {
121 Self::new().expect("failed to determine upstream paths")
122 }
123}
124
125impl UpstreamPaths {
126 pub fn new() -> Result<Self> {
127 let dirs = AppDirs::new()?;
128 Ok(Self {
129 config: ConfigPaths::new(&dirs),
130 install: InstallPaths::new(&dirs),
131 integration: IntegrationPaths::new(&dirs),
132 dirs,
133 })
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::UpstreamPaths;
140
141 #[test]
142 fn upstream_paths_are_composed_from_base_directories() {
143 let paths = UpstreamPaths::new().expect("paths");
144
145 assert_eq!(
146 paths.config.config_file,
147 paths.dirs.config_dir.join("config.toml")
148 );
149 assert_eq!(
150 paths.config.packages_file,
151 paths.dirs.metadata_dir.join("packages.json")
152 );
153 assert_eq!(
154 paths.config.metadata_file,
155 paths.dirs.metadata_dir.join("metadata.json")
156 );
157 assert_eq!(
158 paths.config.paths_nu_file,
159 paths.dirs.metadata_dir.join("paths.nu")
160 );
161 assert_eq!(
162 paths.install.binaries_dir,
163 paths.dirs.packages_dir.join("binaries")
164 );
165 assert_eq!(
166 paths.dirs.packages_dir,
167 paths.dirs.data_dir.join("packages")
168 );
169 assert_eq!(paths.dirs.cache_dir, paths.dirs.data_dir.join("cache"));
170 assert_eq!(
171 paths.integration.symlinks_dir,
172 paths.dirs.data_dir.join("symlinks")
173 );
174 assert_eq!(
175 paths.integration.fish_completions_dir,
176 paths.dirs.user_dir.join(".config/fish/completions")
177 );
178 assert_eq!(
179 paths.install.rollback_dir,
180 paths.dirs.data_dir.join("rollback")
181 );
182 assert_eq!(paths.install.tmp_dir, paths.dirs.data_dir.join("tmp"));
183 }
184}