summaryrefslogtreecommitdiff
path: root/src/backup.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/backup.rs')
-rw-r--r--src/backup.rs126
1 files changed, 76 insertions, 50 deletions
diff --git a/src/backup.rs b/src/backup.rs
index 8cc94f1..a643cb2 100644
--- a/src/backup.rs
+++ b/src/backup.rs
@@ -5,7 +5,6 @@ use std::{
5 time::{SystemTime, UNIX_EPOCH}, 5 time::{SystemTime, UNIX_EPOCH},
6}; 6};
7 7
8use gethostname::gethostname;
9use serde::{Deserialize, Serialize}; 8use serde::{Deserialize, Serialize};
10use uuid::Uuid; 9use uuid::Uuid;
11 10
@@ -20,10 +19,11 @@ pub type BackupId = String;
20 19
21#[derive(Debug, Serialize, Deserialize)] 20#[derive(Debug, Serialize, Deserialize)]
22pub struct Backup { 21pub struct Backup {
23 id: String, 22 pub id: String,
24 timestamp: u64, 23 timestamp: u64,
25 packages: Vec<Package>, 24 packages: Vec<Package>,
26 files: Vec<PathInfo>, 25 pub files: Vec<PathInfo>,
26 device: String,
27} 27}
28 28
29impl Backup { 29impl Backup {
@@ -33,63 +33,82 @@ impl Backup {
33 files.push(PathInfo::from_path(config, dir)?); 33 files.push(PathInfo::from_path(config, dir)?);
34 } 34 }
35 Ok(Self { 35 Ok(Self {
36 // UUID not really needed, maybe a shorter hash 36 // TODO: UUID not really needed, maybe a shorter hash
37 id: Uuid::new_v4().to_string(), 37 id: Uuid::new_v4().to_string(),
38 timestamp: Self::get_timestamp(), 38 timestamp: Self::get_timestamp(),
39 packages, 39 packages,
40 files, 40 files,
41 device: config.device.clone(),
41 }) 42 })
42 } 43 }
43 44
44 pub fn save(&self, config: &Config) -> Result<()> { 45 pub fn save(&self, config: &Config) -> Result<()> {
45 let rel_location = format!( 46 println!("Save Backup {:?}", self.get_location(config));
46 "{}_{}", 47 // println!("{self:#?}");
47 gethostname() 48 self.get_location(config).append_to_root(config)?;
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 49
60 let backup_root = format!("{}/{}", config.root, bl.rel_location); 50 let backup_root = self.get_location(config).get_absolute_dir(config);
61 create_dir_all(&backup_root).unwrap(); 51 create_dir_all(&backup_root).unwrap();
62 let path = format!("{}/index.json", backup_root); 52 let path = format!("{}/index.json", backup_root);
63 let mut f = File::create(path).unwrap(); 53 let mut f = File::create(path).unwrap();
64 f.write_all(&serde_json::to_vec(self).unwrap()).unwrap(); 54 f.write_all(&serde_json::to_vec(self).unwrap()).unwrap();
65 55
56 for path in &self.files {
57 path.save(&backup_root)?;
58 }
59
66 Ok(()) 60 Ok(())
67 } 61 }
68 62
69 pub fn get_index(config: &Config, id: Option<BackupId>) -> Result<Self> { 63 pub fn get_last(config: &Config) -> Result<Option<Self>> {
70 let backup_index_root = format!("{}/index.json", config.root); 64 let backup_index_root = format!("{}/index.json", config.root);
71 let list: Vec<BackupLocation> = Self::get_json_content(&backup_index_root)?; 65 let list: Vec<BackupLocation> = match Self::get_json_content(&backup_index_root) {
72 println!("{list:#?}"); 66 Ok(list) => list,
73 67 Err(err) => {
74 let index_loc = if let Some(id) = id { 68 if err.to_string() == "io: No such file or directory (os error 2)" {
75 list.iter() 69 return Ok(None);
76 .find(|bl| bl.id == id) 70 };
77 .ok_or(Error::BackupNotFound)? 71 return Err(err);
78 .rel_location 72 }
79 .clone()
80 } else {
81 list.last()
82 .ok_or(Error::BackupNotFound)?
83 .rel_location
84 .clone()
85 }; 73 };
86 74
75 Ok(Some(Self::from_index(
76 config,
77 list.last().ok_or(Error::BackupNotFound)?.id.clone(),
78 )?))
79 }
80
81 pub fn from_index(config: &Config, id: BackupId) -> Result<Self> {
82 let backup_index_root = format!("{}/index.json", config.root);
83 let list: Vec<BackupLocation> = Self::get_json_content(&backup_index_root)?;
84 let index_loc = list
85 .iter()
86 .find(|bl| bl.id == id)
87 .ok_or(Error::BackupNotFound)?
88 .rel_location
89 .clone();
90
87 let path = format!("{}/{index_loc}/index.json", config.root); 91 let path = format!("{}/{index_loc}/index.json", config.root);
88 let index_file: Self = Self::get_json_content(&path)?; 92 let index_file: Self = Self::get_json_content(&path)?;
89 93
90 Ok(index_file) 94 Ok(index_file)
91 } 95 }
92 96
97 pub fn get_location(&self, config: &Config) -> BackupLocation {
98 let rel_location = format!("{}_{}", config.device, self.timestamp);
99
100 BackupLocation {
101 id: self.id.to_string(),
102 rel_location,
103 }
104 }
105
106 pub fn get_absolute_file_location(&self, config: &Config, rel_location: &str) -> String {
107 let loc = self.get_location(config).get_absolute_dir(config);
108
109 format!("{}/{}", loc, rel_location)
110 }
111
93 fn get_json_content<T: for<'a> Deserialize<'a>>(path: &str) -> Result<T> { 112 fn get_json_content<T: for<'a> Deserialize<'a>>(path: &str) -> Result<T> {
94 let mut file = File::open(path)?; 113 let mut file = File::open(path)?;
95 let mut content = String::new(); 114 let mut content = String::new();
@@ -97,7 +116,26 @@ impl Backup {
97 Ok(serde_json::from_str(&content)?) 116 Ok(serde_json::from_str(&content)?)
98 } 117 }
99 118
100 fn append_to_root_index(config: &Config, new_backup: BackupLocation) -> Result<()> { 119 fn get_timestamp() -> u64 {
120 SystemTime::now()
121 .duration_since(UNIX_EPOCH)
122 .unwrap()
123 .as_secs()
124 }
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct BackupLocation {
129 id: BackupId,
130 rel_location: String,
131}
132
133impl BackupLocation {
134 pub fn get_absolute_dir(&self, config: &Config) -> String {
135 format!("{}/{}", config.root, self.rel_location)
136 }
137
138 pub fn append_to_root(&self, config: &Config) -> Result<()> {
101 let backup_index_root = format!("{}/index.json", config.root); 139 let backup_index_root = format!("{}/index.json", config.root);
102 let path = PathBuf::from(&backup_index_root); 140 let path = PathBuf::from(&backup_index_root);
103 if path.exists() { 141 if path.exists() {
@@ -107,27 +145,15 @@ impl Backup {
107 let mut loc: Vec<BackupLocation> = serde_json::from_str(&content)?; 145 let mut loc: Vec<BackupLocation> = serde_json::from_str(&content)?;
108 146
109 let mut f = File::create(path)?; 147 let mut f = File::create(path)?;
110 loc.push(new_backup); 148 loc.push(self.clone());
111 149
112 f.write_all(&serde_json::to_vec(&loc)?)?; 150 f.write_all(&serde_json::to_vec(&loc)?)?;
113 } else { 151 } else {
152 create_dir_all(&config.root).unwrap();
114 let mut f = File::create(backup_index_root)?; 153 let mut f = File::create(backup_index_root)?;
115 f.write_all(&serde_json::to_vec(&vec![new_backup])?)?; 154 f.write_all(&serde_json::to_vec(&vec![self])?)?;
116 }; 155 };
117 156
118 Ok(()) 157 Ok(())
119 } 158 }
120
121 fn get_timestamp() -> u64 {
122 SystemTime::now()
123 .duration_since(UNIX_EPOCH)
124 .unwrap()
125 .as_secs()
126 }
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
130struct BackupLocation {
131 id: BackupId,
132 rel_location: String,
133} 159}