diff --git a/src/backups.rs b/src/backups.rs index 5b39e61..2816a6a 100644 --- a/src/backups.rs +++ b/src/backups.rs @@ -33,22 +33,27 @@ pub struct BackupTarget { /// Use `String` for serialization/deserialization. pub storage: String, /// Relative path to the `storage`. - pub path: PathBuf, + pub path: Vec, } impl BackupTarget { - pub fn new(storage_name: String, relative_path: PathBuf) -> Self { - 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 { storage: storage_name, path: relative_path, - } + }) } /// Get full path of the [`BackupTarget`]. pub fn path(&self, storages: &Storages, device: &Device) -> Option { let parent = storages.get(&self.storage).unwrap(); let parent_path = parent.mount_path(device)?; - Some(parent_path.join(self.path.clone())) + Some(parent_path.join(self.path.clone().iter().collect::())) } } diff --git a/src/cmd_backup.rs b/src/cmd_backup.rs index 9c58378..cab7a9e 100644 --- a/src/cmd_backup.rs +++ b/src/cmd_backup.rs @@ -89,8 +89,8 @@ fn new_backup( Ok(Backup::new( name, device.name(), - src_target, - dest_target, + src_target?, + dest_target?, command, )) } @@ -361,9 +361,9 @@ mod test { &storages, )?; assert!(backup.source().storage == "online"); - assert_eq!(backup.source().path, PathBuf::from("docs")); + assert_eq!(backup.source().path, vec!["docs"]); assert!(backup.destination().storage == "online"); - assert!(backup.destination().path == PathBuf::from("tmp")); + assert!(backup.destination().path == vec!["tmp"]); Ok(()) } } diff --git a/src/cmd_status.rs b/src/cmd_status.rs index ba1ad87..c93e641 100644 --- a/src/cmd_status.rs +++ b/src/cmd_status.rs @@ -146,7 +146,7 @@ fn parent_backups<'a>( #[cfg(test)] mod test { - use std::path::PathBuf; + use std::{path::PathBuf, vec}; use crate::{ backups::{self, ExternallyInvoked}, @@ -201,11 +201,11 @@ mod test { device1.name().to_string(), backups::BackupTarget { storage: "storage_1".to_string(), - path: PathBuf::from("bar"), + path: vec!["bar".to_string()], }, backups::BackupTarget { storage: "storage_1".to_string(), - path: PathBuf::from("hoge"), + path: vec!["hoge".to_string()], }, backups::BackupCommand::ExternallyInvoked(ExternallyInvoked::new( "cmd".to_string(), @@ -217,11 +217,11 @@ mod test { device2.name().to_string(), backups::BackupTarget { storage: "storage_1".to_string(), - path: PathBuf::from(""), + path: vec!["".to_string()], }, backups::BackupTarget { storage: "storage_3".to_string(), - path: PathBuf::from("foo"), + path: vec!["foo".to_string()], }, backups::BackupCommand::ExternallyInvoked(ExternallyInvoked::new( "cmd".to_string(), diff --git a/src/storages/directory.rs b/src/storages/directory.rs index f1e460c..1777ec3 100644 --- a/src/storages/directory.rs +++ b/src/storages/directory.rs @@ -2,6 +2,7 @@ use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; +use std::path::PathBuf; use std::{collections::BTreeMap, fmt, path}; use crate::devices; @@ -17,7 +18,7 @@ pub struct Directory { /// ID of parent storage. parent: String, /// Relative path to the parent storage. - relative_path: path::PathBuf, + relative_path: Vec, pub notes: String, /// [`devices::Device`] name and localinfo pairs. local_infos: BTreeMap, @@ -34,14 +35,19 @@ impl Directory { relative_path: path::PathBuf, notes: String, local_infos: BTreeMap, - ) -> Directory { - Directory { + ) -> 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 { name, parent, relative_path, notes, local_infos, - } + }) } pub fn try_from_device_path( @@ -56,23 +62,23 @@ impl Directory { .context("Failed to compare diff of paths")?; trace!("Selected parent: {}", parent.name()); let local_info = LocalInfo::new(alias, path); - Ok(Directory::new( + 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::new( - self.name, - self.parent, - self.relative_path, + Directory { + name: self.name, + parent: self.parent, + relative_path: self.relative_path, notes, - self.local_infos, - ) + local_infos: self.local_infos, + } } /// Resolve mount path of directory with current device. @@ -82,7 +88,7 @@ impl Directory { .context("Can't find parent storage")? .mount_path(device) .context("Can't find mount path")?; - Ok(parent_mount_path.join(self.relative_path.clone())) + Ok(parent_mount_path.join(self.relative_path.clone().iter().collect::())) } } @@ -133,7 +139,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.display(), + relative_path = self.relative_path.iter().collect::().display(), notes = self.notes, ) } @@ -177,7 +183,8 @@ 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();