summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backup.rs28
-rw-r--r--src/config.rs7
-rw-r--r--src/main.rs47
-rw-r--r--src/packages.rs2
-rw-r--r--src/packages/pacman.rs18
-rw-r--r--src/packages/portage.rs5
-rw-r--r--src/pathinfo.rs32
7 files changed, 80 insertions, 59 deletions
diff --git a/src/backup.rs b/src/backup.rs
index 675f020..e463593 100644
--- a/src/backup.rs
+++ b/src/backup.rs
@@ -6,6 +6,7 @@ use std::{
6}; 6};
7 7
8use serde::{Deserialize, Serialize}; 8use serde::{Deserialize, Serialize};
9use tracing::info;
9use uuid::Uuid; 10use uuid::Uuid;
10 11
11use crate::{ 12use crate::{
@@ -15,7 +16,7 @@ use crate::{
15 pathinfo::PathInfo, 16 pathinfo::PathInfo,
16}; 17};
17 18
18pub type BackupId = String; 19pub type Id = String;
19 20
20#[derive(Debug, Serialize, Deserialize)] 21#[derive(Debug, Serialize, Deserialize)]
21pub struct Backup { 22pub struct Backup {
@@ -43,13 +44,12 @@ impl Backup {
43 } 44 }
44 45
45 pub fn save(&self, config: &Config) -> Result<()> { 46 pub fn save(&self, config: &Config) -> Result<()> {
46 println!("Save Backup {:?}", self.get_location(config)); 47 info!("Save Backup {:?}", self.get_location(config));
47 // println!("{self:#?}");
48 self.get_location(config).append_to_root(config)?; 48 self.get_location(config).append_to_root(config)?;
49 49
50 let backup_root = self.get_location(config).get_absolute_dir(config); 50 let backup_root = self.get_location(config).get_absolute_dir(config);
51 create_dir_all(&backup_root).unwrap(); 51 create_dir_all(&backup_root).unwrap();
52 let path = format!("{}/index.json", backup_root); 52 let path = format!("{backup_root}/index.json");
53 let mut f = File::create(path).unwrap(); 53 let mut f = File::create(path).unwrap();
54 f.write_all(&serde_json::to_vec(self).unwrap()).unwrap(); 54 f.write_all(&serde_json::to_vec(self).unwrap()).unwrap();
55 55
@@ -62,7 +62,7 @@ impl Backup {
62 62
63 pub fn get_last(config: &Config) -> Result<Option<Self>> { 63 pub fn get_last(config: &Config) -> Result<Option<Self>> {
64 let backup_index_root = format!("{}/index.json", config.root); 64 let backup_index_root = format!("{}/index.json", config.root);
65 let list: Vec<BackupLocation> = match Self::get_json_content(&backup_index_root) { 65 let list: Vec<IndexEntry> = match Self::get_json_content(&backup_index_root) {
66 Ok(list) => list, 66 Ok(list) => list,
67 Err(err) => { 67 Err(err) => {
68 if err.to_string() == "io: No such file or directory (os error 2)" { 68 if err.to_string() == "io: No such file or directory (os error 2)" {
@@ -78,9 +78,9 @@ impl Backup {
78 )?)) 78 )?))
79 } 79 }
80 80
81 pub fn from_index(config: &Config, id: &BackupId) -> Result<Self> { 81 pub fn from_index(config: &Config, id: &Id) -> Result<Self> {
82 let backup_index_root = format!("{}/index.json", config.root); 82 let backup_index_root = format!("{}/index.json", config.root);
83 let list: Vec<BackupLocation> = Self::get_json_content(&backup_index_root)?; 83 let list: Vec<IndexEntry> = Self::get_json_content(&backup_index_root)?;
84 let index_loc = list 84 let index_loc = list
85 .iter() 85 .iter()
86 .find(|bl| &bl.id == id) 86 .find(|bl| &bl.id == id)
@@ -94,10 +94,10 @@ impl Backup {
94 Ok(index_file) 94 Ok(index_file)
95 } 95 }
96 96
97 pub fn get_location(&self, config: &Config) -> BackupLocation { 97 pub fn get_location(&self, config: &Config) -> IndexEntry {
98 let rel_location = format!("{}_{}", config.device, self.timestamp); 98 let rel_location = format!("{}_{}", config.device, self.timestamp);
99 99
100 BackupLocation { 100 IndexEntry {
101 id: self.id.to_string(), 101 id: self.id.to_string(),
102 rel_location, 102 rel_location,
103 } 103 }
@@ -106,7 +106,7 @@ impl Backup {
106 pub fn get_absolute_file_location(&self, config: &Config, rel_location: &str) -> String { 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); 107 let loc = self.get_location(config).get_absolute_dir(config);
108 108
109 format!("{}/{}", loc, rel_location) 109 format!("{loc}/{rel_location}")
110 } 110 }
111 111
112 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> {
@@ -125,12 +125,12 @@ impl Backup {
125} 125}
126 126
127#[derive(Debug, Clone, Serialize, Deserialize)] 127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct BackupLocation { 128pub struct IndexEntry {
129 id: BackupId, 129 id: Id,
130 rel_location: String, 130 rel_location: String,
131} 131}
132 132
133impl BackupLocation { 133impl IndexEntry {
134 pub fn get_absolute_dir(&self, config: &Config) -> String { 134 pub fn get_absolute_dir(&self, config: &Config) -> String {
135 format!("{}/{}", config.root, self.rel_location) 135 format!("{}/{}", config.root, self.rel_location)
136 } 136 }
@@ -142,7 +142,7 @@ impl BackupLocation {
142 let mut f = File::open(&path)?; 142 let mut f = File::open(&path)?;
143 let mut content = String::new(); 143 let mut content = String::new();
144 f.read_to_string(&mut content)?; 144 f.read_to_string(&mut content)?;
145 let mut loc: Vec<BackupLocation> = serde_json::from_str(&content)?; 145 let mut loc: Vec<IndexEntry> = serde_json::from_str(&content)?;
146 146
147 let mut f = File::create(path)?; 147 let mut f = File::create(path)?;
148 loc.push(self.clone()); 148 loc.push(self.clone());
diff --git a/src/config.rs b/src/config.rs
index 439c17c..13dd0e4 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,5 +1,6 @@
1use config::{File, Map}; 1use config::{File, Map};
2use serde::{Deserialize, Serialize}; 2use serde::{Deserialize, Serialize};
3use tracing::{debug, trace};
3 4
4#[derive(Debug, Serialize, Deserialize)] 5#[derive(Debug, Serialize, Deserialize)]
5#[serde(default)] 6#[serde(default)]
@@ -27,11 +28,15 @@ impl Default for Config {
27 28
28impl Config { 29impl Config {
29 pub fn load() -> Result<Self, config::ConfigError> { 30 pub fn load() -> Result<Self, config::ConfigError> {
31 debug!("load config");
30 let config = config::Config::builder() 32 let config = config::Config::builder()
31 .add_source(File::with_name("config.toml").required(false)) 33 .add_source(File::with_name("config.toml").required(false))
32 .add_source(config::Environment::with_prefix("FXBAUP").separator("_")) 34 .add_source(config::Environment::with_prefix("FXBAUP").separator("_"))
33 .build()?; 35 .build()?;
34 36
35 config.try_deserialize() 37 let cfg = config.try_deserialize();
38 trace!(?cfg, "loaded config");
39
40 cfg
36 } 41 }
37} 42}
diff --git a/src/main.rs b/src/main.rs
index e67e535..1284e0c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,8 @@
1use backup::Backup; 1use backup::Backup;
2use config::Config; 2use config::Config;
3use packages::{pacman::Pacman, PackageManager}; 3use packages::{pacman::Pacman, PackageManager};
4use tracing::{debug, info, level_filters::LevelFilter};
5use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
4 6
5mod backup; 7mod backup;
6mod config; 8mod config;
@@ -11,30 +13,39 @@ mod pathinfo;
11fn main() -> color_eyre::Result<()> { 13fn main() -> color_eyre::Result<()> {
12 color_eyre::install()?; 14 color_eyre::install()?;
13 15
16 let file_appender = tracing_appender::rolling::never("./", "arps.log");
17 let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
18
19 tracing_subscriber::registry()
20 .with(
21 fmt::layer()
22 .with_writer(non_blocking)
23 .with_file(false)
24 .with_ansi(false)
25 .without_time(),
26 )
27 .with(fmt::layer().with_file(false).without_time())
28 .with(
29 EnvFilter::builder()
30 .with_default_directive(LevelFilter::INFO.into())
31 .from_env_lossy(),
32 )
33 .init();
34 debug!("logging initialized");
35
14 let mut cfg = Config::load()?; 36 let mut cfg = Config::load()?;
15 cfg.user.push("fx".to_string()); 37 cfg.user.push("fx".to_string());
16 cfg.directories.push("~/.config/nvim".to_string()); 38 cfg.directories.push("~/.config/nvim".to_string());
17 // cfg.directories.push("~/.config/hypr".to_string());
18 cfg.root = "./backup".to_string(); 39 cfg.root = "./backup".to_string();
19 // cfg.root = "./backup-test".to_string();
20 // cfg.directories.push("u:/code/proj/fxbaup/backup-test-dir".to_string());
21 40
22 let pacman = Pacman; 41 let pacman = Pacman;
23 let pkgs = pacman.get_installed()?; 42 let pkgs = pacman.get_installed()?;
24 43 let backup = Backup::create(&cfg, pkgs);
25 let backup = Backup::create(&cfg, pkgs)?; 44 // info!(?backup);
26 // println!("{backup:#?}"); 45 // pacman.install(vec![Package {
27 46 // id: "lapce".to_string(),
28 backup.save(&cfg)?; 47 // version: "0.4.2-1".to_string(),
29 48 // explicit: true,
30 // PathInfo::compare_to_last_modified(&cfg, &LocationRoot::User("fx".to_string()), "code/proj/fxbaub/backup-test-dir/size.txt")?; 49 // }])?;
31 // PathInfo::compare_to_last_modified(&cfg, &LocationRoot::User("fx".to_string()), "code/proj/fxbaub/backup-test-dir/content.txt")?;
32
33 // let index = Backup::get_index(&cfg, None)?;
34
35 // println!("{index:#?}");
36
37 // let fi = FileInfo::new("~/.config/nvim", &cfg)?;
38 // println!("{:?}", fi.get_absolute_path());
39 Ok(()) 50 Ok(())
40} 51}
diff --git a/src/packages.rs b/src/packages.rs
index e7b4c3d..5ee5664 100644
--- a/src/packages.rs
+++ b/src/packages.rs
@@ -15,5 +15,5 @@ pub struct Package {
15pub trait PackageManager { 15pub trait PackageManager {
16 fn get_installed(&self) -> Result<Vec<Package>>; 16 fn get_installed(&self) -> Result<Vec<Package>>;
17 17
18 fn install(&self, pkgs: Vec<Package>); 18 fn install(&self, pkgs: Vec<Package>) -> Result<()>;
19} 19}
diff --git a/src/packages/pacman.rs b/src/packages/pacman.rs
index b5be4c0..e10c6fb 100644
--- a/src/packages/pacman.rs
+++ b/src/packages/pacman.rs
@@ -1,4 +1,4 @@
1use std::process::Command; 1use std::process::{Command, Stdio};
2 2
3use super::{Package, PackageManager}; 3use super::{Package, PackageManager};
4 4
@@ -34,13 +34,23 @@ impl PackageManager for Pacman {
34 id: split[0].to_string(), 34 id: split[0].to_string(),
35 version: split[1].to_string(), 35 version: split[1].to_string(),
36 explicit, 36 explicit,
37 }) 37 });
38 } 38 }
39 39
40 Ok(pkgs) 40 Ok(pkgs)
41 } 41 }
42 42
43 fn install(&self, _pkgs: Vec<super::Package>) { 43 fn install(&self, pkgs: Vec<super::Package>) -> Result<()> {
44 todo!(); 44 let mut args = vec!["--noconfirm".to_string(), "-S".to_string()];
45
46 for pkg in pkgs {
47 args.push(pkg.id);
48 }
49 Command::new("pacman")
50 .stdout(Stdio::inherit())
51 .args(args)
52 .spawn()?
53 .wait_with_output()?;
54 Ok(())
45 } 55 }
46} 56}
diff --git a/src/packages/portage.rs b/src/packages/portage.rs
index 6b9e508..f9a760b 100644
--- a/src/packages/portage.rs
+++ b/src/packages/portage.rs
@@ -1,3 +1,5 @@
1use tracing::error;
2
1use super::PackageManager; 3use super::PackageManager;
2 4
3pub struct Portage; 5pub struct Portage;
@@ -7,7 +9,8 @@ impl PackageManager for Portage {
7 todo!() 9 todo!()
8 } 10 }
9 11
10 fn install(&self, pkgs: Vec<super::Package>) { 12 fn install(&self, pkgs: Vec<super::Package>) -> crate::error::Result<()> {
13 error!("Install {pkgs:?}");
11 todo!() 14 todo!()
12 } 15 }
13} 16}
diff --git a/src/pathinfo.rs b/src/pathinfo.rs
index 212dd2a..5b9aa21 100644
--- a/src/pathinfo.rs
+++ b/src/pathinfo.rs
@@ -6,9 +6,10 @@ use std::{
6}; 6};
7 7
8use serde::{Deserialize, Serialize}; 8use serde::{Deserialize, Serialize};
9use tracing::info;
9 10
10use crate::{ 11use crate::{
11 backup::{Backup, BackupId}, 12 backup::{Backup, Id},
12 config::Config, 13 config::Config,
13 error::{Error, Result}, 14 error::{Error, Result},
14}; 15};
@@ -18,7 +19,7 @@ pub struct PathInfo {
18 is_file: bool, 19 is_file: bool,
19 rel_location: String, 20 rel_location: String,
20 location_root: LocationRoot, 21 location_root: LocationRoot,
21 last_modified: Option<BackupId>, 22 last_modified: Option<Id>,
22 children: Vec<PathInfo>, 23 children: Vec<PathInfo>,
23} 24}
24 25
@@ -34,7 +35,7 @@ impl PathInfo {
34 rel_location: &str, 35 rel_location: &str,
35 location_root: &LocationRoot, 36 location_root: &LocationRoot,
36 ) -> Result<Self> { 37 ) -> Result<Self> {
37 println!("Handling {rel_location}"); 38 info!("Handling {rel_location}");
38 let path = Self::get_abs_path(&location_root.to_string(), rel_location); 39 let path = Self::get_abs_path(&location_root.to_string(), rel_location);
39 Ok(if path.is_dir() { 40 Ok(if path.is_dir() {
40 let mut last_modified = Some(String::new()); 41 let mut last_modified = Some(String::new());
@@ -51,7 +52,7 @@ impl PathInfo {
51 }; 52 };
52 let handle = Self::handle_dir(config, rl.1, location_root)?; 53 let handle = Self::handle_dir(config, rl.1, location_root)?;
53 if let Some(lm) = handle.last_modified.clone() { 54 if let Some(lm) = handle.last_modified.clone() {
54 if last_modified != None { 55 if last_modified.is_some() {
55 let ts = Backup::from_index(config, &lm)?.timestamp; 56 let ts = Backup::from_index(config, &lm)?.timestamp;
56 if ts > last_modified_timestamp { 57 if ts > last_modified_timestamp {
57 last_modified_timestamp = ts; 58 last_modified_timestamp = ts;
@@ -82,7 +83,7 @@ impl PathInfo {
82 ) -> Result<Self> { 83 ) -> Result<Self> {
83 let last_modified = Self::compare_to_last_modified(config, location_root, rel_location)?; 84 let last_modified = Self::compare_to_last_modified(config, location_root, rel_location)?;
84 85
85 println!("From file {rel_location} ({:?})", last_modified); 86 info!("From file {rel_location} ({last_modified:?})");
86 87
87 Ok(Self { 88 Ok(Self {
88 rel_location: rel_location.to_string(), 89 rel_location: rel_location.to_string(),
@@ -107,7 +108,6 @@ impl PathInfo {
107 let last_file_opt = Self::find_last_modified(files, rel_location, location_root); 108 let last_file_opt = Self::find_last_modified(files, rel_location, location_root);
108 let Some(last_file) = last_file_opt else { 109 let Some(last_file) = last_file_opt else {
109 // File didn't exist last Backup 110 // File didn't exist last Backup
110 println!("File didn't exist last Backup");
111 return Ok(None); 111 return Ok(None);
112 }; 112 };
113 113
@@ -120,8 +120,7 @@ impl PathInfo {
120 let old_path = modified_backup.get_absolute_file_location(config, &last_file.rel_location); 120 let old_path = modified_backup.get_absolute_file_location(config, &last_file.rel_location);
121 let new_path = format!("{location_root}/{rel_location}"); 121 let new_path = format!("{location_root}/{rel_location}");
122 122
123 let mut old = File::open(old_path)?; 123 let mut old = File::open(old_path)?; let mut new = File::open(new_path)?;
124 let mut new = File::open(new_path)?;
125 124
126 let old_len = old.metadata()?.len(); 125 let old_len = old.metadata()?.len();
127 let new_len = new.metadata()?.len(); 126 let new_len = new.metadata()?.len();
@@ -147,15 +146,10 @@ impl PathInfo {
147 ) -> Option<PathInfo> { 146 ) -> Option<PathInfo> {
148 for path in files { 147 for path in files {
149 if path.is_file { 148 if path.is_file {
150 println!("Checking {}", path.rel_location);
151 println!("File rel: {} ?= {}", path.rel_location, rel_location);
152 println!("File rot: {} ?= {}", path.location_root, location_root);
153 if path.rel_location == rel_location && path.location_root == *location_root { 149 if path.rel_location == rel_location && path.location_root == *location_root {
154 println!("Return Some");
155 return Some(path); 150 return Some(path);
156 }; 151 };
157 } else { 152 } else {
158 println!("Checking all in {path:?}");
159 let is_modified = 153 let is_modified =
160 PathInfo::find_last_modified(path.children, rel_location, location_root); 154 PathInfo::find_last_modified(path.children, rel_location, location_root);
161 if is_modified.is_some() { 155 if is_modified.is_some() {
@@ -174,11 +168,9 @@ impl PathInfo {
174 if self.last_modified.is_some() { 168 if self.last_modified.is_some() {
175 return Ok(()); 169 return Ok(());
176 } 170 }
177 println!("Save File {:?}", self.rel_location); 171 info!("Save File {:?}", self.rel_location);
178 if self.is_file { 172 if self.is_file {
179 let new_path = format!("{}/{}", backup_root, self.rel_location); 173 let new_path = format!("{}/{}", backup_root, self.rel_location);
180 // println!("New Path: {new_path}");
181 // println!("Old Path: {:?}", self.get_absolute_path());
182 let np = Path::new(&new_path); 174 let np = Path::new(&new_path);
183 if let Some(parent) = np.parent() { 175 if let Some(parent) = np.parent() {
184 create_dir_all(parent)?; 176 create_dir_all(parent)?;
@@ -194,7 +186,7 @@ impl PathInfo {
194 } 186 }
195 187
196 fn get_abs_path(location_root: &str, rel_location: &str) -> PathBuf { 188 fn get_abs_path(location_root: &str, rel_location: &str) -> PathBuf {
197 let path = format!("{}/{}", location_root, rel_location); 189 let path = format!("{location_root}/{rel_location}");
198 PathBuf::from(path) 190 PathBuf::from(path)
199 } 191 }
200 192
@@ -383,7 +375,7 @@ mod tests {
383 config.root = "./backup-test".to_string(); 375 config.root = "./backup-test".to_string();
384 config 376 config
385 .directories 377 .directories
386 .push("u:fx/code/proj/fxbaup/backup-test-dir".to_string()); 378 .push("u:fx/code/proj/arps/backup-test-dir".to_string());
387 379
388 create_dir_all("./backup-test-dir")?; 380 create_dir_all("./backup-test-dir")?;
389 let mut f = File::create("./backup-test-dir/size.txt")?; 381 let mut f = File::create("./backup-test-dir/size.txt")?;
@@ -403,12 +395,12 @@ mod tests {
403 let mut f = File::create("./backup-test-dir/content.txt")?; 395 let mut f = File::create("./backup-test-dir/content.txt")?;
404 f.write_all("unmodefied".as_bytes())?; 396 f.write_all("unmodefied".as_bytes())?;
405 397
406 let pi = PathInfo::from_path(&config, "u:fx/code/proj/fxbaup/backup-test-dir")?; 398 let pi = PathInfo::from_path(&config, "u:fx/code/proj/arps/backup-test-dir")?;
407 399
408 let last_backup = Backup::get_last(&config)?.unwrap(); 400 let last_backup = Backup::get_last(&config)?.unwrap();
409 for file in pi.children { 401 for file in pi.children {
410 println!("test rel: {}", file.rel_location); 402 println!("test rel: {}", file.rel_location);
411 let res = if file.rel_location == "code/proj/fxbaup/backup-test-dir/nothing.txt" { 403 let res = if file.rel_location == "code/proj/arps/backup-test-dir/nothing.txt" {
412 Some(last_backup.id.clone()) 404 Some(last_backup.id.clone())
413 } else { 405 } else {
414 None 406 None