feat: abstract State
parent
6e216aa88f
commit
4ec336eb86
|
@ -63,24 +63,6 @@ impl Delta {
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modify the given state by applying this delta's changes to it
|
|
||||||
pub fn apply(&self, state: &mut HashMap<PathBuf, HashSet<PathBuf>>) {
|
|
||||||
// First we add new files, then we remove the old ones
|
|
||||||
for (dir, added) in self.added.iter() {
|
|
||||||
if let Some(current) = state.get_mut(dir) {
|
|
||||||
current.extend(added.iter().cloned());
|
|
||||||
} else {
|
|
||||||
state.insert(dir.clone(), added.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dir, removed) in self.removed.iter() {
|
|
||||||
if let Some(current) = state.get_mut(dir) {
|
|
||||||
current.retain(|k| !removed.contains(k));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the difference between this delta and the other delta.
|
// Calculate the difference between this delta and the other delta.
|
||||||
//
|
//
|
||||||
// The difference simply means removing all adds and removes that are also performed in the
|
// The difference simply means removing all adds and removes that are also performed in the
|
||||||
|
|
|
@ -4,7 +4,7 @@ mod meta;
|
||||||
pub use config::ManagerConfig;
|
pub use config::ManagerConfig;
|
||||||
pub use meta::MetaManager;
|
pub use meta::MetaManager;
|
||||||
|
|
||||||
use super::Backup;
|
use super::{Backup, State};
|
||||||
use crate::other;
|
use crate::other;
|
||||||
use chrono::SubsecRound;
|
use chrono::SubsecRound;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
@ -72,10 +72,10 @@ where
|
||||||
|
|
||||||
let mut backup = if !current_chain.is_empty() {
|
let mut backup = if !current_chain.is_empty() {
|
||||||
let previous_backup = current_chain.last().unwrap();
|
let previous_backup = current_chain.last().unwrap();
|
||||||
let state = Backup::state(current_chain);
|
let previous_state = State::from(current_chain.iter().map(|b| &b.delta));
|
||||||
|
|
||||||
Backup::create_from(
|
Backup::create_from(
|
||||||
state,
|
previous_state,
|
||||||
previous_backup.start_time,
|
previous_backup.start_time,
|
||||||
&self.backup_dir,
|
&self.backup_dir,
|
||||||
&self.dirs,
|
&self.dirs,
|
||||||
|
|
|
@ -2,11 +2,13 @@ mod delta;
|
||||||
mod io_ext;
|
mod io_ext;
|
||||||
pub mod manager;
|
pub mod manager;
|
||||||
mod path;
|
mod path;
|
||||||
|
mod state;
|
||||||
|
|
||||||
use delta::Delta;
|
use delta::Delta;
|
||||||
pub use manager::Manager;
|
pub use manager::Manager;
|
||||||
pub use manager::ManagerConfig;
|
pub use manager::ManagerConfig;
|
||||||
pub use manager::MetaManager;
|
pub use manager::MetaManager;
|
||||||
|
pub use state::State;
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use flate2::read::GzDecoder;
|
use flate2::read::GzDecoder;
|
||||||
|
@ -14,7 +16,7 @@ use flate2::write::GzEncoder;
|
||||||
use flate2::Compression;
|
use flate2::Compression;
|
||||||
use path::PathExt;
|
use path::PathExt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -61,18 +63,6 @@ impl<T: Clone> Backup<T> {
|
||||||
self.metadata = Some(metadata);
|
self.metadata = Some(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve the state of the list of backups by applying their deltas in-order to an initially
|
|
||||||
/// empty state.
|
|
||||||
pub fn state(backups: &Vec<Self>) -> HashMap<PathBuf, HashSet<PathBuf>> {
|
|
||||||
let mut state: HashMap<PathBuf, HashSet<PathBuf>> = HashMap::new();
|
|
||||||
|
|
||||||
for backup in backups {
|
|
||||||
backup.delta.apply(&mut state);
|
|
||||||
}
|
|
||||||
|
|
||||||
state
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new Full backup, populated with the given directories.
|
/// Create a new Full backup, populated with the given directories.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -141,7 +131,7 @@ impl<T: Clone> Backup<T> {
|
||||||
///
|
///
|
||||||
/// The `Backup` instance describing this new backup.
|
/// The `Backup` instance describing this new backup.
|
||||||
pub fn create_from<P: AsRef<Path>>(
|
pub fn create_from<P: AsRef<Path>>(
|
||||||
previous_state: HashMap<PathBuf, HashSet<PathBuf>>,
|
previous_state: State,
|
||||||
previous_start_time: chrono::DateTime<Utc>,
|
previous_start_time: chrono::DateTime<Utc>,
|
||||||
backup_dir: P,
|
backup_dir: P,
|
||||||
dirs: &Vec<(PathBuf, PathBuf)>,
|
dirs: &Vec<(PathBuf, PathBuf)>,
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
use crate::backup::Delta;
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
/// Struct that represents a current state for a backup. This struct acts as a smart pointer around
|
||||||
|
/// a HashMap.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct State(HashMap<PathBuf, HashSet<PathBuf>>);
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
State(HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply the delta to the current state.
|
||||||
|
pub fn apply(&mut self, delta: &Delta) {
|
||||||
|
// First we add new files, then we remove the old ones
|
||||||
|
for (dir, added) in delta.added.iter() {
|
||||||
|
if let Some(current) = self.0.get_mut(dir) {
|
||||||
|
current.extend(added.iter().cloned());
|
||||||
|
} else {
|
||||||
|
self.0.insert(dir.clone(), added.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dir, removed) in delta.removed.iter() {
|
||||||
|
if let Some(current) = self.0.get_mut(dir) {
|
||||||
|
current.retain(|k| !removed.contains(k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for State
|
||||||
|
where
|
||||||
|
T: IntoIterator,
|
||||||
|
T::Item: Borrow<Delta>,
|
||||||
|
{
|
||||||
|
fn from(deltas: T) -> Self {
|
||||||
|
let mut state = State::new();
|
||||||
|
|
||||||
|
for delta in deltas {
|
||||||
|
state.apply(delta.borrow());
|
||||||
|
}
|
||||||
|
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<HashMap<PathBuf, HashSet<PathBuf>>> for State {
|
||||||
|
fn as_ref(&self) -> &HashMap<PathBuf, HashSet<PathBuf>> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for State {
|
||||||
|
type Target = HashMap<PathBuf, HashSet<PathBuf>>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for State {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue