use crate::command_runner::CommandRunner; use crate::storage::Storage; use crate::symbols::Symbol; use async_trait::async_trait; use std::borrow::Borrow; use std::error::Error; use std::fs; use std::io; use std::marker::PhantomData; use std::path::Path; use std::str::FromStr; #[derive(Debug, PartialEq)] pub enum StorageDirection { Load, Store, } #[derive(Debug)] pub struct SavedDirectory<_C, C, P, S> { path: P, storage: S, dir: StorageDirection, command_runner: C, phantom: PhantomData<_C>, } impl<_C, C, P, S> SavedDirectory<_C, C, P, S> { pub fn new(path: P, storage: S, dir: StorageDirection, command_runner: C) -> Self { Self { path, storage, dir, command_runner, phantom: PhantomData::default(), } } } #[async_trait(?Send)] impl<_C: CommandRunner, C: Borrow<_C>, P: AsRef, S: Storage> Symbol for SavedDirectory<_C, C, P, S> { async 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::Store) } 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 = self.storage.recent_date()?; let output = self .command_runner .borrow() .get_output( "sh", args![ "-c", format!( "find {} -printf '%T@\\n' | sort -r | head -n1 | grep '^[0-9]\\+' -o", self.path.as_ref().to_str().unwrap() ), ], ) .await?; let modified_date = u64::from_str(String::from_utf8(output)?.trim_end())?; if if self.dir == StorageDirection::Store { modified_date > dump_date } else { dump_date > modified_date } { let output = self .command_runner .borrow() .run_with_args( "diff", args!["-rq", self.storage.read_filename()?, self.path.as_ref()], ) .await?; match output.status.code() { Some(0) => Ok(true), Some(1) => Ok(false), _ => Err(String::from_utf8(output.stderr)?.into()), } } else { Ok(true) } } async fn execute(&self) -> Result<(), Box> { if self.dir == StorageDirection::Load { self .command_runner .borrow() .run_successfully("rm", args!["-rf", self.path.as_ref()]) .await?; self .command_runner .borrow() .run_successfully( "cp", args!["-a", self.storage.read_filename()?, self.path.as_ref()], ) .await } else { self .command_runner .borrow() .run_successfully( "cp", args!["-a", self.path.as_ref(), self.storage.write_filename()], ) .await } } } #[cfg(test)] mod test {}