use std::error::Error; use std::fmt; use std::fs::{metadata, File}; use std::io::copy; use std::marker::PhantomData; use std::path::Path; use crate::resources::Resource; use crate::symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner}; pub struct Concat { target: D, sources: S, source_item: PhantomData, } impl Concat { pub fn new(sources: S, target: D) -> Self { Self { target, sources, source_item: PhantomData::default(), } } } impl, D: AsRef, I: AsRef> Symbol for Concat { fn target_reached(&self) -> Result> { let target = self.target.as_ref(); if !target.exists() { return Ok(false); } let target_date = metadata(target)?.modified()?; for source in self.sources.as_ref() { if metadata(source)?.modified()? > target_date { return Ok(false); } } Ok(true) } fn execute(&self) -> Result<(), Box> { let mut file = File::create(self.target.as_ref())?; for source in self.sources.as_ref() { copy(&mut File::open(source)?, &mut file)?; } Ok(()) } fn get_prerequisites(&self) -> Vec { let mut r: Vec = self .sources .as_ref() .iter() .map(|s| Resource::new("file", s.as_ref().to_str().unwrap())) .collect(); if let Some(parent) = self.target.as_ref().parent() { r.push(Resource::new("dir", parent.to_str().unwrap())) } r } fn as_action<'a>(&'a self, runner: &'a dyn SymbolRunner) -> Box { Box::new(SymbolAction::new(runner, self)) } fn into_action<'a>(self: Box, runner: &'a dyn SymbolRunner) -> Box where Self: 'a, { Box::new(OwnedSymbolAction::new(runner, *self)) } } impl, I> fmt::Display for Concat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "Concat {}", self.target.as_ref().display()) } }