From 0ed94b3f011a2d3c22bdc4affb502720be22c371 Mon Sep 17 00:00:00 2001 From: fxqnlr Date: Sat, 14 Sep 2024 18:59:23 +0200 Subject: add restoration of files and packages --- src/backup.rs | 19 ++++++++++++++----- src/cli.rs | 5 ++++- src/error.rs | 26 +++++++++----------------- src/main.rs | 9 ++++++--- src/pathinfo.rs | 44 +++++++++++++++++++++++++++++++------------- 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 { pub fn save(&self, config: &Config) -> Result<()> { info!("Save Backup {:?}", self.get_location(config)); - self.get_location(config).append_to_root(config)?; + let loc = self.get_location(config); + loc.append_to_root(config)?; - let backup_root = self.get_location(config).get_absolute_dir(config); + let backup_root = loc.get_absolute_dir(config); create_dir_all(&backup_root).unwrap(); let path = format!("{backup_root}/index.json"); let mut f = File::create(path).unwrap(); @@ -66,7 +67,7 @@ impl Backup { let list: Vec = match Self::get_json_content(&backup_index_root) { Ok(list) => list, Err(err) => { - if err.to_string() == "io: No such file or directory (os error 2)" { + if err.to_string() == "No such file or directory (os error 2)" { return Ok(None); }; return Err(err); @@ -112,8 +113,16 @@ impl Backup { format!("{loc}/{rel_location}") } - pub fn restore(&self) { - todo!() + pub fn restore(&self, config: &Config) -> Result<()> { + info!(?self.id, ?self.timestamp, "Restore Backup"); + + let backup_root = self.get_location(config).get_absolute_dir(config); + + for path in &self.files { + path.restore(config, &backup_root)?; + } + + Ok(()) } fn get_json_content Deserialize<'a>>(path: &str) -> Result { 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 { #[arg(short, long)] package_manager: Option, }, - Restore, + Restore { + #[arg(short, long)] + package_install: bool + }, } 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 { #[error("Unsupported os/distro")] Unsupported, - #[error("json: {source}")] - SerdeJson { - #[from] - source: serde_json::Error, - }, - - #[error("toml serializer: {source}")] - TomlSerialize { - #[from] - source: toml::ser::Error, - }, - - #[error("io: {source}")] - Io { - #[from] - source: std::io::Error, - }, + // Deps + #[error(transparent)] + SerdeJson(#[from] serde_json::Error), + + #[error(transparent)] + TomlSerialize(#[from] toml::ser::Error), + + #[error(transparent)] + Io(#[from] std::io::Error), } 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<()> { let backup = Backup::create(&config, package_manager)?; backup.save(&config)?; } - Subcommands::Restore => { + Subcommands::Restore { package_install } => { let Some(last_backup) = Backup::get_last(&config)? else { return Err(Error::BackupNotFound)?; }; - last_backup.packages.install()?; - last_backup.restore(); + if package_install { + last_backup.packages.install()?; + } + + last_backup.restore(&config)?; } }; 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::{ }; use serde::{Deserialize, Serialize}; -use tracing::info; +use tracing::{debug, info}; use crate::{ backup::{Backup, Id}, @@ -186,6 +186,33 @@ impl PathInfo { Ok(()) } + pub fn restore(&self, config: &Config, backup_root: &str) -> Result<()> { + if self.is_file { + info!(?self.rel_location, "Restore File"); + let backup_path = if let Some(last_modified) = self.last_modified.clone() { + let backup = Backup::from_index(config, &last_modified)?; + &backup.get_location(config).get_absolute_dir(config) + } else { + backup_root + }; + let backup_loc = format!("{}/{}", backup_path, self.rel_location); + let system_loc = self.get_absolute_path(); + debug!(?backup_loc, ?system_loc, "copy"); + + if let Some(parents) = system_loc.parent() { + create_dir_all(parents)?; + } + + std::fs::copy(backup_loc, system_loc)?; + } else { + for path in &self.children { + path.restore(config, backup_root)?; + } + } + + Ok(()) + } + fn get_abs_path(location_root: &str, rel_location: &str) -> PathBuf { let path = format!("{location_root}/{rel_location}"); PathBuf::from(path) @@ -196,10 +223,7 @@ impl PathInfo { return Err(Error::InvalidDirectory(value.to_string())); }; if split.0.starts_with('~') { - return Ok(( - split.1.to_string(), - LocationRoot::User, - )); + return Ok((split.1.to_string(), LocationRoot::User)); }; Ok(( split.1.to_string(), @@ -330,17 +354,11 @@ mod tests { let mut values_ok: Vec<(&str, (String, LocationRoot))> = Vec::new(); values_ok.push(( "~/.config/nvim", - ( - ".config/nvim".to_string(), - LocationRoot::User, - ), + (".config/nvim".to_string(), LocationRoot::User), )); values_ok.push(( "u:test/.config/nvim", - ( - ".config/nvim".to_string(), - LocationRoot::User, - ), + (".config/nvim".to_string(), LocationRoot::User), )); values_ok.push(( "r:/.config/nvim", -- cgit v1.2.3