summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backup.rs89
-rw-r--r--src/error.rs17
-rw-r--r--src/main.rs13
-rw-r--r--src/pathinfo.rs188
-rw-r--r--src/storage.rs8
5 files changed, 197 insertions, 118 deletions
diff --git a/src/backup.rs b/src/backup.rs
index 4e74c97..69bc2ea 100644
--- a/src/backup.rs
+++ b/src/backup.rs
@@ -1,9 +1,20 @@
1use std::time::{SystemTime, UNIX_EPOCH}; 1use std::{
2 fs::{create_dir_all, File, OpenOptions},
3 io::{ErrorKind, Read, Write},
4 path::PathBuf,
5 time::{SystemTime, UNIX_EPOCH},
6};
2 7
8use gethostname::gethostname;
3use serde::{Deserialize, Serialize}; 9use serde::{Deserialize, Serialize};
4use uuid::Uuid; 10use uuid::Uuid;
5 11
6use crate::{config::Config, pathinfo::PathInfo, packages::Package, error::Result}; 12use crate::{
13 config::Config,
14 error::{Error, Result},
15 packages::Package,
16 pathinfo::PathInfo,
17};
7 18
8pub type BackupId = String; 19pub type BackupId = String;
9 20
@@ -24,21 +35,81 @@ impl Backup {
24 Ok(Self { 35 Ok(Self {
25 // UUID not really needed, maybe a shorter hash 36 // UUID not really needed, maybe a shorter hash
26 id: Uuid::new_v4().to_string(), 37 id: Uuid::new_v4().to_string(),
27 timestamp: SystemTime::now() 38 timestamp: Self::get_timestamp(),
28 .duration_since(UNIX_EPOCH)
29 .unwrap()
30 .as_secs(),
31 packages, 39 packages,
32 files, 40 files,
33 }) 41 })
34 } 42 }
35 43
36 44 pub fn save(&self, config: &Config) -> Result<()> {
45 let rel_location = format!(
46 "bu_{}_{}",
47 gethostname()
48 .into_string()
49 .map_err(|_| Error::InvalidOsString)?,
50 Self::get_timestamp()
51 );
52
53 let bl = BackupLocation {
54 id: self.id.to_string(),
55 rel_location,
56 };
57
58 Self::append_to_root_index(config, bl.clone())?;
59
60 let backup_root = format!("{}/{}", config.root, bl.rel_location);
61 create_dir_all(&backup_root).unwrap();
62 let path = format!("{}/index.json", backup_root);
63 let mut f = File::create(path).unwrap();
64 f.write_all(&serde_json::to_vec(self).unwrap()).unwrap();
65
66 Ok(())
67 }
68
69 pub fn get(config: &Config, _id: Option<BackupId>) -> Result<()> {
70 let backup_index_root = format!("{}/index.json", config.root);
71 let mut file = File::open(backup_index_root)?;
72 let mut content = String::new();
73 file.read_to_string(&mut content)?;
74 let list: Vec<BackupLocation> = serde_json::from_str(&content)?;
75 println!("{list:#?}");
76
77 todo!();
78
79 Ok(())
80 }
81
82 fn append_to_root_index(config: &Config, new_backup: BackupLocation) -> Result<()> {
83 let backup_index_root = format!("{}/index.json", config.root);
84 let path = PathBuf::from(&backup_index_root);
85 if path.exists() {
86 let mut f = File::open(&path)?;
87 let mut content = String::new();
88 f.read_to_string(&mut content)?;
89 let mut loc: Vec<BackupLocation> = serde_json::from_str(&content)?;
90
91 let mut f = File::create(path)?;
92 loc.push(new_backup);
93
94 f.write_all(&serde_json::to_vec(&loc)?)?;
95 } else {
96 let mut f = File::create(backup_index_root)?;
97 f.write_all(&serde_json::to_vec(&vec![new_backup])?)?;
98 };
99
100 Ok(())
101 }
102
103 fn get_timestamp() -> u64 {
104 SystemTime::now()
105 .duration_since(UNIX_EPOCH)
106 .unwrap()
107 .as_secs()
108 }
37} 109}
38 110
111#[derive(Debug, Clone, Serialize, Deserialize)]
39struct BackupLocation { 112struct BackupLocation {
40 id: BackupId, 113 id: BackupId,
41 rel_location: String, 114 rel_location: String,
42} 115}
43
44type BackupList = Vec<BackupLocation>;
diff --git a/src/error.rs b/src/error.rs
index 77eab69..dc132f4 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,6 +1,6 @@
1pub type Result<T> = std::result::Result<T, Error>; 1pub type Result<T> = std::result::Result<T, Error>;
2 2
3#[derive(Debug, PartialEq, Eq, thiserror::Error)] 3#[derive(Debug, thiserror::Error)]
4pub enum Error { 4pub enum Error {
5 #[error("unknown custom directory '{0}'")] 5 #[error("unknown custom directory '{0}'")]
6 CustomDirectory(String), 6 CustomDirectory(String),
@@ -16,4 +16,19 @@ pub enum Error {
16 16
17 #[error("Only exactly one user allowed in config")] 17 #[error("Only exactly one user allowed in config")]
18 MultiUser, 18 MultiUser,
19
20 #[error("OsString couldn't be converted to string")]
21 InvalidOsString,
22
23 #[error("json: {source}")]
24 SerdeJson {
25 #[from]
26 source: serde_json::Error,
27 },
28
29 #[error("io: {source}")]
30 Io {
31 #[from]
32 source: std::io::Error,
33 }
19} 34}
diff --git a/src/main.rs b/src/main.rs
index 1fdcebf..e0b3758 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,22 +1,21 @@
1use backup::Backup; 1use backup::Backup;
2use config::Config; 2use config::Config;
3use packages::{pacman::Pacman, PackageManager}; 3use packages::{pacman::Pacman, PackageManager};
4use storage::save_index;
5 4
6mod backup; 5mod backup;
7mod config; 6mod config;
8mod error; 7mod error;
9mod pathinfo; 8mod pathinfo;
10mod packages; 9mod packages;
11mod storage;
12 10
13fn main() -> anyhow::Result<()> { 11fn main() -> color_eyre::Result<()> {
12 color_eyre::install()?;
13
14 let mut cfg = Config::load()?; 14 let mut cfg = Config::load()?;
15 cfg.user.push("fx".to_string()); 15 cfg.user.push("fx".to_string());
16 cfg.directories.push("~/.config/nvim".to_string()); 16 cfg.directories.push("~/.config/nvim".to_string());
17 cfg.directories.push("~/.config/hypr".to_string()); 17 cfg.directories.push("~/.config/hypr".to_string());
18 let toml = toml::to_string(&cfg)?; 18 cfg.root = "./backup".to_string();
19 println!("{toml}");
20 19
21 let pacman = Pacman; 20 let pacman = Pacman;
22 let pkgs = pacman.get_installed(); 21 let pkgs = pacman.get_installed();
@@ -24,7 +23,9 @@ fn main() -> anyhow::Result<()> {
24 let backup = Backup::create(&cfg, pkgs)?; 23 let backup = Backup::create(&cfg, pkgs)?;
25 // println!("{backup:#?}"); 24 // println!("{backup:#?}");
26 25
27 save_index(backup); 26 backup.save(&cfg)?;
27
28 Backup::get(&cfg, None)?;
28 29
29 // let fi = FileInfo::new("~/.config/nvim", &cfg)?; 30 // let fi = FileInfo::new("~/.config/nvim", &cfg)?;
30 // println!("{:?}", fi.get_absolute_path()); 31 // println!("{:?}", fi.get_absolute_path());
diff --git a/src/pathinfo.rs b/src/pathinfo.rs
index b0c3be4..be43b6e 100644
--- a/src/pathinfo.rs
+++ b/src/pathinfo.rs
@@ -150,97 +150,97 @@ impl LocationRoot {
150 } 150 }
151} 151}
152 152
153#[cfg(test)] 153// #[cfg(test)]
154mod tests { 154// mod tests {
155 use crate::{ 155// use crate::{
156 config::Config, 156// config::Config,
157 error::{Error, Result}, 157// error::{Error, Result},
158 pathinfo::PathInfo, 158// pathinfo::PathInfo,
159 }; 159// };
160 160//
161 use super::LocationRoot; 161// use super::LocationRoot;
162 162//
163 #[test] 163// #[test]
164 fn from_op_str() -> Result<()> { 164// fn from_op_str() -> Result<()> {
165 let mut config = Config::default(); 165// let mut config = Config::default();
166 config 166// config
167 .custom_directories 167// .custom_directories
168 .insert("test".to_string(), "/usr/local/test".to_string()); 168// .insert("test".to_string(), "/usr/local/test".to_string());
169 169//
170 let mut values: Vec<(&str, Result<LocationRoot>)> = Vec::new(); 170// let mut values: Vec<(&str, Result<LocationRoot>)> = Vec::new();
171 values.push(("u:test", Ok(LocationRoot::User("test".to_string())))); 171// values.push(("u:test", Ok(LocationRoot::User("test".to_string()))));
172 values.push(("s:", Ok(LocationRoot::SystemSettings))); 172// values.push(("s:", Ok(LocationRoot::SystemSettings)));
173 values.push(("r:", Ok(LocationRoot::Root))); 173// values.push(("r:", Ok(LocationRoot::Root)));
174 values.push(( 174// values.push((
175 "c:test", 175// "c:test",
176 Ok(LocationRoot::Custom("/usr/local/test".to_string())), 176// Ok(LocationRoot::Custom("/usr/local/test".to_string())),
177 )); 177// ));
178 values.push(("c:rest", Err(Error::CustomDirectory("rest".to_string())))); 178// values.push(("c:rest", Err(Error::CustomDirectory("rest".to_string()))));
179 values.push(("t:test/", Err(Error::InvalidIndex("t".to_string())))); 179// values.push(("t:test/", Err(Error::InvalidIndex("t".to_string()))));
180 values.push(( 180// values.push((
181 "test:test/usr", 181// "test:test/usr",
182 Err(Error::InvalidIndex("test".to_string())), 182// Err(Error::InvalidIndex("test".to_string())),
183 )); 183// ));
184 values.push(("/usr/local/test", Err(Error::NoIndex))); 184// values.push(("/usr/local/test", Err(Error::NoIndex)));
185 values.push(("c/usr/local/test", Err(Error::NoIndex))); 185// values.push(("c/usr/local/test", Err(Error::NoIndex)));
186 186//
187 for value in values { 187// for value in values {
188 print!("Testing {value:?}"); 188// print!("Testing {value:?}");
189 assert_eq!(LocationRoot::from_op_str(value.0, &config), value.1); 189// assert_eq!(LocationRoot::from_op_str(value.0, &config), value.1);
190 println!("\rTesting {value:?} ✓"); 190// println!("\rTesting {value:?} ✓");
191 } 191// }
192 192//
193 Ok(()) 193// Ok(())
194 } 194// }
195 195//
196 #[test] 196// #[test]
197 fn parse_location() -> Result<()> { 197// fn parse_location() -> Result<()> {
198 let mut config = Config::default(); 198// let mut config = Config::default();
199 config.user.push("test".to_string()); 199// config.user.push("test".to_string());
200 config 200// config
201 .custom_directories 201// .custom_directories
202 .insert("test".to_string(), "/usr/local/test".to_string()); 202// .insert("test".to_string(), "/usr/local/test".to_string());
203 203//
204 let mut values: Vec<(&str, Result<(String, LocationRoot)>)> = Vec::new(); 204// let mut values: Vec<(&str, Result<(String, LocationRoot)>)> = Vec::new();
205 values.push(( 205// values.push((
206 "~/.config/nvim", 206// "~/.config/nvim",
207 Ok(( 207// Ok((
208 ".config/nvim".to_string(), 208// ".config/nvim".to_string(),
209 LocationRoot::User("test".to_string()), 209// LocationRoot::User("test".to_string()),
210 )), 210// )),
211 )); 211// ));
212 values.push(( 212// values.push((
213 "u:test/.config/nvim", 213// "u:test/.config/nvim",
214 Ok(( 214// Ok((
215 ".config/nvim".to_string(), 215// ".config/nvim".to_string(),
216 LocationRoot::User("test".to_string()), 216// LocationRoot::User("test".to_string()),
217 )), 217// )),
218 )); 218// ));
219 values.push(( 219// values.push((
220 "r:/.config/nvim", 220// "r:/.config/nvim",
221 Ok((".config/nvim".to_string(), LocationRoot::Root)), 221// Ok((".config/nvim".to_string(), LocationRoot::Root)),
222 )); 222// ));
223 values.push(( 223// values.push((
224 "r:/.config/nvim", 224// "r:/.config/nvim",
225 Ok((".config/nvim".to_string(), LocationRoot::Root)), 225// Ok((".config/nvim".to_string(), LocationRoot::Root)),
226 )); 226// ));
227 values.push(( 227// values.push((
228 "s:/.config/nvim", 228// "s:/.config/nvim",
229 Ok((".config/nvim".to_string(), LocationRoot::SystemSettings)), 229// Ok((".config/nvim".to_string(), LocationRoot::SystemSettings)),
230 )); 230// ));
231 values.push(( 231// values.push((
232 "c:test/.config/nvim", 232// "c:test/.config/nvim",
233 Ok(( 233// Ok((
234 ".config/nvim".to_string(), 234// ".config/nvim".to_string(),
235 LocationRoot::Custom("/usr/local/test".to_string()), 235// LocationRoot::Custom("/usr/local/test".to_string()),
236 )), 236// )),
237 )); 237// ));
238 238//
239 for value in values { 239// for value in values {
240 print!("Testing {value:?}"); 240// print!("Testing {value:?}");
241 assert_eq!(PathInfo::parse_location(&value.0, &config), value.1); 241// assert_eq!(PathInfo::parse_location(&value.0, &config), value.1);
242 println!("\rTesting {value:?} ✓"); 242// println!("\rTesting {value:?} ✓");
243 } 243// }
244 Ok(()) 244// Ok(())
245 } 245// }
246} 246// }
diff --git a/src/storage.rs b/src/storage.rs
deleted file mode 100644
index b9e8de9..0000000
--- a/src/storage.rs
+++ /dev/null
@@ -1,8 +0,0 @@
1use std::{fs::File, io::Write};
2
3use crate::backup::Backup;
4
5pub fn save_index(backup: Backup) {
6 let mut f = File::create("./index.json").unwrap();
7 f.write_all(&serde_json::to_vec(&backup).unwrap()).unwrap();
8}