use std::path::{Path, PathBuf};
use crate::utils::path as path_utils;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum FsChange {
Move(FileToRename),
Remove(FileToRemove),
Update(FileUpdate),
}
impl FsChange {
pub fn mov(
source: PathBuf,
destination: PathBuf,
local_watched_path: &Path,
remote_synched_path: &Path,
) -> Self {
Self::Move(FileToRename::new(
source,
destination,
local_watched_path,
remote_synched_path,
))
}
pub fn remove(
removed_path: PathBuf,
local_watched_path: &Path,
remote_synched_path: &Path,
) -> Self {
Self::Remove(FileToRemove::new(
removed_path,
local_watched_path,
remote_synched_path,
))
}
pub fn update(
changed_path: PathBuf,
local_watched_path: &Path,
remote_synched_path: &Path,
) -> Self {
Self::Update(FileUpdate::new(
changed_path,
local_watched_path,
remote_synched_path,
))
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct FileToRename {
source: PathBuf,
destination: PathBuf,
}
impl FileToRename {
fn new(
source: PathBuf,
destination: PathBuf,
local_watched_path: &Path,
remote_synched_path: &Path,
) -> Self {
Self {
source: remote_relative_path(&source, local_watched_path, remote_synched_path),
destination: remote_relative_path(
&destination,
local_watched_path,
remote_synched_path,
),
}
}
pub fn source(&self) -> &Path {
self.source.as_path()
}
pub fn destination(&self) -> &Path {
self.destination.as_path()
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct FileToRemove {
path: PathBuf,
}
impl FileToRemove {
fn new(removed_path: PathBuf, local_watched_path: &Path, remote_synched_path: &Path) -> Self {
Self {
path: remote_relative_path(&removed_path, local_watched_path, remote_synched_path),
}
}
pub fn path(&self) -> &Path {
self.path.as_path()
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct FileUpdate {
host_bridge: PathBuf,
remote: PathBuf,
}
impl FileUpdate {
fn new(changed_path: PathBuf, local_watched_path: &Path, remote_synched_path: &Path) -> Self {
Self {
remote: remote_relative_path(&changed_path, local_watched_path, remote_synched_path),
host_bridge: changed_path,
}
}
pub fn host_bridge(&self) -> &Path {
self.host_bridge.as_path()
}
pub fn remote(&self) -> &Path {
self.remote.as_path()
}
}
fn remote_relative_path(
target: &Path,
local_watched_path: &Path,
remote_synched_path: &Path,
) -> PathBuf {
let local_diff = path_utils::diff_paths(target, local_watched_path);
match local_diff {
None => remote_synched_path.to_path_buf(),
Some(p) => {
let mut remote = remote_synched_path.to_path_buf();
remote.push(p);
remote
}
}
}
#[cfg(test)]
mod test {
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn should_get_remote_relative_path_from_subdir() {
assert_eq!(
remote_relative_path(
Path::new("/tmp/abc/test.txt"),
Path::new("/tmp"),
Path::new("/home/foo")
)
.as_path(),
Path::new("/home/foo/abc/test.txt")
);
}
#[test]
fn should_get_remote_relative_path_same_path() {
assert_eq!(
remote_relative_path(
Path::new("/tmp/abc/test.txt"),
Path::new("/tmp/abc/test.txt"),
Path::new("/home/foo/test.txt")
)
.as_path(),
Path::new("/home/foo/test.txt")
);
}
#[test]
fn should_make_fs_change_move_from_same_directory() {
let change = FsChange::mov(
PathBuf::from("/tmp/foo.txt"),
PathBuf::from("/tmp/bar.txt"),
Path::new("/tmp"),
Path::new("/home/foo"),
);
if let FsChange::Move(change) = change {
assert_eq!(change.source(), Path::new("/home/foo/foo.txt"));
assert_eq!(change.destination(), Path::new("/home/foo/bar.txt"));
} else {
panic!("not a Move");
}
}
#[test]
fn should_make_fs_change_move_from_subdirectory() {
let change = FsChange::mov(
PathBuf::from("/tmp/abc/foo.txt"),
PathBuf::from("/tmp/abc/bar.txt"),
Path::new("/tmp/abc"),
Path::new("/home/foo"),
);
if let FsChange::Move(change) = change {
assert_eq!(change.source(), Path::new("/home/foo/foo.txt"));
assert_eq!(change.destination(), Path::new("/home/foo/bar.txt"));
} else {
panic!("not a Move");
}
}
#[test]
fn should_make_fs_change_remove_from_same_directory() {
let change = FsChange::remove(
PathBuf::from("/tmp/bar.txt"),
Path::new("/tmp/bar.txt"),
Path::new("/home/foo/bar.txt"),
);
if let FsChange::Remove(change) = change {
assert_eq!(change.path(), Path::new("/home/foo/bar.txt"));
} else {
panic!("not a remove");
}
}
#[test]
fn should_make_fs_change_remove_from_subdirectory() {
let change = FsChange::remove(
PathBuf::from("/tmp/abc/bar.txt"),
Path::new("/tmp/abc"),
Path::new("/home/foo"),
);
if let FsChange::Remove(change) = change {
assert_eq!(change.path(), Path::new("/home/foo/bar.txt"));
} else {
panic!("not a remove");
}
}
#[test]
fn should_make_fs_change_update_from_same_directory() {
let change = FsChange::update(
PathBuf::from("/tmp/bar.txt"),
Path::new("/tmp/bar.txt"),
Path::new("/home/foo/bar.txt"),
);
if let FsChange::Update(change) = change {
assert_eq!(change.host_bridge(), Path::new("/tmp/bar.txt"),);
assert_eq!(change.remote(), Path::new("/home/foo/bar.txt"));
} else {
panic!("not an update");
}
}
#[test]
fn should_make_fs_change_update_from_subdirectory() {
let change = FsChange::update(
PathBuf::from("/tmp/abc/foo.txt"),
Path::new("/tmp"),
Path::new("/home/foo/temp"),
);
if let FsChange::Update(change) = change {
assert_eq!(change.host_bridge(), Path::new("/tmp/abc/foo.txt"),);
assert_eq!(change.remote(), Path::new("/home/foo/temp/abc/foo.txt"));
} else {
panic!("not an update");
}
}
}