summaryrefslogtreecommitdiff
path: root/src/pathinfo.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/pathinfo.rs')
-rw-r--r--src/pathinfo.rs246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/pathinfo.rs b/src/pathinfo.rs
new file mode 100644
index 0000000..b0c3be4
--- /dev/null
+++ b/src/pathinfo.rs
@@ -0,0 +1,246 @@
1use std::{
2 fmt::Display,
3 path::PathBuf,
4};
5
6use serde::{Deserialize, Serialize};
7
8use crate::{
9 backup::BackupId,
10 config::Config,
11 error::{Error, Result},
12};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct PathInfo {
16 pub modified: bool,
17 pub is_file: bool,
18 rel_location: String,
19 location_root: LocationRoot,
20 last_modified: BackupId,
21 children: Vec<PathInfo>
22}
23
24impl PathInfo {
25 pub fn from_path(config: &Config, path: &str) -> Result<Self> {
26 let locations = Self::parse_location(path, config)?;
27
28 Ok(Self::handle_dir(config, &locations.0, &locations.1)?)
29 }
30
31 fn handle_dir(
32 config: &Config,
33 rel_location: &str,
34 location_root: &LocationRoot,
35 ) -> Result<Self> {
36 println!("Handling {rel_location}");
37 let path = Self::get_abs_path(&location_root.to_string(), rel_location);
38 Ok(if path.is_dir() {
39 let mut modified = false;
40 let mut children: Vec<PathInfo> = Vec::new();
41
42 let paths = std::fs::read_dir(path).unwrap();
43 for path in paths {
44 let pathstr = path.unwrap().path().to_string_lossy().to_string();
45 let root = format!("{}/", location_root.to_string());
46 let Some(rl) = pathstr.split_once(&root) else {
47 panic!("HUH");
48 };
49 let handle = Self::handle_dir(config, rl.1, location_root)?;
50 if handle.modified {
51 modified = true;
52 };
53 children.push(handle);
54 }
55 Self {
56 modified,
57 is_file: false,
58 rel_location: rel_location.to_string(),
59 location_root: location_root.clone(),
60 last_modified: "".to_string(),
61 children
62 }
63 } else {
64 Self::from_file(rel_location, location_root.clone())?
65 })
66 }
67
68 fn from_file(rel_location: &str, location_root: LocationRoot) -> Result<Self> {
69 println!("From file {rel_location}");
70
71 let modified = false;
72
73 Ok(Self {
74 rel_location: rel_location.to_string(),
75 location_root,
76 modified,
77 last_modified: "".to_string(),
78 is_file: true,
79 children: Vec::new()
80 })
81 }
82
83 pub fn get_absolute_path(&self) -> PathBuf {
84 Self::get_abs_path(&self.location_root.to_string(), &self.rel_location)
85 }
86
87 fn get_abs_path(location_root: &str, rel_location: &str) -> PathBuf {
88 let path = format!("{}/{}", location_root, rel_location);
89 PathBuf::from(path)
90 }
91
92 fn parse_location(value: &str, config: &Config) -> Result<(String, LocationRoot)> {
93 let Some(split) = value.split_once('/') else {
94 return Err(Error::InvalidDirectory(value.to_string()));
95 };
96 if split.0.starts_with('~') {
97 if config.user.len() != 1 {
98 return Err(Error::MultiUser);
99 }
100 return Ok((
101 split.1.to_string(),
102 LocationRoot::User(config.user[0].clone()),
103 ));
104 };
105 Ok((
106 split.1.to_string(),
107 LocationRoot::from_op_str(split.0, config)?,
108 ))
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
113pub enum LocationRoot {
114 User(String),
115 Custom(String),
116 SystemSettings,
117 Root,
118}
119
120impl Display for LocationRoot {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 match self {
123 LocationRoot::User(user) => write!(f, "/home/{user}"),
124 LocationRoot::Custom(loc) => write!(f, "{loc}"),
125 LocationRoot::SystemSettings => write!(f, "/etc"),
126 LocationRoot::Root => write!(f, "/"),
127 }
128 }
129}
130
131impl LocationRoot {
132 fn from_op_str(value: &str, config: &Config) -> Result<Self> {
133 let split_str = value.split_once(':');
134 let Some(split_op) = split_str else {
135 return Err(Error::NoIndex);
136 };
137 match split_op.0 {
138 "u" => Ok(Self::User(split_op.1.to_string())),
139 "s" => Ok(Self::SystemSettings),
140 "r" => Ok(Self::Root),
141 "c" => Ok(Self::Custom(
142 config
143 .custom_directories
144 .get(split_op.1)
145 .ok_or_else(|| Error::CustomDirectory(split_op.1.to_string()))?
146 .to_string(),
147 )),
148 _ => Err(Error::InvalidIndex(split_op.0.to_string())),
149 }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use crate::{
156 config::Config,
157 error::{Error, Result},
158 pathinfo::PathInfo,
159 };
160
161 use super::LocationRoot;
162
163 #[test]
164 fn from_op_str() -> Result<()> {
165 let mut config = Config::default();
166 config
167 .custom_directories
168 .insert("test".to_string(), "/usr/local/test".to_string());
169
170 let mut values: Vec<(&str, Result<LocationRoot>)> = Vec::new();
171 values.push(("u:test", Ok(LocationRoot::User("test".to_string()))));
172 values.push(("s:", Ok(LocationRoot::SystemSettings)));
173 values.push(("r:", Ok(LocationRoot::Root)));
174 values.push((
175 "c:test",
176 Ok(LocationRoot::Custom("/usr/local/test".to_string())),
177 ));
178 values.push(("c:rest", Err(Error::CustomDirectory("rest".to_string()))));
179 values.push(("t:test/", Err(Error::InvalidIndex("t".to_string()))));
180 values.push((
181 "test:test/usr",
182 Err(Error::InvalidIndex("test".to_string())),
183 ));
184 values.push(("/usr/local/test", Err(Error::NoIndex)));
185 values.push(("c/usr/local/test", Err(Error::NoIndex)));
186
187 for value in values {
188 print!("Testing {value:?}");
189 assert_eq!(LocationRoot::from_op_str(value.0, &config), value.1);
190 println!("\rTesting {value:?} ✓");
191 }
192
193 Ok(())
194 }
195
196 #[test]
197 fn parse_location() -> Result<()> {
198 let mut config = Config::default();
199 config.user.push("test".to_string());
200 config
201 .custom_directories
202 .insert("test".to_string(), "/usr/local/test".to_string());
203
204 let mut values: Vec<(&str, Result<(String, LocationRoot)>)> = Vec::new();
205 values.push((
206 "~/.config/nvim",
207 Ok((
208 ".config/nvim".to_string(),
209 LocationRoot::User("test".to_string()),
210 )),
211 ));
212 values.push((
213 "u:test/.config/nvim",
214 Ok((
215 ".config/nvim".to_string(),
216 LocationRoot::User("test".to_string()),
217 )),
218 ));
219 values.push((
220 "r:/.config/nvim",
221 Ok((".config/nvim".to_string(), LocationRoot::Root)),
222 ));
223 values.push((
224 "r:/.config/nvim",
225 Ok((".config/nvim".to_string(), LocationRoot::Root)),
226 ));
227 values.push((
228 "s:/.config/nvim",
229 Ok((".config/nvim".to_string(), LocationRoot::SystemSettings)),
230 ));
231 values.push((
232 "c:test/.config/nvim",
233 Ok((
234 ".config/nvim".to_string(),
235 LocationRoot::Custom("/usr/local/test".to_string()),
236 )),
237 ));
238
239 for value in values {
240 print!("Testing {value:?}");
241 assert_eq!(PathInfo::parse_location(&value.0, &config), value.1);
242 println!("\rTesting {value:?} ✓");
243 }
244 Ok(())
245 }
246}