use std::borrow::{Borrow, Cow}; use std::error::Error; use std::fmt; use std::fs; use std::io; use std::path::Path; use std::str::FromStr; use command_runner::CommandRunner; use resources::Resource; use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner}; use storage::Storage; #[derive(Debug, PartialEq)] pub enum StorageDirection { Load, Save } pub struct StoredDirectory<'a, S> where S: Storage { path: Cow<'a, str>, storage: S, dir: StorageDirection, command_runner: &'a CommandRunner } impl<'a, S> StoredDirectory<'a, S> where S: Storage { pub fn new(path: Cow<'a, str>, storage: S, dir: StorageDirection, command_runner: &'a CommandRunner) -> Self { StoredDirectory { path: path, storage: storage, dir: dir, command_runner: command_runner } } } impl<'a, S> fmt::Display for StoredDirectory<'a, S> where S: Storage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Stored directory {} ({:?})", self.path, self.dir) } } impl<'a, S> Symbol for StoredDirectory<'a, S> where S: Storage { fn target_reached(&self) -> Result> { let metadata = fs::metadata(self.path.as_ref()); // Check if dir exists if let Err(e) = metadata { return if e.kind() == io::ErrorKind::NotFound { Ok(self.dir == StorageDirection::Save) } else { Err(Box::new(e)) }; } if !metadata.unwrap().is_dir() { return Err(Box::new(io::Error::new(io::ErrorKind::AlreadyExists, "Could not create a directory, non-directory file exists"))); } let dump_date = try!(self.storage.recent_date()); let output = try!(self.command_runner.get_output("sh", &["-c", &format!("find {} -printf '%T@\\n' | sort -r | head -n1 | grep '^[0-9]\\+' -o", self.path)])); let modified_date = try!(u64::from_str(try!(String::from_utf8(output)).trim_right())); if if self.dir == StorageDirection::Save { modified_date > dump_date } else { dump_date > modified_date } { let output = try!(self.command_runner.run_with_args("diff", &["-rq", &try!(self.storage.read_filename()), self.path.borrow()])); match output.status.code() { Some(0) => Ok(true), Some(1) => Ok(false), _ => Err(try!(String::from_utf8(output.stderr)).into()) } } else { Ok(true) } } fn execute(&self) -> Result<(), Box> { if self.dir == StorageDirection::Load { try!(self.command_runner.run_successfully("rm", &["-rf", self.path.borrow()])); self.command_runner.run_successfully("cp", &["-a", &try!(self.storage.read_filename()), self.path.borrow()]) } else { self.command_runner.run_successfully("cp", &["-a", self.path.borrow(), &self.storage.write_filename()]) } } fn get_prerequisites(&self) -> Vec { if self.dir == StorageDirection::Save { return vec![]; } if let Some(parent) = Path::new(self.path.as_ref()).parent() { vec![ Resource::new("dir", parent.to_string_lossy()) ] } else { vec![] } } fn provides(&self) -> Option> { if self.dir == StorageDirection::Load { Some(vec![ Resource::new("dir", self.path.to_string()) ]) } else { None } } fn as_action<'b>(&'b self, runner: &'b SymbolRunner) -> Box { Box::new(SymbolAction::new(runner, self)) } fn into_action<'b>(self: Box, runner: &'b SymbolRunner) -> Box where Self: 'b { Box::new(OwnedSymbolAction::new(runner, *self)) } } #[cfg(test)] mod test { }