Simple tool for automatic file management

chore: extract actions to separate file

hauleth.dev 7513b7c9 2784a34e

verified
Changed files
+69 -59
src
+63
src/actions.rs
···
+
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<Path>),
+
/// Move given file to new destination
+
Move(Box<Path>),
+
/// 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(),
+
}
+
}
+
}
+6 -59
src/job.rs
···
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<Box<dyn Filter>>,
+
filter: Box<dyn Filter>,
location: PathBuf,
actions: Vec<Action>,
}
impl Job {
-
pub async fn run(&self) -> Result<impl tokio_stream::Stream<Item = (Action, PathBuf)> + '_> {
+
/// Returns stream of actions that should be executed
+
pub async fn actions(&self) -> Result<impl tokio_stream::Stream<Item = (Action, PathBuf)> + '_> {
let loc = normalise_path(&self.location);
let dir = ReadDirStream::new(fs::read_dir(&loc).await?);
···
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())
}
···
}
})
}
-
-
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<Path> },
-
/// Move given file to new destination
-
Move { move_to: Box<Path> },
-
/// 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(),