summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backup.rs19
-rw-r--r--src/cli.rs5
-rw-r--r--src/error.rs26
-rw-r--r--src/main.rs9
-rw-r--r--src/pathinfo.rs44
5 files changed, 64 insertions, 39 deletions
diff --git a/src/backup.rs b/src/backup.rs
index f9de139..3d07ace 100644
--- a/src/backup.rs
+++ b/src/backup.rs
@@ -45,9 +45,10 @@ impl Backup {
45 45
46 pub fn save(&self, config: &Config) -> Result<()> { 46 pub fn save(&self, config: &Config) -> Result<()> {
47 info!("Save Backup {:?}", self.get_location(config)); 47 info!("Save Backup {:?}", self.get_location(config));
48 self.get_location(config).append_to_root(config)?; 48 let loc = self.get_location(config);
49 loc.append_to_root(config)?;
49 50
50 let backup_root = self.get_location(config).get_absolute_dir(config); 51 let backup_root = loc.get_absolute_dir(config);
51 create_dir_all(&backup_root).unwrap(); 52 create_dir_all(&backup_root).unwrap();
52 let path = format!("{backup_root}/index.json"); 53 let path = format!("{backup_root}/index.json");
53 let mut f = File::create(path).unwrap(); 54 let mut f = File::create(path).unwrap();
@@ -66,7 +67,7 @@ impl Backup {
66 let list: Vec<IndexEntry> = match Self::get_json_content(&backup_index_root) { 67 let list: Vec<IndexEntry> = match Self::get_json_content(&backup_index_root) {
67 Ok(list) => list, 68 Ok(list) => list,
68 Err(err) => { 69 Err(err) => {
69 if err.to_string() == "io: No such file or directory (os error 2)" { 70 if err.to_string() == "No such file or directory (os error 2)" {
70 return Ok(None); 71 return Ok(None);
71 }; 72 };
72 return Err(err); 73 return Err(err);
@@ -112,8 +113,16 @@ impl Backup {
112 format!("{loc}/{rel_location}") 113 format!("{loc}/{rel_location}")
113 } 114 }
114 115
115 pub fn restore(&self) { 116 pub fn restore(&self, config: &Config) -> Result<()> {
116 todo!() 117 info!(?self.id, ?self.timestamp, "Restore Backup");
118
119 let backup_root = self.get_location(config).get_absolute_dir(config);
120
121 for path in &self.files {
122 path.restore(config, &backup_root)?;
123 }
124
125 Ok(())
117 } 126 }
118 127
119 fn get_json_content<T: for<'a> Deserialize<'a>>(path: &str) -> Result<T> { 128 fn get_json_content<T: for<'a> Deserialize<'a>>(path: &str) -> Result<T> {
diff --git a/src/cli.rs b/src/cli.rs
index 6ffe03f..1b62a84 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -20,6 +20,9 @@ pub enum Subcommands {
20 #[arg(short, long)] 20 #[arg(short, long)]
21 package_manager: Option<Manager>, 21 package_manager: Option<Manager>,
22 }, 22 },
23 Restore, 23 Restore {
24 #[arg(short, long)]
25 package_install: bool
26 },
24} 27}
25 28
diff --git a/src/error.rs b/src/error.rs
index e24c3b1..cb57e99 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -24,21 +24,13 @@ pub enum Error {
24 #[error("Unsupported os/distro")] 24 #[error("Unsupported os/distro")]
25 Unsupported, 25 Unsupported,
26 26
27 #[error("json: {source}")] 27 // Deps
28 SerdeJson { 28 #[error(transparent)]
29 #[from] 29 SerdeJson(#[from] serde_json::Error),
30 source: serde_json::Error, 30
31 }, 31 #[error(transparent)]
32 32 TomlSerialize(#[from] toml::ser::Error),
33 #[error("toml serializer: {source}")] 33
34 TomlSerialize { 34 #[error(transparent)]
35 #[from] 35 Io(#[from] std::io::Error),
36 source: toml::ser::Error,
37 },
38
39 #[error("io: {source}")]
40 Io {
41 #[from]
42 source: std::io::Error,
43 },
44} 36}
diff --git a/src/main.rs b/src/main.rs
index 7393af9..487d095 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -46,13 +46,16 @@ fn main() -> color_eyre::Result<()> {
46 let backup = Backup::create(&config, package_manager)?; 46 let backup = Backup::create(&config, package_manager)?;
47 backup.save(&config)?; 47 backup.save(&config)?;
48 } 48 }
49 Subcommands::Restore => { 49 Subcommands::Restore { package_install } => {
50 let Some(last_backup) = Backup::get_last(&config)? else { 50 let Some(last_backup) = Backup::get_last(&config)? else {
51 return Err(Error::BackupNotFound)?; 51 return Err(Error::BackupNotFound)?;
52 }; 52 };
53 53
54 last_backup.packages.install()?; 54 if package_install {
55 last_backup.restore(); 55 last_backup.packages.install()?;
56 }
57
58 last_backup.restore(&config)?;
56 } 59 }
57 }; 60 };
58 Ok(()) 61 Ok(())
diff --git a/src/pathinfo.rs b/src/pathinfo.rs
index 03b8a6b..1231ff8 100644
--- a/src/pathinfo.rs
+++ b/src/pathinfo.rs
@@ -6,7 +6,7 @@ use std::{
6}; 6};
7 7
8use serde::{Deserialize, Serialize}; 8use serde::{Deserialize, Serialize};
9use tracing::info; 9use tracing::{debug, info};
10 10
11use crate::{ 11use crate::{
12 backup::{Backup, Id}, 12 backup::{Backup, Id},
@@ -186,6 +186,33 @@ impl PathInfo {
186 Ok(()) 186 Ok(())
187 } 187 }
188 188
189 pub fn restore(&self, config: &Config, backup_root: &str) -> Result<()> {
190 if self.is_file {
191 info!(?self.rel_location, "Restore File");
192 let backup_path = if let Some(last_modified) = self.last_modified.clone() {
193 let backup = Backup::from_index(config, &last_modified)?;
194 &backup.get_location(config).get_absolute_dir(config)
195 } else {
196 backup_root
197 };
198 let backup_loc = format!("{}/{}", backup_path, self.rel_location);
199 let system_loc = self.get_absolute_path();
200 debug!(?backup_loc, ?system_loc, "copy");
201
202 if let Some(parents) = system_loc.parent() {
203 create_dir_all(parents)?;
204 }
205
206 std::fs::copy(backup_loc, system_loc)?;
207 } else {
208 for path in &self.children {
209 path.restore(config, backup_root)?;
210 }
211 }
212
213 Ok(())
214 }
215
189 fn get_abs_path(location_root: &str, rel_location: &str) -> PathBuf { 216 fn get_abs_path(location_root: &str, rel_location: &str) -> PathBuf {
190 let path = format!("{location_root}/{rel_location}"); 217 let path = format!("{location_root}/{rel_location}");
191 PathBuf::from(path) 218 PathBuf::from(path)
@@ -196,10 +223,7 @@ impl PathInfo {
196 return Err(Error::InvalidDirectory(value.to_string())); 223 return Err(Error::InvalidDirectory(value.to_string()));
197 }; 224 };
198 if split.0.starts_with('~') { 225 if split.0.starts_with('~') {
199 return Ok(( 226 return Ok((split.1.to_string(), LocationRoot::User));
200 split.1.to_string(),
201 LocationRoot::User,
202 ));
203 }; 227 };
204 Ok(( 228 Ok((
205 split.1.to_string(), 229 split.1.to_string(),
@@ -330,17 +354,11 @@ mod tests {
330 let mut values_ok: Vec<(&str, (String, LocationRoot))> = Vec::new(); 354 let mut values_ok: Vec<(&str, (String, LocationRoot))> = Vec::new();
331 values_ok.push(( 355 values_ok.push((
332 "~/.config/nvim", 356 "~/.config/nvim",
333 ( 357 (".config/nvim".to_string(), LocationRoot::User),
334 ".config/nvim".to_string(),
335 LocationRoot::User,
336 ),
337 )); 358 ));
338 values_ok.push(( 359 values_ok.push((
339 "u:test/.config/nvim", 360 "u:test/.config/nvim",
340 ( 361 (".config/nvim".to_string(), LocationRoot::User),
341 ".config/nvim".to_string(),
342 LocationRoot::User,
343 ),
344 )); 362 ));
345 values_ok.push(( 363 values_ok.push((
346 "r:/.config/nvim", 364 "r:/.config/nvim",