From 02ddaf27b6309ece82fd2c2ac75aca9027ea154c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyryl=20P=C5=82otnicki?= Date: Sun, 1 Sep 2019 17:03:27 +0100 Subject: [PATCH] saving repo items --- src/error.rs | 17 +++++-- src/lib.rs | 2 +- src/repository.rs | 105 +++++++++++++++++++++++++++--------------- src/restore.rs | 8 +++- tests/system_tests.rs | 4 +- 5 files changed, 91 insertions(+), 45 deletions(-) diff --git a/src/error.rs b/src/error.rs index 0a358dd..7d975da 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,27 +1,38 @@ use std::io; use failure::Fail; +use std::path::StripPrefixError; #[derive(Debug, Fail)] pub enum BakareError { #[fail(display = "io error")] - IOError, + IOError(Option), #[fail(display = "backup source same as repository")] SourceSameAsRepository, #[fail(display = "repository path is not absolute")] RepositoryPathNotAbsolute, #[fail(display = "path to store is not absolute")] PathToStoreNotAbsolute, + #[fail(display = "directory used in place of a file")] + DirectoryNotFile, + #[fail(display = "corrupted repository - cannot find file")] + CorruptedRepoNoFile, } impl From for BakareError { fn from(e: io::Error) -> Self { - BakareError::IOError + BakareError::IOError(Some(e)) } } impl From for BakareError { fn from(e: walkdir::Error) -> Self { - BakareError::IOError + BakareError::IOError(e.into_io_error()) + } +} + +impl From for BakareError { + fn from(_: StripPrefixError) -> Self { + BakareError::IOError(None) } } diff --git a/src/lib.rs b/src/lib.rs index 81430c6..af22b42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ pub mod source; pub mod repository; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct ItemVersion<'a>(&'a str); #[derive(Copy, Clone)] diff --git a/src/repository.rs b/src/repository.rs index 3ad0440..7994d22 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -1,15 +1,12 @@ use std::fs; -use std::path::{Path, PathBuf}; +use std::path::Path; -use walkdir::{DirEntry, WalkDir}; +use walkdir::WalkDir; use crate::error::BakareError; use crate::IndexVersion; use crate::IndexViewReadonly; use crate::ItemVersion; -use std::borrow::Cow; -use std::rc::Rc; -use std::sync::Arc; /// represents a place where backup is stored an can be restored from. /// right now only on-disk directory storage is supported @@ -22,10 +19,11 @@ pub struct Repository<'a> { newest_index_version: IndexVersion, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct RepositoryItem<'a> { version: ItemVersion<'a>, relative_path: Box, + absolute_path: Box, } pub struct RepositoryIterator<'a> { @@ -34,6 +32,28 @@ pub struct RepositoryIterator<'a> { current_item_number: usize, } +impl<'a> RepositoryItem<'a> { + pub fn save(&self, save_to: &Path) -> Result<(), BakareError> { + if !save_to.is_absolute() { + return Err(BakareError::PathToStoreNotAbsolute); + } + + let target_path = save_to.join(self.relative_path.clone()); + let parent = target_path.parent().unwrap(); + if !parent.exists() { + println!("Creating {}", parent.display()); + fs::create_dir_all(parent)?; + } + if !self.absolute_path.exists() { + return Err(BakareError::CorruptedRepoNoFile); + } + println!("Saving {} to {}", self.absolute_path.display(), target_path.display()); + fs::copy(self.absolute_path.clone(), target_path.clone())?; + + Ok(()) + } +} + impl<'a> Iterator for RepositoryIterator<'a> { type Item = &'a RepositoryItem<'a>; @@ -55,44 +75,25 @@ impl<'a> RepositoryItem<'a> { } impl<'a> Repository<'a> { - fn get_all_files_recursively(path: &Path) -> Result>, BakareError> { - let path_text = path.to_string_lossy(); - let walker = WalkDir::new(path); - - let mut result = vec![]; - - for maybe_entry in walker { - let entry = maybe_entry?; - if entry.path() != path { - if entry.path().is_file() { - result.push(Box::from(path)); - } - if entry.path().is_dir() { - let children = Repository::get_all_files_recursively(entry.path())?; - - for child in children { - result.push(child); - } - } - } - } - - Ok(result) - } pub fn open(path: &Path) -> Result { if !path.is_absolute() { return Err(BakareError::RepositoryPathNotAbsolute); } - println!("opening repository at {}", path.display()); let all_files = Repository::get_all_files_recursively(path)?; - let all_items: Vec = all_files + let all_items: Result, BakareError> = all_files .into_iter() - .map(|p| RepositoryItem { - version: ItemVersion(""), - relative_path: p, + .map(|p| { + let relative_path = Box::from(p.strip_prefix(path)?); + Ok(RepositoryItem { + version: ItemVersion(""), + relative_path, + absolute_path: Box::from(p), + }) }) .collect(); + let mut all_items = all_items?; + all_items.sort(); let version = IndexVersion; println!("opened repository at {} - {} items present", path.display(), all_items.len()); @@ -132,17 +133,47 @@ impl<'a> Repository<'a> { fs::copy(source_path, destination_path)?; self.index.items.push(RepositoryItem { version: ItemVersion(""), - relative_path: Box::from(destination_path), + relative_path: Box::from(destination_path.strip_prefix(self.path)?), + absolute_path: Box::from(destination_path), }); } Ok(()) } pub fn item(&self, path: &Path) -> Option<&RepositoryItem> { - self.index.items.iter().find(|i| *i.relative_path == *path) + let relative_path = { + if path.is_relative() { + Some(path) + } else { + path.strip_prefix(self.path).ok() + } + }; + if let Some(relative_path) = relative_path { + self.index.items.iter().find(|i| *i.relative_path == *relative_path) + } else { + None + } } pub fn newest_version_for(&self, item: RepositoryItem) -> ItemVersion { ItemVersion("") } + + fn get_all_files_recursively(path: &Path) -> Result>, BakareError> { + let walker = WalkDir::new(path); + + let mut result = vec![]; + + for maybe_entry in walker { + let entry = maybe_entry?; + if entry.path() == path { + continue; + } + if entry.path().is_file() { + result.push(Box::from(entry.path())); + } + } + + Ok(result) + } } diff --git a/src/restore.rs b/src/restore.rs index 2c84f78..32e0941 100644 --- a/src/restore.rs +++ b/src/restore.rs @@ -14,8 +14,11 @@ pub struct Engine<'a> { } impl<'a> Engine<'a> { - pub fn new(repository: &'a Repository, target_path: &'a Path) -> Self { - Engine { repository, target_path } + pub fn new(repository: &'a Repository, target_path: &'a Path) -> Result { + if !target_path.is_absolute() { + return Err(BakareError::PathToStoreNotAbsolute); + } + Ok(Engine { repository, target_path }) } pub fn restore_all(&self) -> Result<(), BakareError> { @@ -27,6 +30,7 @@ impl<'a> Engine<'a> { fn restore(&self, item: &RepositoryItem) -> Result<(), BakareError> { println!("restoring {:#?}", item); + item.save(self.target_path)?; Ok(()) } diff --git a/tests/system_tests.rs b/tests/system_tests.rs index aa40143..2def78f 100644 --- a/tests/system_tests.rs +++ b/tests/system_tests.rs @@ -32,7 +32,7 @@ fn restore_older_version_of_file() -> Result<(), BakareError> { let file_path = source.file_path(relative_path_text); let new_contents = "totally new contents"; let restore_target = tempdir()?; - let restore_engine = restore::Engine::new(&restore_repository, &restore_target.path()); + let restore_engine = restore::Engine::new(&restore_repository, &restore_target.path())?; let old_contents = "some old contents"; { @@ -82,7 +82,7 @@ fn assert_same_after_restore(source_path: &Path) -> Result<(), BakareError> { } { let restore_repository = Repository::open(repository_path.as_path())?; - let restore_engine = restore::Engine::new(&restore_repository, &restore_target); + let restore_engine = restore::Engine::new(&restore_repository, &restore_target)?; restore_engine.restore_all()?; } let are_source_and_target_different = is_different(source_path, &restore_target).unwrap();