Refactor layout

refactor
Dennis Schwerdel 2018-03-09 23:31:20 +01:00
parent 0b5a485a26
commit ca1916145f
5 changed files with 159 additions and 89 deletions

View File

@ -4,29 +4,37 @@ use ::prelude::*;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::sync::Arc;
pub struct BackupRepository {
layout: Arc<RepositoryLayout>,
repo: Repository
}
impl BackupRepository {
pub fn create<P: AsRef<Path>, R: AsRef<Path>>(path: P, config: &Config, remote: R) -> Result<Self, RepositoryError> {
let layout = Arc::new(RepositoryLayout::new(path.as_ref()));
Ok(BackupRepository {
repo: try!(Repository::create(path, config, remote))
layout: layout.clone(),
repo: try!(Repository::create(layout, config, remote))
})
}
#[allow(unknown_lints, useless_let_if_seq)]
pub fn open<P: AsRef<Path>>(path: P, online: bool) -> Result<Self, RepositoryError> {
let layout = Arc::new(RepositoryLayout::new(path.as_ref()));
Ok(BackupRepository {
repo: try!(Repository::open(path, online))
layout: layout.clone(),
repo: try!(Repository::open(layout, online))
})
}
pub fn import<P: AsRef<Path>, R: AsRef<Path>>(path: P, remote: R, key_files: Vec<String>) -> Result<Self, RepositoryError> {
let layout = Arc::new(RepositoryLayout::new(path.as_ref()));
Ok(BackupRepository {
repo: try!(Repository::import(path, remote, key_files))
layout: layout.clone(),
repo: try!(Repository::import(layout, remote, key_files))
})
}
@ -77,7 +85,7 @@ impl BackupRepository {
}
pub fn get_layout(&self) -> &RepositoryLayout {
&self.repo.layout
&self.layout
}
pub fn create_backup_recursively<P: AsRef<Path>>(&mut self, path: P, reference: Option<&Backup>, options: &BackupOptions) -> Result<Backup, RepositoryError> {

View File

@ -5,7 +5,7 @@ pub use repository::chunking::{ChunkerType, Chunker, ChunkerStatus, ChunkerError
pub use repository::{Repository, Backup, Config, RepositoryError, RepositoryInfo, Inode, FileType,
IntegrityError, BackupFileError, BackupError, BackupOptions, BundleAnalysis,
FileData, DiffType, InodeError, RepositoryLayout, Location,
RepositoryStatistics};
RepositoryStatistics, ChunkRepositoryLayout};
pub use repository::index::{Index, IndexError, IndexStatistics};
pub use backups::mount::FuseFilesystem;
pub use translation::CowStr;

View File

@ -117,7 +117,7 @@ fn load_bundles(
pub struct BundleDb {
pub layout: RepositoryLayout,
pub layout: Arc<ChunkRepositoryLayout>,
uploader: Option<Arc<BundleUploader>>,
crypto: Arc<Mutex<Crypto>>,
local_bundles: HashMap<BundleId, StoredBundle>,
@ -127,7 +127,7 @@ pub struct BundleDb {
impl BundleDb {
fn new(layout: RepositoryLayout, crypto: Arc<Mutex<Crypto>>) -> Self {
fn new(layout: Arc<ChunkRepositoryLayout>, crypto: Arc<Mutex<Crypto>>) -> Self {
BundleDb {
layout,
crypto,
@ -239,7 +239,7 @@ impl BundleDb {
}
pub fn open(
layout: RepositoryLayout,
layout: Arc<ChunkRepositoryLayout>,
crypto: Arc<Mutex<Crypto>>,
online: bool
) -> Result<(Self, Vec<BundleInfo>, Vec<BundleInfo>), BundleDbError> {
@ -251,7 +251,7 @@ impl BundleDb {
Ok((self_, new, gone))
}
pub fn create(layout: &RepositoryLayout) -> Result<(), BundleDbError> {
pub fn create(layout: Arc<ChunkRepositoryLayout>) -> Result<(), BundleDbError> {
try!(fs::create_dir_all(layout.remote_bundles_path()).context(
&layout.remote_bundles_path() as
&Path
@ -332,11 +332,14 @@ impl BundleDb {
fn copy_remote_bundle_to_cache(&mut self, bundle: &StoredBundle) -> Result<(), BundleDbError> {
let id = bundle.id();
let (folder, filename) = self.layout.local_bundle_path(&id, self.local_bundles.len());
try!(fs::create_dir_all(&folder).context(&folder as &Path));
let dst_path = self.layout.local_bundle_path(&id, self.local_bundles.len());
{
let folder = dst_path.parent().unwrap();
try!(fs::create_dir_all(folder).context(folder as &Path));
}
let bundle = try!(bundle.copy_to(
self.layout.base_path(),
folder.join(filename)
dst_path
));
self.local_bundles.insert(id, bundle);
Ok(())
@ -347,8 +350,7 @@ impl BundleDb {
if bundle.info.mode == BundleMode::Meta {
try!(self.copy_remote_bundle_to_cache(&bundle))
}
let (folder, filename) = self.layout.remote_bundle_path(self.remote_bundles.len());
let dst_path = folder.join(filename);
let dst_path = self.layout.remote_bundle_path(&bundle.id(),self.remote_bundles.len());
let src_path = self.layout.base_path().join(bundle.path);
bundle.path = dst_path
.strip_prefix(self.layout.base_path())

View File

@ -2,6 +2,35 @@ use prelude::*;
use std::path::{Path, PathBuf};
pub trait ChunkRepositoryLayout {
fn base_path(&self) -> &Path;
fn index_path(&self) -> PathBuf;
fn bundle_map_path(&self) -> PathBuf;
fn local_locks_path(&self) -> PathBuf;
fn remote_path(&self) -> PathBuf;
fn remote_exists(&self) -> bool;
fn remote_locks_path(&self) -> PathBuf;
fn remote_bundles_path(&self) -> PathBuf;
fn local_bundles_path(&self) -> PathBuf;
fn remote_bundle_path(&self, bundle: &BundleId, count: usize) -> PathBuf;
fn local_bundle_path(&self, bundle: &BundleId, count: usize) -> PathBuf;
fn temp_bundles_path(&self) -> PathBuf;
fn temp_bundle_path(&self) -> PathBuf;
fn local_bundle_cache_path(&self) -> PathBuf;
fn remote_bundle_cache_path(&self) -> PathBuf;
fn dirtyfile_path(&self) -> PathBuf;
fn config_path(&self) -> PathBuf;
fn keys_path(&self) -> PathBuf;
fn excludes_path(&self) -> PathBuf;
fn backups_path(&self) -> PathBuf;
fn backup_path(&self, name: &str) -> PathBuf;
fn remote_readme_path(&self) -> PathBuf;
}
#[derive(Clone)]
pub struct RepositoryLayout(PathBuf);
@ -10,39 +39,19 @@ impl RepositoryLayout {
RepositoryLayout(path.as_ref().to_path_buf())
}
#[inline]
pub fn base_path(&self) -> &Path {
&self.0
}
#[inline]
pub fn config_path(&self) -> PathBuf {
self.0.join("config.yaml")
}
#[inline]
pub fn excludes_path(&self) -> PathBuf {
self.0.join("excludes")
}
#[inline]
pub fn index_path(&self) -> PathBuf {
self.0.join("index")
}
#[inline]
pub fn keys_path(&self) -> PathBuf {
self.0.join("keys")
}
#[inline]
pub fn bundle_map_path(&self) -> PathBuf {
self.0.join("bundles.map")
}
#[inline]
pub fn local_locks_path(&self) -> PathBuf {
self.0.join("locks")
pub fn excludes_path(&self) -> PathBuf {
self.0.join("excludes")
}
#[inline]
@ -55,11 +64,6 @@ impl RepositoryLayout {
self.backups_path().join(format!("{}.backup", name))
}
#[inline]
pub fn remote_path(&self) -> PathBuf {
self.0.join("remote")
}
#[inline]
pub fn remote_exists(&self) -> bool {
self.remote_bundles_path().exists() && self.backups_path().exists() &&
@ -71,27 +75,7 @@ impl RepositoryLayout {
self.0.join("remote/README.md")
}
#[inline]
pub fn remote_locks_path(&self) -> PathBuf {
self.0.join("remote/locks")
}
#[inline]
pub fn remote_bundles_path(&self) -> PathBuf {
self.0.join("remote/bundles")
}
#[inline]
pub fn local_bundles_path(&self) -> PathBuf {
self.0.join("bundles/cached")
}
fn bundle_path(
&self,
bundle: &BundleId,
mut folder: PathBuf,
mut count: usize,
) -> (PathBuf, PathBuf) {
fn bundle_path(&self, bundle: &BundleId, mut folder: PathBuf, mut count: usize) -> PathBuf {
let file = bundle.to_string().to_owned() + ".bundle";
{
let mut rest = &file as &str;
@ -104,44 +88,123 @@ impl RepositoryLayout {
count /= 250;
}
}
(folder, file.into())
folder.join(Path::new(&file))
}
}
impl ChunkRepositoryLayout for RepositoryLayout {
#[inline]
fn base_path(&self) -> &Path {
&self.0
}
#[inline]
pub fn remote_bundle_path(&self, count: usize) -> (PathBuf, PathBuf) {
fn remote_exists(&self) -> bool {
self.remote_bundles_path().exists() && self.remote_locks_path().exists()
}
#[inline]
fn index_path(&self) -> PathBuf {
self.0.join("index")
}
#[inline]
fn bundle_map_path(&self) -> PathBuf {
self.0.join("bundles.map")
}
#[inline]
fn local_locks_path(&self) -> PathBuf {
self.0.join("locks")
}
#[inline]
fn remote_path(&self) -> PathBuf {
self.0.join("remote")
}
#[inline]
fn remote_locks_path(&self) -> PathBuf {
self.0.join("remote/locks")
}
#[inline]
fn remote_bundles_path(&self) -> PathBuf {
self.0.join("remote/bundles")
}
#[inline]
fn local_bundles_path(&self) -> PathBuf {
self.0.join("bundles/cached")
}
#[inline]
fn remote_bundle_path(&self, _bundle: &BundleId, count: usize) -> PathBuf {
self.bundle_path(&BundleId::random(), self.remote_bundles_path(), count)
}
#[inline]
pub fn local_bundle_path(&self, bundle: &BundleId, count: usize) -> (PathBuf, PathBuf) {
fn local_bundle_path(&self, bundle: &BundleId, count: usize) -> PathBuf {
self.bundle_path(bundle, self.local_bundles_path(), count)
}
#[inline]
pub fn temp_bundles_path(&self) -> PathBuf {
fn temp_bundles_path(&self) -> PathBuf {
self.0.join("bundles/temp")
}
#[inline]
pub fn temp_bundle_path(&self) -> PathBuf {
self.temp_bundles_path().join(
BundleId::random().to_string().to_owned() +
".bundle"
)
fn temp_bundle_path(&self) -> PathBuf {
self.temp_bundles_path().join(BundleId::random().to_string().to_owned() + ".bundle")
}
#[inline]
pub fn local_bundle_cache_path(&self) -> PathBuf {
fn local_bundle_cache_path(&self) -> PathBuf {
self.0.join("bundles/local.cache")
}
#[inline]
pub fn remote_bundle_cache_path(&self) -> PathBuf {
fn remote_bundle_cache_path(&self) -> PathBuf {
self.0.join("bundles/remote.cache")
}
#[inline]
pub fn dirtyfile_path(&self) -> PathBuf {
fn dirtyfile_path(&self) -> PathBuf {
self.0.join("dirty")
}
}
#[inline]
fn config_path(&self) -> PathBuf {
self.0.join("config.yaml")
}
#[inline]
fn keys_path(&self) -> PathBuf {
self.0.join("keys")
}
#[inline]
fn excludes_path(&self) -> PathBuf {
self.0.join("excludes")
}
#[inline]
fn backups_path(&self) -> PathBuf {
self.0.join("remote/backups")
}
#[inline]
fn backup_path(&self, name: &str) -> PathBuf {
self.backups_path().join(format!("{}.backup", name))
}
#[inline]
fn remote_readme_path(&self) -> PathBuf {
self.0.join("remote/README.md")
}
}

View File

@ -31,7 +31,7 @@ pub use self::backup::{BackupError, BackupOptions, DiffType};
pub use self::backup_file::{Backup, BackupFileError};
pub use self::integrity::IntegrityError;
pub use self::info::{RepositoryInfo, BundleAnalysis, RepositoryStatistics};
pub use self::layout::RepositoryLayout;
pub use self::layout::{RepositoryLayout, ChunkRepositoryLayout};
use self::bundle_map::BundleMap;
@ -74,7 +74,7 @@ impl index::Key for Hash {
}
pub struct Repository {
pub layout: RepositoryLayout,
pub layout: Arc<ChunkRepositoryLayout>,
pub config: Config,
index: Index<Hash, Location>,
crypto: Arc<Mutex<Crypto>>,
@ -93,12 +93,11 @@ pub struct Repository {
impl Repository {
pub fn create<P: AsRef<Path>, R: AsRef<Path>>(
path: P,
pub fn create<R: AsRef<Path>>(
layout: Arc<ChunkRepositoryLayout>,
config: &Config,
remote: R,
) -> Result<Self, RepositoryError> {
let layout = RepositoryLayout::new(path.as_ref().to_path_buf());
try!(fs::create_dir(layout.base_path()));
try!(File::create(layout.excludes_path()).and_then(|mut f| {
f.write_all(DEFAULT_EXCLUDES)
@ -113,7 +112,7 @@ impl Repository {
));
try!(fs::create_dir_all(layout.remote_locks_path()));
try!(config.save(layout.config_path()));
try!(BundleDb::create(&layout));
try!(BundleDb::create(layout.clone()));
try!(Index::<Hash, Location>::create(
layout.index_path(),
&INDEX_MAGIC,
@ -121,12 +120,11 @@ impl Repository {
));
try!(BundleMap::create().save(layout.bundle_map_path()));
try!(fs::create_dir_all(layout.backups_path()));
Self::open(path, true)
Self::open(layout, true)
}
#[allow(unknown_lints, useless_let_if_seq)]
pub fn open<P: AsRef<Path>>(path: P, online: bool) -> Result<Self, RepositoryError> {
let layout = RepositoryLayout::new(path.as_ref().to_path_buf());
pub fn open(layout: Arc<ChunkRepositoryLayout>, online: bool) -> Result<Self, RepositoryError> {
if !layout.remote_exists() {
return Err(RepositoryError::NoRemote);
}
@ -220,17 +218,16 @@ impl Repository {
Ok(repo)
}
pub fn import<P: AsRef<Path>, R: AsRef<Path>>(
path: P,
pub fn import<R: AsRef<Path>>(
layout: Arc<ChunkRepositoryLayout>,
remote: R,
key_files: Vec<String>,
) -> Result<Self, RepositoryError> {
let path = path.as_ref();
let mut repo = try!(Repository::create(path, &Config::default(), remote));
let mut repo = try!(Repository::create(layout.clone(), &Config::default(), remote));
for file in key_files {
try!(repo.crypto.lock().unwrap().register_keyfile(file));
}
repo = try!(Repository::open(path, true));
repo = try!(Repository::open(layout, true));
let mut backups: Vec<(String, Backup)> = try!(repo.get_all_backups()).into_iter().collect();
backups.sort_by_key(|&(_, ref b)| b.timestamp);
if let Some((name, backup)) = backups.pop() {