diff --git a/src/actions.rs b/src/actions.rs new file mode 100644 index 0000000..c297fdd --- /dev/null +++ b/src/actions.rs @@ -0,0 +1,63 @@ +use tokio::fs; +use tokio::process::Command; + +use std::path::{Path, PathBuf}; + +/// Actions available for file +#[derive(Clone, Debug, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Action { + /// Run given script with 1st argument. It will be ran in parent directory for given file + Script(Box), + /// Move given file to new destination + Move(Box), + /// Print message and do nothing + Echo(String), + /// Move to trash + Trash, +} + +impl Action { + pub async fn run(self, source: PathBuf, execute: bool) { + if execute { self.execute(source).await } else { self.dry_run(source).await } + } + + pub async fn dry_run(self, source: PathBuf) { + match self { + Action::Script(ref script) => println!("Execute {script:?} {source:?}"), + Action::Move(ref dest) => println!("Move {source:?} -> {dest:?}"), + Action::Echo(ref message) => println!("{source:?} - {message}"), + Action::Trash => println!("Move {source:?} to trash"), + } + } + + pub async fn execute(self, source: PathBuf) { + match self { + Action::Script(ref script) => { + Command::new(script.as_ref()) + .arg(&source) + .current_dir(source.parent().unwrap()) + .spawn() + .expect("Couldnt spawn process") + .wait() + .await + .expect("Child exited abnormally"); + } + + Action::Move(ref dest_dir) => { + let dest = crate::job::normalise_path(dest_dir).join(source.file_name().unwrap()); + if let Err(err) = fs::rename(&source, &dest).await { + if err.raw_os_error() == Some(libc::EXDEV) { + panic!("X dev"); + } else { + panic!("Cannot move {source:?} -> {dest:?}: {err:?}"); + } + } + } + + Action::Echo(ref message) => println!("{source:?} - {message}"), + + Action::Trash => trash::delete(source).unwrap(), + } + } +} diff --git a/src/job.rs b/src/job.rs index 055c2de..8ed5205 100644 --- a/src/job.rs +++ b/src/job.rs @@ -3,25 +3,24 @@ use color_eyre::eyre::Result; use std::path::{Path, PathBuf}; use tokio::fs; -use tokio::process::Command; use tokio_stream::wrappers::ReadDirStream; -use futures::prelude::*; - use serde::Deserialize; use crate::filters::Filter; +use crate::actions::Action; /// Definition of the job files #[derive(Debug, Deserialize)] pub struct Job { - filters: Vec>, + filter: Box, location: PathBuf, actions: Vec, } impl Job { - pub async fn run(&self) -> Result + '_> { + /// Returns stream of actions that should be executed + pub async fn actions(&self) -> Result + '_> { let loc = normalise_path(&self.location); let dir = ReadDirStream::new(fs::read_dir(&loc).await?); @@ -29,7 +28,7 @@ impl Job { Ok(async_stream::stream! { for await entry in dir { let entry = entry.unwrap(); - if self.matches_filters(&entry.path()).await { + if self.filter.matches(&entry.path()).await { for action in &self.actions { yield (action.clone(), entry.path()) } @@ -37,61 +36,9 @@ impl Job { } }) } - - async fn matches_filters(&self, path: &Path) -> bool { - stream::iter(&self.filters).all(|f| f.matches(path)).await - } -} - -/// Actions available for file -#[derive(Clone, Debug, Deserialize)] -#[serde(untagged)] -pub enum Action { - /// Run given script with 1st argument. It will be ran in parent directory for given file - Script { script: Box }, - /// Move given file to new destination - Move { move_to: Box }, - /// Print message and do nothing - Echo { message: String }, - /// Move to trash - Trash, -} - -impl Action { - pub async fn execute(self, source: PathBuf) { - match self { - Action::Script { ref script } => { - Command::new(script.as_ref()) - .arg(&source) - .current_dir(source.parent().unwrap()) - .spawn() - .expect("Couldnt spawn process") - .wait() - .await - .expect("Child exited abnormally"); - } - - Action::Move { - move_to: ref dest_dir, - } => { - let dest = normalise_path(dest_dir).join(source.file_name().unwrap()); - if let Err(err) = fs::rename(&source, &dest).await { - if err.raw_os_error() == Some(libc::EXDEV) { - panic!("X dev"); - } else { - panic!("Cannot move {source:?} -> {dest:?}: {err:?}"); - } - } - } - - Action::Echo { ref message } => println!("{source:?} - {message}"), - - Action::Trash => trash::delete(source).unwrap(), - } - } } -fn normalise_path(path: &Path) -> PathBuf { +pub(crate) fn normalise_path(path: &Path) -> PathBuf { match path.strip_prefix("~") { Ok(prefix) => std::env::home_dir().unwrap().join(prefix), Err(_) => path.to_owned(),