From 6e73872eb0012fff13e003686a6b3cd841f51e4c Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 20 Nov 2024 17:26:53 +0200 Subject: [PATCH] feat(ark-cli): add watch command to monitor directory changes and update index Signed-off-by: Tarek --- ark-cli/Cargo.toml | 3 +- ark-cli/USAGE.md | 10 +++++ ark-cli/src/commands/mod.rs | 2 + ark-cli/src/commands/watch.rs | 74 +++++++++++++++++++++++++++++++++++ ark-cli/src/main.rs | 1 + ark-cli/src/util.rs | 7 ++-- 6 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 ark-cli/src/commands/watch.rs diff --git a/ark-cli/Cargo.toml b/ark-cli/Cargo.toml index 08655206..ea661d3d 100644 --- a/ark-cli/Cargo.toml +++ b/ark-cli/Cargo.toml @@ -18,6 +18,7 @@ serde_json = "1.0.82" chrono = "0.4.34" anyhow = "1.0.80" thiserror = "1.0.57" +futures = "0.3" # REGISTRAR log = { version = "0.4.17", features = ["release_max_level_off"] } @@ -25,7 +26,7 @@ lazy_static = "1.4.0" canonical-path = "2.0.2" -fs-index = { path = "../fs-index" } +fs-index = { path = "../fs-index", features = ["watch"] } fs-atomic-versions = { path = "../fs-atomic-versions" } fs-metadata = { path = "../fs-metadata" } fs-properties = { path = "../fs-properties" } diff --git a/ark-cli/USAGE.md b/ark-cli/USAGE.md index 9a77906e..867b5e4e 100644 --- a/ark-cli/USAGE.md +++ b/ark-cli/USAGE.md @@ -136,6 +136,16 @@ $ /tmp/ark-cli list -t --filter=search 22-207093268 search,engine ``` +### Watch a Directory for Changes + +You can watch a directory for changes and automatically update the index by running the following command: + +```sh +ark-cli watch [PATH] +``` + +If you don't provide a path, the current directory (`.`) will be used by default. This command continuously monitors the specified directory for file changes (create, modify, or remove) and updates the index accordingly. It's useful for keeping your index in sync with the latest changes in the folder. + ## :zap: Low-level utilities :zap: There are commands which could be useful with time, when you grasp the basic concepts. Some of these commands also can be useful for debugging [ArkLib](https://github.com/ARK-Builders/ark-rust). diff --git a/ark-cli/src/commands/mod.rs b/ark-cli/src/commands/mod.rs index eab0cc1a..631c3ec6 100644 --- a/ark-cli/src/commands/mod.rs +++ b/ark-cli/src/commands/mod.rs @@ -8,6 +8,7 @@ mod list; mod monitor; mod render; pub mod storage; +mod watch; pub use file::{file_append, file_insert, format_file, format_line}; @@ -18,6 +19,7 @@ pub enum Commands { Monitor(monitor::Monitor), Render(render::Render), List(list::List), + Watch(watch::Watch), #[command(about = "Manage links")] Link { #[clap(subcommand)] diff --git a/ark-cli/src/commands/watch.rs b/ark-cli/src/commands/watch.rs new file mode 100644 index 00000000..6ef1d1e8 --- /dev/null +++ b/ark-cli/src/commands/watch.rs @@ -0,0 +1,74 @@ +use std::path::PathBuf; + +use futures::{pin_mut, StreamExt}; + +use fs_index::{watch_index, WatchEvent}; + +use crate::{AppError, DateTime, ResourceId, Utc}; + +#[derive(Clone, Debug, clap::Args)] +#[clap( + name = "watch", + about = "Watch the ark managed folder for changes and update the index accordingly" +)] +pub struct Watch { + #[clap( + help = "Path to the directory to watch for changes", + default_value = ".", + value_parser + )] + path: PathBuf, +} + +impl Watch { + pub async fn run(&self) -> Result<(), AppError> { + let stream = watch_index::<_, ResourceId>(&self.path); + pin_mut!(stream); + + while let Some(value) = stream.next().await { + match value { + WatchEvent::UpdatedOne(update) => { + println!("Index updated with a single file change"); + + let added = update.added(); + let removed = update.removed(); + for file in added { + let time_stamped_path = file.1.iter().next().unwrap(); + let file_path = time_stamped_path.item(); + let last_modified = time_stamped_path.last_modified(); + let last_modified: DateTime = last_modified.into(); + println!( + "\tAdded file: {:?} (last modified: {})", + file_path, + last_modified.format("%d/%m/%Y %T") + ); + } + for file in removed { + println!("\tRemoved file with hash: {:?}", file); + } + } + WatchEvent::UpdatedAll(update) => { + println!("Index fully updated"); + + let added = update.added(); + let removed = update.removed(); + + for file in added { + let time_stamped_path = file.1.iter().next().unwrap(); + let file_path = time_stamped_path.item(); + let last_modified = time_stamped_path.last_modified(); + println!( + "\tAdded file: {:?} (last modified: {:?})", + file_path, last_modified + ); + } + for file in removed { + println!("\tRemoved file with hash: {:?}", file); + } + } + } + } + + Ok(()) + } +} diff --git a/ark-cli/src/main.rs b/ark-cli/src/main.rs index e8029c18..7158df00 100644 --- a/ark-cli/src/main.rs +++ b/ark-cli/src/main.rs @@ -71,6 +71,7 @@ async fn run() -> Result<()> { Monitor(monitor) => monitor.run()?, Render(render) => render.run()?, List(list) => list.run()?, + Watch(watch) => watch.run().await?, Link { subcommand } => match subcommand { Create(create) => create.run().await?, Load(load) => load.run()?, diff --git a/ark-cli/src/util.rs b/ark-cli/src/util.rs index 40eff290..c5db3536 100644 --- a/ark-cli/src/util.rs +++ b/ark-cli/src/util.rs @@ -179,10 +179,9 @@ pub fn translate_storage( root: &Option, storage: &str, ) -> Option<(PathBuf, Option)> { - if let Ok(path) = PathBuf::from_str(storage) { - if path.exists() && path.is_dir() { - return Some((path, None)); - } + let Ok(path) = PathBuf::from_str(storage); + if path.exists() && path.is_dir() { + return Some((path, None)); } match storage.to_lowercase().as_str() {