diff --git a/CHANGELOG.md b/CHANGELOG.md index 16a827f..685004c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,6 @@ ### Changed - Colored output for `storage list` and `backup list` ([#15](https://github.com/qwjyh/xdbm/pull/15)) -- **BREAKING** Relative path is changed from `PathBuf` to `Vector` for portability. This means that existing config files need to be changed. -- Add `status` subcommand to see storage and backup on given path or current working directory ([#17](https://github.com/qwjyh/xdbm/pull/17)). ## [0.2.1] - 2024-06-19 diff --git a/src/backups.rs b/src/backups.rs index 8f70509..fbb4c1f 100644 --- a/src/backups.rs +++ b/src/backups.rs @@ -27,38 +27,32 @@ pub fn backups_file(device: &Device) -> PathBuf { } /// Targets for backup source or destination. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct BackupTarget { /// `name()` of [`crate::storages::Storage`]. /// Use `String` for serialization/deserialization. pub storage: String, /// Relative path to the `storage`. - pub path: Vec, + pub path: PathBuf, } impl BackupTarget { - pub fn new(storage_name: String, relative_path: PathBuf) -> Result { - let relative_path = relative_path - .components() - .map(|c| c.as_os_str().to_str().map(|s| s.to_owned())) - .collect::>() - .context("Path contains non-utf8 character")?; - Ok(BackupTarget { + pub fn new(storage_name: String, relative_path: PathBuf) -> Self { + BackupTarget { storage: storage_name, path: relative_path, - }) + } } - /// Get full path of the [`BackupTarget`]. - pub fn path(&self, storages: &Storages, device: &Device) -> Option { + pub fn path(&self, storages: &Storages, device: &Device) -> Result { let parent = storages.get(&self.storage).unwrap(); let parent_path = parent.mount_path(device)?; - Some(parent_path.join(self.path.clone().iter().collect::())) + Ok(parent_path.join(self.path.clone())) } } /// Type of backup commands. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub enum BackupCommand { ExternallyInvoked(ExternallyInvoked), } @@ -85,7 +79,7 @@ impl BackupCommandExt for BackupCommand { /// Backup commands which is not invoked from xdbm itself. /// Call xdbm externally to record backup datetime and status. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ExternallyInvoked { name: String, pub note: String, @@ -108,7 +102,7 @@ impl BackupCommandExt for ExternallyInvoked { } /// Backup execution log. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct BackupLog { pub datetime: DateTime, status: BackupResult, @@ -128,7 +122,7 @@ impl BackupLog { } /// Result of backup. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub enum BackupResult { Success, Failure, @@ -145,7 +139,7 @@ impl BackupResult { } /// Backup source, destination, command and logs. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Backup { /// must be unique name: String, @@ -180,7 +174,7 @@ impl Backup { &self.name } - pub fn device<'a>(&'a self, devices: &'a [Device]) -> Option<&'a Device> { + pub fn device<'a>(&'a self, devices: &'a [Device]) -> Option<&Device> { devices.iter().find(|dev| dev.name() == self.device) } @@ -206,7 +200,7 @@ impl Backup { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Backups { pub list: BTreeMap, } diff --git a/src/cmd_args.rs b/src/cmd_args.rs index c0b46b7..70a8033 100644 --- a/src/cmd_args.rs +++ b/src/cmd_args.rs @@ -44,18 +44,6 @@ 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, long)] - storage: bool, - /// Show backup config covering the path. - #[arg(short, long)] - backup: bool, - }, - /// Print config dir. Path {}, diff --git a/src/cmd_backup.rs b/src/cmd_backup.rs index cab7a9e..7ae9767 100644 --- a/src/cmd_backup.rs +++ b/src/cmd_backup.rs @@ -5,7 +5,7 @@ use std::{ }; use anyhow::{anyhow, Context, Ok, Result}; -use chrono::Local; +use chrono::{Local, TimeDelta}; use console::Style; use dunce::canonicalize; use git2::Repository; @@ -89,8 +89,8 @@ fn new_backup( Ok(Backup::new( name, device.name(), - src_target?, - dest_target?, + src_target, + dest_target, command, )) } @@ -154,6 +154,17 @@ pub fn cmd_backup_list( Ok(()) } +fn duration_style(time: TimeDelta) -> Style { + match time { + x if x < TimeDelta::days(7) => Style::new().green(), + x if x < TimeDelta::days(14) => Style::new().yellow(), + x if x < TimeDelta::days(28) => Style::new().magenta(), + x if x < TimeDelta::days(28 * 3) => Style::new().red(), + x if x < TimeDelta::days(180) => Style::new().red().bold(), + _ => Style::new().on_red().black(), + } +} + /// TODO: status printing fn write_backups_list( mut writer: impl io::Write, @@ -177,16 +188,10 @@ fn write_backups_list( ))?; name_width = name_width.max(backup.name().width()); dev_width = dev_width.max(dev.width()); - let src = backup - .source() - .path(storages, device) - .context("Couldn't get path for source")?; + let src = backup.source().path(storages, device)?; src_width = src_width.max(format!("{}", src.display()).width()); src_storage_width = src_storage_width.max(backup.source().storage.width()); - let dest = backup - .destination() - .path(storages, device) - .context("Couldn't get path for destination")?; + let dest = backup.destination().path(storages, device)?; dest_width = dest_width.max(format!("{}", dest.display()).width()); dest_storage_width = dest_storage_width.max(backup.destination().storage.width()); let cmd_name = backup.command().name(); @@ -198,20 +203,14 @@ fn write_backups_list( "Couldn't find the device specified in the backup config: {}", backup.name() ))?; - let src = backup - .source() - .path(storages, device) - .context("Couldn't get path for source")?; - let dest = backup - .destination() - .path(storages, device) - .context("Couldn't get path for destination")?; + let src = backup.source().path(storages, device)?; + let dest = backup.destination().path(storages, device)?; let cmd_name = backup.command().name(); let (last_backup_elapsed, style_on_time_elapsed) = match backup.last_backup() { Some(log) => { let time = Local::now() - log.datetime; let s = util::format_summarized_duration(time); - let style = util::duration_style(time); + let style = duration_style(time); (style.apply_to(s), style) } None => { @@ -361,9 +360,9 @@ mod test { &storages, )?; assert!(backup.source().storage == "online"); - assert_eq!(backup.source().path, vec!["docs"]); + assert_eq!(backup.source().path, PathBuf::from("docs")); assert!(backup.destination().storage == "online"); - assert!(backup.destination().path == vec!["tmp"]); + assert!(backup.destination().path == PathBuf::from("tmp")); Ok(()) } } diff --git a/src/cmd_status.rs b/src/cmd_status.rs deleted file mode 100644 index 560c02f..0000000 --- a/src/cmd_status.rs +++ /dev/null @@ -1,298 +0,0 @@ -use anyhow::{Context, Result}; -use chrono::Local; -use console::Style; -use std::{ - env, - path::{self, Path, PathBuf}, -}; - -use crate::{ - backups::{Backup, Backups}, - devices::{self, Device}, - storages::{self, Storage, 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 current_device = devices::get_device(config_dir)?; - - if show_storage { - let storages = storages::Storages::read(config_dir)?; - let storage = util::min_parent_storage(&path, &storages, ¤t_device); - trace!("storage {:?}", storage); - - // TODO: recursively trace all storages for subdirectory? - 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 = devices.iter().map(|device| { - Backups::read(config_dir, device) - .context("Backups were not found") - .unwrap() - }); - - let (target_storage, target_diff_from_storage) = - util::min_parent_storage(&path, &storages, ¤t_device) - .context("Target path is not covered in any storage")?; - - let covering_backup: Vec<_> = devices - .iter() - .zip(backups) - .map(|(device, backups)| { - debug!( - "dev {}, storage {:?}", - device.name(), - backups - .list - .iter() - .map(|(backup_name, backup)| format!( - "{} {}", - backup_name, - backup.source().storage - )) - .collect::>() - ); - ( - device, - parent_backups( - &target_diff_from_storage, - target_storage, - backups, - &storages, - device, - ), - ) - }) - .collect(); - trace!("{:?}", covering_backup.first()); - - let name_len = &covering_backup - .iter() - .map(|(_, backups)| { - backups - .iter() - .map(|(backup, _path)| backup.name().len()) - .max() - .unwrap_or(0) - }) - .max() - .unwrap_or(5); - - for (backup_device, covering_backups) in covering_backup { - if covering_backups.is_empty() { - continue; - } - - println!("Device: {}", backup_device.name()); - for (backup, path_from_backup) in covering_backups { - let (last_backup, style) = match backup.last_backup() { - Some(log) => { - let timediff = Local::now() - log.datetime; - ( - util::format_summarized_duration(timediff), - util::duration_style(timediff), - ) - } - None => ("---".to_string(), Style::new().red()), - }; - println!( - " {:( - target_path_from_storage: &'a Path, - target_storage: &'a Storage, - backups: Backups, - storages: &'a Storages, - device: &'a Device, -) -> Vec<(Backup, PathBuf)> { - trace!("Dev {:?}", device.name()); - let target_path = match target_storage.mount_path(device) { - Some(target_path) => target_path.join(target_path_from_storage), - None => return vec![], - }; - trace!("Path on the device {:?}", target_path); - backups - .list - .into_iter() - .filter_map(|(_k, backup)| { - let backup_path = backup.source().path(storages, device)?; - trace!("{:?}", backup_path.components()); - let diff = pathdiff::diff_paths(&target_path, backup_path.clone())?; - trace!("Backup: {:?}, Diff: {:?}", backup_path, diff); - // note: Should `RootDir` is included in this list? - if diff - .components() - .any(|c| matches!(c, path::Component::ParentDir | path::Component::Prefix(_))) - { - None - } else { - Some((backup, diff)) - } - }) - .collect() -} - -#[cfg(test)] -mod test { - use std::{path::PathBuf, vec}; - - use crate::{ - backups::{self, ExternallyInvoked}, - devices, - storages::{self, online_storage::OnlineStorage, StorageExt}, - util, - }; - - use super::parent_backups; - - #[test] - fn test_parent_backups() { - let device1 = devices::Device::new("device_1".to_string()); - let mut storage1 = storages::Storage::Online(OnlineStorage::new( - "storage_1".to_string(), - "smb".to_string(), - 1_000_000, - "str1".to_string(), - PathBuf::from("/home/foo/"), - &device1, - )); - let storage2 = storages::Storage::Online(OnlineStorage::new( - "storage_2".to_string(), - "smb".to_string(), - 1_000_000_000, - "str2".to_string(), - PathBuf::from("/"), - &device1, - )); - let device2 = devices::Device::new("device_2".to_string()); - storage1 - .bound_on_device("alias".to_string(), PathBuf::from("/mnt/dev"), &device2) - .unwrap(); - let storage3 = storages::Storage::Online(OnlineStorage::new( - "storage_3".to_string(), - "smb".to_string(), - 2_000_000_000, - "str2".to_string(), - PathBuf::from("/"), - &device2, - )); - let storages = { - let mut storages = storages::Storages::new(); - storages.add(storage1).unwrap(); - storages.add(storage2).unwrap(); - storages.add(storage3).unwrap(); - storages - }; - - let backup1 = backups::Backup::new( - "backup_1".to_string(), - device1.name().to_string(), - backups::BackupTarget { - storage: "storage_1".to_string(), - path: vec!["bar".to_string()], - }, - backups::BackupTarget { - storage: "storage_1".to_string(), - path: vec!["hoge".to_string()], - }, - backups::BackupCommand::ExternallyInvoked(ExternallyInvoked::new( - "cmd".to_string(), - "".to_string(), - )), - ); - let backup2 = backups::Backup::new( - "backup_2".to_string(), - device2.name().to_string(), - backups::BackupTarget { - storage: "storage_1".to_string(), - path: vec!["".to_string()], - }, - backups::BackupTarget { - storage: "storage_3".to_string(), - path: vec!["foo".to_string()], - }, - backups::BackupCommand::ExternallyInvoked(ExternallyInvoked::new( - "cmd".to_string(), - "".to_string(), - )), - ); - - let backups = { - let mut backups = backups::Backups::new(); - backups.add(backup1).unwrap(); - backups.add(backup2).unwrap(); - backups - }; - - let target_path1 = PathBuf::from("/home/foo/bar/hoo"); - let (target_storage1, target_path_from_storage1) = - util::min_parent_storage(&target_path1, &storages, &device1) - .expect("Failed to get storage"); - let covering_backups_1 = parent_backups( - &target_path_from_storage1, - target_storage1, - backups.clone(), - &storages, - &device1, - ); - assert_eq!(covering_backups_1.len(), 2); - - let target_path2 = PathBuf::from("/mnt/"); - let (target_storage2, target_path_from_storage2) = - util::min_parent_storage(&target_path2, &storages, &device2) - .expect("Failed to get storage"); - let covering_backups_2 = parent_backups( - &target_path_from_storage2, - target_storage2, - backups.clone(), - &storages, - &device2, - ); - assert_eq!(covering_backups_2.len(), 0); - - let target_path3 = PathBuf::from("/mnt/dev/foo"); - let (target_storage3, target_path_from_storage3) = - util::min_parent_storage(&target_path3, &storages, &device2) - .expect("Failed to get storage"); - let covering_backups_3 = parent_backups( - &target_path_from_storage3, - target_storage3, - backups, - &storages, - &device2, - ); - assert_eq!(covering_backups_3.len(), 1); - let mut covering_backup_names_3 = - covering_backups_3.iter().map(|(backup, _)| backup.name()); - assert_eq!(covering_backup_names_3.next().unwrap(), "backup_2"); - assert!(covering_backup_names_3.next().is_none()); - } -} diff --git a/src/cmd_storage.rs b/src/cmd_storage.rs index 2cb9414..8c39646 100644 --- a/src/cmd_storage.rs +++ b/src/cmd_storage.rs @@ -215,8 +215,8 @@ fn write_storages_list( "" }; let path = storage.mount_path(device).map_or_else( - || { - info!("Mount path not found"); + |e| { + info!("Not found: {}", e); "".to_string() }, |v| v.display().to_string(), diff --git a/src/main.rs b/src/main.rs index 23dadcd..18e332d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,7 +31,6 @@ mod cmd_backup; mod cmd_check; mod cmd_completion; mod cmd_init; -mod cmd_status; mod cmd_storage; mod cmd_sync; mod devices; @@ -92,11 +91,6 @@ 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 d4b9dd4..4031d61 100644 --- a/src/storages.rs +++ b/src/storages.rs @@ -78,7 +78,7 @@ impl StorageExt for Storage { } } - fn mount_path(&self, device: &devices::Device) -> Option { + fn mount_path(&self, device: &devices::Device) -> Result { match self { Self::Physical(s) => s.mount_path(device), Self::SubDirectory(s) => s.mount_path(device), @@ -144,8 +144,8 @@ pub trait StorageExt { fn local_info(&self, device: &devices::Device) -> Option<&local_info::LocalInfo>; /// Get mount path of `self` on `device`. - /// Return [`None`] if the storage([`self`]) is not configured for the `device`. - fn mount_path(&self, device: &devices::Device) -> Option; + /// `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`. fn bound_on_device( diff --git a/src/storages/directory.rs b/src/storages/directory.rs index 1642518..4cd7803 100644 --- a/src/storages/directory.rs +++ b/src/storages/directory.rs @@ -2,7 +2,6 @@ use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; use std::{collections::BTreeMap, fmt, path}; use crate::devices; @@ -18,9 +17,9 @@ pub struct Directory { /// ID of parent storage. parent: String, /// Relative path to the parent storage. - relative_path: Vec, + relative_path: path::PathBuf, pub notes: String, - /// [`devices::Device`] name and localinfo pairs. + /// Device and localinfo pairs. local_infos: BTreeMap, } @@ -35,19 +34,14 @@ impl Directory { relative_path: path::PathBuf, notes: String, local_infos: BTreeMap, - ) -> Result { - let relative_path = relative_path - .components() - .map(|c| c.as_os_str().to_str().map(|s| s.to_owned())) - .collect::>>() - .context("Path contains non-utf8 character")?; - Ok(Directory { + ) -> Directory { + Directory { name, parent, relative_path, notes, local_infos, - }) + } } pub fn try_from_device_path( @@ -62,23 +56,23 @@ impl Directory { .context("Failed to compare diff of paths")?; trace!("Selected parent: {}", parent.name()); let local_info = LocalInfo::new(alias, path); - Directory::new( + Ok(Directory::new( name, parent.name().to_string(), diff_path, notes, BTreeMap::from([(device.name(), local_info)]), - ) + )) } pub fn update_note(self, notes: String) -> Directory { - Directory { - name: self.name, - parent: self.parent, - relative_path: self.relative_path, + Directory::new( + self.name, + self.parent, + self.relative_path, notes, - local_infos: self.local_infos, - } + self.local_infos, + ) } /// Resolve mount path of directory with current device. @@ -86,9 +80,8 @@ impl Directory { let parent_mount_path = self .parent(storages) .context("Can't find parent storage")? - .mount_path(device) - .context("Can't find mount path")?; - Ok(parent_mount_path.join(self.relative_path.clone().iter().collect::())) + .mount_path(device)?; + Ok(parent_mount_path.join(self.relative_path.clone())) } } @@ -105,10 +98,12 @@ impl StorageExt for Directory { self.local_infos.get(&device.name()) } - fn mount_path(&self, device: &devices::Device) -> Option { - self.local_infos + fn mount_path(&self, device: &devices::Device) -> Result { + Ok(self + .local_infos .get(&device.name()) - .map(|info| info.mount_path()) + .context(format!("LocalInfo for storage: {} not found", &self.name()))? + .mount_path()) } /// This method doesn't use `mount_path`. @@ -127,7 +122,7 @@ impl StorageExt for Directory { } // Get parent `&Storage` of directory. - fn parent<'a>(&'a self, storages: &'a Storages) -> Option<&'a Storage> { + fn parent<'a>(&'a self, storages: &'a Storages) -> Option<&Storage> { storages.get(&self.parent) } } @@ -139,7 +134,7 @@ impl fmt::Display for Directory { "S {name:<10} < {parent:<10}{relative_path:<10} : {notes}", name = self.name(), parent = self.parent, - relative_path = self.relative_path.iter().collect::().display(), + relative_path = self.relative_path.display(), notes = self.notes, ) } @@ -183,8 +178,7 @@ mod test { "subdir".into(), "some note".to_string(), local_infos, - ) - .unwrap(); + ); let mut storages = Storages::new(); storages.add(storages::Storage::Physical(physical)).unwrap(); storages.add(Storage::SubDirectory(directory)).unwrap(); diff --git a/src/storages/online_storage.rs b/src/storages/online_storage.rs index 6c4d62c..4ce2459 100644 --- a/src/storages/online_storage.rs +++ b/src/storages/online_storage.rs @@ -61,10 +61,12 @@ impl StorageExt for OnlineStorage { self.local_infos.get(&device.name()) } - fn mount_path(&self, device: &devices::Device) -> Option { - self.local_infos + fn mount_path(&self, device: &devices::Device) -> Result { + Ok(self + .local_infos .get(&device.name()) - .map(|info| info.mount_path()) + .context(format!("LocalInfo for storage: {} not found", &self.name()))? + .mount_path()) } fn bound_on_device( diff --git a/src/storages/physical_drive_partition.rs b/src/storages/physical_drive_partition.rs index 14a35a6..95dec3f 100644 --- a/src/storages/physical_drive_partition.rs +++ b/src/storages/physical_drive_partition.rs @@ -21,7 +21,6 @@ pub struct PhysicalDrivePartition { fs: String, is_removable: bool, // system_names: BTreeMap, - /// [`Device`] name and [`LocalInfo`] mapping. local_infos: BTreeMap, } @@ -113,10 +112,12 @@ impl StorageExt for PhysicalDrivePartition { self.local_infos.get(&device.name()) } - fn mount_path(&self, device: &devices::Device) -> Option { - self.local_infos + fn mount_path(&self, device: &devices::Device) -> Result { + Ok(self + .local_infos .get(&device.name()) - .map(|info| info.mount_path()) + .context(format!("LocalInfo for storage: {} not found", &self.name()))? + .mount_path()) } fn bound_on_device( diff --git a/src/util.rs b/src/util.rs index ea2c947..820de33 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,6 @@ use std::path::{self, PathBuf}; use anyhow::{Context, Result}; -use chrono::TimeDelta; use console::Style; use crate::{ @@ -19,12 +18,12 @@ pub fn min_parent_storage<'a>( .list .iter() .filter_map(|(k, storage)| { - let storage_path = storage.mount_path(device)?; + let storage_path = match storage.mount_path(device) { + Ok(path) => path, + Err(_) => return None, + }; let diff = pathdiff::diff_paths(path, storage_path)?; - if diff - .components() - .any(|c| matches!(c, path::Component::ParentDir | path::Component::Prefix(_))) - { + if diff.components().any(|c| c == path::Component::ParentDir) { None } else { Some((k, diff)) @@ -63,17 +62,6 @@ pub fn format_summarized_duration(dt: chrono::Duration) -> String { } } -pub fn duration_style(time: TimeDelta) -> Style { - match time { - x if x < TimeDelta::days(7) => Style::new().green(), - x if x < TimeDelta::days(14) => Style::new().yellow(), - x if x < TimeDelta::days(28) => Style::new().magenta(), - x if x < TimeDelta::days(28 * 3) => Style::new().red(), - x if x < TimeDelta::days(180) => Style::new().red().bold(), - _ => Style::new().on_red().black(), - } -} - #[cfg(test)] mod test { use anyhow::Result; diff --git a/tests/cli.rs b/tests/cli.rs index 929a74e..4dd4fe6 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -145,7 +145,7 @@ mod integrated_test { // bare-repo let bare_repo_dir = assert_fs::TempDir::new()?; - let _bare_repo = Repository::init_bare(&bare_repo_dir)?; + let bare_repo = Repository::init_bare(&bare_repo_dir)?; // push to bare repository let repo_1 = Repository::open(&config_dir_1)?; let upstream_name = "remote"; @@ -216,8 +216,6 @@ mod integrated_test { #[test] fn two_devices() -> Result<()> { // 1st device - // - // devices: first let config_dir_1 = assert_fs::TempDir::new()?; setup_gitconfig()?; let mut cmd1 = Command::cargo_bin("xdbm")?; @@ -229,7 +227,7 @@ mod integrated_test { // bare-repo let bare_repo_dir = assert_fs::TempDir::new()?; - let _bare_repo = Repository::init_bare(&bare_repo_dir)?; + let bare_repo = Repository::init_bare(&bare_repo_dir)?; // push to bare repository let repo_1 = Repository::open(&config_dir_1)?; let upstream_name = "remote"; @@ -250,8 +248,6 @@ mod integrated_test { ))?; // 2nd device - // - // devices: first, second let config_dir_2 = assert_fs::TempDir::new()?; let mut cmd2 = Command::cargo_bin("xdbm")?; cmd2.arg("-c") @@ -275,7 +271,6 @@ mod integrated_test { assert!(config_dir_2.join("backups").join("first.yml").exists()); assert!(config_dir_2.join("backups").join("second.yml").exists()); - // sync std::process::Command::new("git") .arg("push") .current_dir(&config_dir_2) @@ -292,11 +287,6 @@ mod integrated_test { .success(); // Add storage - // - // devices: first, second - // storages: - // - gdrive @ sample_storage (online) - // - first: sample_storage let sample_storage = assert_fs::TempDir::new()?; let mut cmd_add_storage_1 = Command::cargo_bin("xdbm")?; cmd_add_storage_1 @@ -318,13 +308,6 @@ mod integrated_test { .success() .stdout(predicate::str::contains("")); // Add storage (directory) - // - // devices: first, second - // storages: - // - gdrive (online) - // - first: sample_storage - // - gdrive_docs (subdir of sample_storage/foo/bar) - // - first let sample_directory = &sample_storage.join("foo").join("bar"); DirBuilder::new().recursive(true).create(sample_directory)?; Command::cargo_bin("xdbm")? @@ -356,14 +339,6 @@ mod integrated_test { .success(); // bind - // - // devices: first, second - // storages: - // - gdrive (online) - // - first: sample_storage - // - gdrive_docs (subdir of sample_storage/foo/bar) - // - first - // - second: sample_directory Command::cargo_bin("xdbm")? .arg("-c") .arg(config_dir_2.path()) @@ -379,16 +354,6 @@ mod integrated_test { .stdout(predicate::str::contains("")); // storage 3 - // - // devices: first, second - // storages: - // - gdrive (online) - // - first: sample_storage - // - gdrive_docs (subdir of sample_storage/foo/bar) - // - first - // - second: sample_directory - // - nas (online) - // - second: sample_storage_2 let sample_storage_2 = assert_fs::TempDir::new()?; Command::cargo_bin("xdbm")? .arg("-c") @@ -419,19 +384,6 @@ mod integrated_test { .stdout(predicate::str::contains("gdrive_docs").and(predicate::str::contains("nas"))); // backup add - // - // devices: first, second - // storages: - // - gdrive (online) - // - first: sample_storage - // - gdrive_docs (subdir of sample_storage/foo/bar) - // - first - // - second: sample_directory - // - nas (online) - // - second: sample_storage_2 - // backups: - // - foodoc: second - // - sample_storage_2/foo/bar -> sample_directory/docs let backup_src = &sample_storage_2.join("foo").join("bar"); DirBuilder::new().recursive(true).create(backup_src)?; let backup_dest = &sample_directory.join("docs"); @@ -486,19 +438,6 @@ mod integrated_test { ); // backup done - // - // devices: first, second - // storages: - // - gdrive (online) - // - first: sample_storage - // - gdrive_docs (subdir of sample_storage/foo/bar) - // - first - // - second: sample_directory - // - nas (online) - // - second: sample_storage_2 - // backups: - // - foodoc: second - // - sample_storage_2/foo/bar -> sample_directory/docs (done 1) Command::cargo_bin("xdbm")? .arg("-c") .arg(config_dir_2.path()) @@ -509,274 +448,6 @@ mod integrated_test { .assert() .success(); - // backup list after backup done - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_2.path()) - .arg("backup") - .arg("list") - .assert() - .success() - .stdout( - predicate::str::contains("foodoc") - .and(predicate::str::contains("nas")) - .and(predicate::str::contains("gdrive_docs")) - .and(predicate::str::contains("---").not()), - ); - - // status - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_2.path()) - .arg("status") - .assert() - .success(); - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_2.path()) - .arg("status") - .arg("-s") - .arg(backup_src.clone().join("foo")) - .assert() - .success() - .stdout(predicate::str::contains("nas").and(predicate::str::contains("foodoc").not())); - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_2.path()) - .arg("status") - .arg("-sb") - .arg(backup_src.clone().join("foo")) - .assert() - .success() - .stdout( - predicate::str::contains("nas") - .and(predicate::str::contains("second")) - .and(predicate::str::contains("foodoc")), - ); - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_2.path()) - .arg("status") - .arg("-sb") - .arg(backup_src.clone().parent().unwrap()) - .assert() - .success() - .stdout( - predicate::str::contains("nas") - .and(predicate::str::contains("second").not()) - .and(predicate::str::contains("foodoc").not()), - ); - - std::process::Command::new("git") - .arg("push") - .current_dir(&config_dir_2) - .assert() - .success(); - std::process::Command::new("git") - .arg("pull") - .current_dir(&config_dir_1) - .assert() - .success(); - - // bind - // - // devices: first, second - // storages: - // - gdrive (online) - // - first: sample_storage - // - gdrive_docs (subdir of sample_storage/foo/bar) - // - first - // - second: sample_directory - // - nas (online) - // - first: sample_storage_2_first_path - // - second: sample_storage_2 - // backups: - // - foodoc: second - // - sample_storage_2/foo/bar -> sample_directory/docs (done 1) - let sample_storage_2_first_path = assert_fs::TempDir::new()?; - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_1.path()) - .arg("storage") - .arg("bind") - .arg("--alias") - .arg("sample2") - .arg("--path") - .arg(sample_storage_2_first_path.path()) - .arg("nas") - .assert() - .success() - .stdout(predicate::str::contains("")); - - // backup add - // - // devices: first, second - // storages: - // - gdrive (online) - // - first: sample_storage - // - gdrive_docs (subdir of sample_storage/foo/bar) - // - first - // - second: sample_directory - // - nas (online) - // - first: sample_storage_2_first_path - // - second: sample_storage_2 - // backups: - // - foodoc: second - // - sample_storage_2/foo/bar -> sample_directory/docs (done 1) - // - abcdbackup: first - // - sample_storage_2_first_path/abcd/efgh -> sample_storage/Downloads/abcd/efgh - let backup_src = &sample_storage_2_first_path.join("abcd").join("efgh"); - DirBuilder::new().recursive(true).create(backup_src)?; - let backup_dest = &sample_storage.join("Downloads").join("abcd").join("efgh"); - DirBuilder::new().recursive(true).create(backup_dest)?; - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_1.path()) - .arg("backup") - .arg("add") - .arg("--src") - .arg(backup_src) - .arg("--dest") - .arg(backup_dest) - .arg("abcdbackup") - .arg("external") - .arg("rsync") - .arg("note: nonsense") - .assert() - .success(); - - // backup add - // - // devices: first, second - // storages: - // - gdrive (online) - // - first: sample_storage - // - gdrive_docs (subdir of sample_storage/foo/bar) - // - first - // - second: sample_directory - // - nas (online) - // - first: sample_storage_2_first_path - // - second: sample_storage_2 - // backups: - // - foodoc: second - // - sample_storage_2/foo/bar -> sample_directory/docs (done 1) - // - abcdbackup: first - // - sample_storage_2_first_path/abcd/efgh -> sample_storage/Downloads/abcd/efgh - // - abcdsubbackup: first - // - sample_storage_2_first_path/abcd/efgh/sub -> sample_storage/Downloads/abcd/efgh/sub - let backup_src = &sample_storage_2_first_path - .join("abcd") - .join("efgh") - .join("sub"); - DirBuilder::new().recursive(true).create(backup_src)?; - let backup_dest = &sample_storage - .join("Downloads") - .join("abcd") - .join("efgh") - .join("sub"); - DirBuilder::new().recursive(true).create(backup_dest)?; - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_1.path()) - .arg("backup") - .arg("add") - .arg("--src") - .arg(backup_src) - .arg("--dest") - .arg(backup_dest) - .arg("abcdsubbackup") - .arg("external") - .arg("rsync") - .arg("note: only subdirectory") - .assert() - .success(); - - std::process::Command::new("git") - .arg("push") - .current_dir(&config_dir_1) - .assert() - .success(); - std::process::Command::new("git") - .arg("pull") - .current_dir(&config_dir_2) - .assert() - .success(); - - // backup add - // - // devices: first, second - // storages: - // - gdrive (online) - // - first: sample_storage - // - gdrive_docs (subdir of sample_storage/foo/bar) - // - first - // - second: sample_directory - // - nas (online) - // - first: sample_storage_2_first_path - // - second: sample_storage_2 - // backups: - // - foodoc: second - // - sample_storage_2/foo/bar -> sample_directory/docs (done 1) - // - abcdbackup: first - // - sample_storage_2_first_path/abcd/efgh -> sample_storage/Downloads/abcd/efgh - // - abcdsubbackup: first - // - sample_storage_2_first_path/abcd/efgh/sub -> sample_storage/Downloads/abcd/efgh/sub - // - abcdbackup2: second - // - sample_storage_2/abcd/efgh -> sample_directory/Downloads/abcd/efgh - let backup_src = &sample_storage_2.join("abcd").join("efgh"); - DirBuilder::new().recursive(true).create(backup_src)?; - let backup_dest = &sample_directory.join("Downloads").join("abcd").join("efgh"); - DirBuilder::new().recursive(true).create(backup_dest)?; - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_2.path()) - .arg("backup") - .arg("add") - .arg("--src") - .arg(backup_src) - .arg("--dest") - .arg(backup_dest) - .arg("abcdbackup2") - .arg("external") - .arg("rsync") - .arg("note: only subdirectory") - .assert() - .success(); - - // status - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_2.path()) - .arg("status") - .arg("-sb") - .arg(backup_src) - .assert() - .success() - .stdout( - predicate::str::contains("nas") - .and(predicate::str::contains("first")) - .and(predicate::str::contains("abcdbackup")) - .and(predicate::str::contains("abcdsubbackup").not()) - .and(predicate::str::contains("second")) - .and(predicate::str::contains("abcdbackup2")), - ); - Command::cargo_bin("xdbm")? - .arg("-c") - .arg(config_dir_2.path()) - .arg("status") - .arg("-sb") - .arg(backup_src.join("sub")) - .assert() - .success() - .stdout( - predicate::str::contains("nas") - .and(predicate::str::contains("first")) - .and(predicate::str::contains("abcdbackup")) - .and(predicate::str::contains("abcdsubbackup")) - .and(predicate::str::contains("second")) - .and(predicate::str::contains("abcdbackup2")), - ); - Ok(()) } }