diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 2c5ef42..1c94591 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -37,6 +37,7 @@ actix-rt = { workspace = true } # boilerplate derive_more = { workspace = true } derive-with = { workspace = true } +thiserror = { workspace = true } # Webhooks serde = { workspace = true } @@ -46,6 +47,9 @@ time = { workspace = true } secrecy = { workspace = true } standardwebhooks = { workspace = true } +# file watcher (linux) +inotify = { workspace = true } + [dev-dependencies] # Testing assert2 = { workspace = true } diff --git a/crates/cli/README.md b/crates/cli/README.md index f8b52f9..f6cbee1 100644 --- a/crates/cli/README.md +++ b/crates/cli/README.md @@ -523,7 +523,6 @@ stateDiagram-v2 cli --> forge cli --> repo_actor cli --> webhook_actor - cli --> file_watcher_actor forge --> core forge --> forge_forgejo diff --git a/crates/cli/src/file_watcher.rs b/crates/cli/src/file_watcher.rs new file mode 100644 index 0000000..1235c1e --- /dev/null +++ b/crates/cli/src/file_watcher.rs @@ -0,0 +1,70 @@ +// +use actix::prelude::*; + +use actix::Recipient; +use inotify::{EventMask, Inotify, WatchMask}; + +use std::{path::PathBuf, time::Duration}; + +const CHECK_INTERVAL: Duration = Duration::from_secs(1); + +#[derive(Debug, Clone, Message)] +#[rtype(result = "()")] +pub struct WatchFile; + +#[derive(Debug, Message)] +#[rtype(result = "()")] +pub struct FileUpdated; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("io")] + Io(#[from] std::io::Error), +} + +pub struct FileWatcher { + inotify: Inotify, + recipient: Recipient, + run_interval: Option, +} +impl FileWatcher { + pub fn new(path: PathBuf, recipient: Recipient) -> Result { + let inotify = Inotify::init()?; + inotify.watches().add( + path, + WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE | WatchMask::ATTRIB, + )?; + Ok(Self { + inotify, + recipient, + run_interval: None, + }) + } +} +impl Actor for FileWatcher { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + tracing::info!("Starting file watcher actor"); + self.run_interval + .replace(ctx.run_interval(CHECK_INTERVAL, |_act, ctx| { + ctx.notify(WatchFile); + })); + } +} + +impl Handler for FileWatcher { + type Result = (); + + fn handle(&mut self, _msg: WatchFile, _ctx: &mut Self::Context) -> Self::Result { + let mut buffer = [0u8; 4096]; + if let Ok(mut events) = self.inotify.read_events(&mut buffer) { + if events.any(|event| { + event.mask.contains(EventMask::MODIFY) || event.mask.contains(EventMask::ATTRIB) + }) { + tracing::info!("File modified"); + self.recipient.do_send(FileUpdated); + }; + } + } +} diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index ee3ee78..724a8bc 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,4 +1,5 @@ // +mod file_watcher; mod init; mod server; diff --git a/crates/server-actor/MESSAGES.md b/crates/cli/src/server/actor/MESSAGES.md similarity index 100% rename from crates/server-actor/MESSAGES.md rename to crates/cli/src/server/actor/MESSAGES.md diff --git a/crates/cli/src/server/actor/handlers/file_updated.rs b/crates/cli/src/server/actor/handlers/file_updated.rs index 64fef78..7aa6d49 100644 --- a/crates/cli/src/server/actor/handlers/file_updated.rs +++ b/crates/cli/src/server/actor/handlers/file_updated.rs @@ -1,10 +1,12 @@ -//- +// use actix::prelude::*; use git_next_core::server::ServerConfig; -use git_next_file_watcher_actor::FileUpdated; -use crate::server::actor::{messages::ReceiveServerConfig, ServerActor}; +use crate::{ + file_watcher::FileUpdated, + server::actor::{messages::ReceiveServerConfig, ServerActor}, +}; impl Handler for ServerActor { type Result = (); diff --git a/crates/cli/src/server/mod.rs b/crates/cli/src/server/mod.rs index 9fbf0ce..d5136a1 100644 --- a/crates/cli/src/server/mod.rs +++ b/crates/cli/src/server/mod.rs @@ -6,9 +6,9 @@ mod tests; use actix::prelude::*; +use crate::file_watcher::{FileUpdated, FileWatcher}; use actor::ServerActor; use git_next_core::git::RepositoryFactory; -use git_next_file_watcher_actor::{FileUpdated, FileWatcher}; use kxio::{fs::FileSystem, network::Network}; use tracing::{error, info, level_filters::LevelFilter}; diff --git a/crates/file-watcher-actor/Cargo.toml b/crates/file-watcher-actor/Cargo.toml index c3b048f..5b2b48f 100644 --- a/crates/file-watcher-actor/Cargo.toml +++ b/crates/file-watcher-actor/Cargo.toml @@ -5,31 +5,3 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } description = "Config file watcher for git-next, the trunk-based development manager" - -[dependencies] -# logging -tracing = { workspace = true } - -# file watcher -inotify = { workspace = true } - -# Webhooks -# bytes = { workspace = true } -# warp = { workspace = true } - -# boilerplate -# derive_more = { workspace = true } -thiserror = { workspace = true } - -# Actors -actix = { workspace = true } - -[dev-dependencies] -# Testing -# assert2 = { workspace = true } - -[lints.clippy] -nursery = { level = "warn", priority = -1 } -# pedantic = "warn" -unwrap_used = "warn" -expect_used = "warn" diff --git a/crates/file-watcher-actor/README.md b/crates/file-watcher-actor/README.md index ddc70e2..b90af45 100644 --- a/crates/file-watcher-actor/README.md +++ b/crates/file-watcher-actor/README.md @@ -7,3 +7,5 @@ development workflows where each commit must pass CI before being included in the main branch. See [git-next](https://crates.io/crates/git-next) for more information. + +N.B. this crate has been merged into [git-next](https://crates.io/git-next). diff --git a/crates/file-watcher-actor/src/lib.rs b/crates/file-watcher-actor/src/lib.rs index 2bdb140..23c7c85 100644 --- a/crates/file-watcher-actor/src/lib.rs +++ b/crates/file-watcher-actor/src/lib.rs @@ -1,68 +1 @@ -use actix::prelude::*; - -use actix::Recipient; -use inotify::{EventMask, Inotify, WatchMask}; -use std::{path::PathBuf, time::Duration}; - -const CHECK_INTERVAL: Duration = Duration::from_secs(1); - -#[derive(Debug, Clone, Message)] -#[rtype(result = "()")] -pub struct WatchFile; - -#[derive(Debug, Message)] -#[rtype(result = "()")] -pub struct FileUpdated; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("io")] - Io(#[from] std::io::Error), -} - -pub struct FileWatcher { - inotify: Inotify, - recipient: Recipient, - run_interval: Option, -} -impl FileWatcher { - pub fn new(path: PathBuf, recipient: Recipient) -> Result { - let inotify = Inotify::init()?; - inotify.watches().add( - path, - WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE | WatchMask::ATTRIB, - )?; - Ok(Self { - inotify, - recipient, - run_interval: None, - }) - } -} -impl Actor for FileWatcher { - type Context = Context; - - fn started(&mut self, ctx: &mut Self::Context) { - tracing::info!("Starting file watcher actor"); - self.run_interval - .replace(ctx.run_interval(CHECK_INTERVAL, |_act, ctx| { - ctx.notify(WatchFile); - })); - } -} - -impl Handler for FileWatcher { - type Result = (); - - fn handle(&mut self, _msg: WatchFile, _ctx: &mut Self::Context) -> Self::Result { - let mut buffer = [0u8; 4096]; - if let Ok(mut events) = self.inotify.read_events(&mut buffer) { - if events.any(|event| { - event.mask.contains(EventMask::MODIFY) || event.mask.contains(EventMask::ATTRIB) - }) { - tracing::info!("File modified"); - self.recipient.do_send(FileUpdated); - }; - } - } -} +// moved to /crates/cli/src/file_watcher diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 6541ce0..ecc9a24 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -5,11 +5,3 @@ edition = { workspace = true } license = { workspace = true } repository = { workspace = true } description = "[deprecated crate] server for git-next, the trunk-based development manager" - - - -[lints.clippy] -nursery = { level = "warn", priority = -1 } -# pedantic = "warn" -unwrap_used = "warn" -expect_used = "warn"