From 37782c934c2b76f8319e8d83a9c0d284fbb04ed3 Mon Sep 17 00:00:00 2001 From: qwjyh Date: Wed, 7 Aug 2024 11:39:58 +0200 Subject: [PATCH] (WIP) new: implement `status` subcommand - Error while getting mount path of Storages - Need to redesign the API of LocalInfo or something --- src/cmd_args.rs | 12 +++++++ src/cmd_status.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 6 ++++ src/storages.rs | 1 - 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/cmd_status.rs diff --git a/src/cmd_args.rs b/src/cmd_args.rs index 70a8033..4627f97 100644 --- a/src/cmd_args.rs +++ b/src/cmd_args.rs @@ -44,6 +44,18 @@ pub(crate) enum Commands { #[command(subcommand)] Backup(BackupSubCommands), + /// Print status for the given path. + Status { + /// Target path. Default is the current directory. + path: Option, + /// Show storage which the path belongs to. + #[arg(short)] + storage: bool, + /// Show backup config covering the path. + #[arg(short)] + backup: bool, + }, + /// Print config dir. Path {}, diff --git a/src/cmd_status.rs b/src/cmd_status.rs new file mode 100644 index 0000000..eebc2cc --- /dev/null +++ b/src/cmd_status.rs @@ -0,0 +1,81 @@ +use anyhow::{Context, Result}; +use console::Style; +use std::{ + env, + path::{self, Path, PathBuf}, +}; + +use crate::{ + backups::Backups, + devices::{self, Device}, + storages::{self, StorageExt, Storages}, + util, +}; + +// TODO: fine styling like `backup list`, or should I just use the same style? +pub(crate) fn cmd_status( + path: Option, + show_storage: bool, + show_backup: bool, + config_dir: &Path, +) -> Result<()> { + let path = path.unwrap_or(env::current_dir().context("Failed to get current directory.")?); + let device = devices::get_device(config_dir)?; + + if show_storage { + let storages = storages::Storages::read(config_dir)?; + let storage = util::min_parent_storage(&path, &storages, &device); + + match storage { + Some(storage) => { + println!("Storage: {}", storage.0.name()) + } + None => { + println!("Storage: None"); + } + } + } + if show_backup { + let devices = devices::get_devices(config_dir)?; + let storages = storages::Storages::read(config_dir)?; + let backups = Backups::read(config_dir, &device)?; + let covering_backup = devices + .iter() + .map(|device| (device, parent_backups(&path, &backups, &storages, device))); + + for (backup_device, covering_backups) in covering_backup { + println!("Device: {}", backup_device.name()); + for backup in covering_backups { + println!(" {}", console::style(backup.0).bold()); + } + } + } + todo!() +} + +fn parent_backups<'a>( + target_path: &'a PathBuf, + backups: &'a Backups, + storages: &'a Storages, + device: &'a Device, +) -> Vec<(&'a String, PathBuf)> { + backups + .list + .iter() + .filter_map(|(k, v)| { + let backup_path = match v.source().path(storages, device) { + Ok(path) => path, + Err(e) => { + error!("Error while getting backup source path: {}", e); + return None; + } + }; + let diff = pathdiff::diff_paths(target_path, backup_path)?; + if diff.components().any(|c| c == path::Component::ParentDir) { + None + } else { + Some((k, diff)) + } + }) + .collect() +} diff --git a/src/main.rs b/src/main.rs index 18e332d..23dadcd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,6 +31,7 @@ mod cmd_backup; mod cmd_check; mod cmd_completion; mod cmd_init; +mod cmd_status; mod cmd_storage; mod cmd_sync; mod devices; @@ -91,6 +92,11 @@ fn main() -> Result<()> { println!("{}", &config_dir.display()); } Commands::Sync { remote_name } => cmd_sync::cmd_sync(&config_dir, remote_name)?, + Commands::Status { + path, + storage, + backup, + } => cmd_status::cmd_status(path, storage, backup, &config_dir)?, Commands::Check {} => cmd_check::cmd_check(&config_dir)?, Commands::Backup(backup) => { trace!("backup subcommand with args: {:?}", backup); diff --git a/src/storages.rs b/src/storages.rs index 4031d61..b80536e 100644 --- a/src/storages.rs +++ b/src/storages.rs @@ -144,7 +144,6 @@ pub trait StorageExt { fn local_info(&self, device: &devices::Device) -> Option<&local_info::LocalInfo>; /// Get mount path of `self` on `device`. - /// `storages` is a `BTreeMap` with key of storage name and value of the storage. fn mount_path(&self, device: &devices::Device) -> Result; /// Add local info of `device` to `self`.