Skip to content

Commit

Permalink
replace old config and allow initialization configuration
Browse files Browse the repository at this point in the history
This also allows correct configuration of PollWatcher via notify-debouncer-mini
  • Loading branch information
0xpr03 committed Aug 12, 2022
1 parent ae9134c commit 29376ad
Show file tree
Hide file tree
Showing 18 changed files with 128 additions and 151 deletions.
37 changes: 0 additions & 37 deletions README.md
Expand Up @@ -25,43 +25,6 @@ As used by: [alacritty], [cargo watch], [cobalt], [docket], [mdBook], [pax],
[rdiff], [rust-analyzer], [timetrack], [watchexec], [xi-editor], [watchfiles],
and others.

## Base Installation

```toml
[dependencies]
notify = "5.0.0-pre.15"
```

## Usage

A basic example

```rust
use notify::{RecommendedWatcher, RecursiveMode, Result, watcher};
use std::time::Duration;

fn main() -> Result<()> {
// Automatically select the best implementation for your platform.
// You can also access each implementation directly e.g. INotifyWatcher.
let mut watcher = watcher(Duration::from_secs(2))?;

// Add a path to be watched. All files and directories at that path and
// below will be monitored for changes.
watcher.watch("/home/test/notify", RecursiveMode::Recursive)?;

// This is a simple loop, but you may want to use more complex logic here,
// for example to handle I/O.
for event in &watcher {
match event {
Ok(event) => println!("changed: {:?}", event.path),
Err(err) => println!("watch error: {:?}", err),
};
}

Ok(())
}
```

## Platforms

- Linux / Android: inotify
Expand Down
4 changes: 4 additions & 0 deletions examples/Cargo.toml
Expand Up @@ -21,6 +21,10 @@ path = "monitor_raw.rs"
name = "debounced"
path = "debounced.rs"

[[example]]
name = "debounced_custom"
path = "debounced_full_custom.rs"

[[example]]
name = "poll_sysfs"
path = "poll_sysfs.rs"
Expand Down
4 changes: 2 additions & 2 deletions examples/async_monitor.rs
Expand Up @@ -2,7 +2,7 @@ use futures::{
channel::mpsc::{channel, Receiver},
SinkExt, StreamExt,
};
use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher};
use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher, Config};
use std::path::Path;

/// Async, futures channel based event watching
Expand All @@ -28,7 +28,7 @@ fn async_watcher() -> notify::Result<(RecommendedWatcher, Receiver<notify::Resul
futures::executor::block_on(async {
tx.send(res).await.unwrap();
})
})?;
}, Config::default())?;

Ok((watcher, rx))
}
Expand Down
2 changes: 1 addition & 1 deletion examples/debounced.rs
@@ -1,6 +1,6 @@
use std::{path::Path, time::Duration};

use notify::{RecursiveMode, Watcher};
use notify::{RecursiveMode};
use notify_debouncer_mini::new_debouncer;

/// Example for debouncer
Expand Down
6 changes: 3 additions & 3 deletions examples/debounced_full_custom.rs
@@ -1,7 +1,7 @@
use std::{path::Path, time::Duration};

use notify::{RecursiveMode, Watcher};
use notify_debouncer_mini::new_debouncer;
use notify::{RecursiveMode, Config};
use notify_debouncer_mini::new_debouncer_opt;

/// Debouncer with custom backend and waiting for exit
fn main() {
Expand All @@ -18,7 +18,7 @@ fn main() {
// setup debouncer
let (tx, rx) = std::sync::mpsc::channel();
// select backend via fish operator, here PollWatcher backend
let mut debouncer = new_debouncer_opt::<_,notify::PollWatcher>(Duration::from_secs(2), None, tx).unwrap();
let mut debouncer = new_debouncer_opt::<_,notify::PollWatcher>(Duration::from_secs(2), None, tx, Config::default()).unwrap();

debouncer
.watcher()
Expand Down
2 changes: 1 addition & 1 deletion examples/hot_reload_tide/src/main.rs
Expand Up @@ -38,7 +38,7 @@ async fn main() -> tide::Result<()> {
Err(error) => println!("Error reloading config: {:?}", error),
}
}
})?;
},notify::Config::default())?;

watcher.watch(Path::new(CONFIG_PATH), RecursiveMode::Recursive)?;

Expand Down
4 changes: 2 additions & 2 deletions examples/monitor_raw.rs
@@ -1,4 +1,4 @@
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use notify::{RecommendedWatcher, RecursiveMode, Watcher, Config};
use std::path::Path;

fn main() {
Expand All @@ -16,7 +16,7 @@ fn watch<P: AsRef<Path>>(path: P) -> notify::Result<()> {

// Automatically select the best implementation for your platform.
// You can also access each implementation directly e.g. INotifyWatcher.
let mut watcher = RecommendedWatcher::new(tx)?;
let mut watcher = RecommendedWatcher::new(tx, Config::default())?;

// Add a path to be watched. All files and directories at that path and
// below will be monitored for changes.
Expand Down
12 changes: 5 additions & 7 deletions examples/poll_sysfs.rs
Expand Up @@ -3,8 +3,7 @@
/// This example can't be demonstrated under windows, it might be relevant for network shares
#[cfg(not(target_os = "windows"))]
fn not_windows_main() -> notify::Result<()> {
use notify::poll::PollWatcherConfig;
use notify::{PollWatcher, RecursiveMode, Watcher};
use notify::{PollWatcher, RecursiveMode, Watcher, Config};
use std::path::Path;
use std::time::Duration;

Expand All @@ -27,13 +26,12 @@ fn not_windows_main() -> notify::Result<()> {

println!("watching {:?}...", paths);
// configure pollwatcher backend
let config = PollWatcherConfig {
compare_contents: true, // crucial part for pseudo filesystems
poll_interval: Duration::from_secs(2),
};
let config = Config::default()
.with_compare_contents(true) // crucial part for pseudo filesystems
.with_poll_interval(Duration::from_secs(2));
let (tx, rx) = std::sync::mpsc::channel();
// create pollwatcher backend
let mut watcher = PollWatcher::with_config(tx, config)?;
let mut watcher = PollWatcher::new(tx, config)?;
for path in paths {
// watch all paths
watcher.watch(&path, RecursiveMode::Recursive)?;
Expand Down
16 changes: 9 additions & 7 deletions examples/watcher_kind.rs
@@ -1,18 +1,20 @@
use std::{path::Path, time::Duration};
use notify::*;

use notify::{poll::PollWatcherConfig, *};
// exampale of detecting the recommended watcher kind
fn main() {
let (tx, rx) = std::sync::mpsc::channel();
// This example is a little bit misleading as you can just create one Config and use it for all watchers.
// That way the pollwatcher specific stuff is still configured, if it should be used.
let mut watcher: Box<dyn Watcher> = if RecommendedWatcher::kind() == WatcherKind::PollWatcher {
// custom config for PollWatcher kind
let config = PollWatcherConfig {
poll_interval: Duration::from_secs(1),
..Default::default()
};
Box::new(PollWatcher::with_config(tx, config).unwrap())
// you
let config = Config::default()
.with_poll_interval(Duration::from_secs(1));
Box::new(PollWatcher::new(tx, config).unwrap())
} else {
// use default config for everything else
Box::new(RecommendedWatcher::new(tx).unwrap())
Box::new(RecommendedWatcher::new(tx, Config::default()).unwrap())
};

// watch some stuff
Expand Down
15 changes: 9 additions & 6 deletions notify-debouncer-mini/src/lib.rs
Expand Up @@ -4,7 +4,6 @@
//!
//! ```toml
//! [dependencies]
//! notify = "5.0.0-pre.15"
//! notify-debouncer-mini = "0.1"
//! ```
//!
Expand All @@ -13,10 +12,12 @@
//! ```rust,no_run
//! # use std::path::Path;
//! # use std::time::Duration;
//! use notify::{Watcher, RecursiveMode, Result};
//! use notify_debouncer_mini::{new_debouncer,DebounceEventResult};
//! use notify_debouncer_mini::{notify::*,new_debouncer,DebounceEventResult};
//!
//! # fn main() {
//! // setup initial watcher backend config
//! let config = Config::default();
//!
//! // Select recommended watcher for debouncer.
//! // Using a callback here, could also be a channel.
//! let mut debouncer = new_debouncer(Duration::from_secs(2), None, |res: DebounceEventResult| {
Expand Down Expand Up @@ -50,6 +51,7 @@ use std::{
time::{Duration, Instant},
};

pub use notify;
use notify::{Error, ErrorKind, Event, RecommendedWatcher, Watcher};

/// The set of requirements for watcher debounce event handling functions.
Expand Down Expand Up @@ -259,6 +261,7 @@ pub fn new_debouncer_opt<F: DebounceEventHandler, T: Watcher>(
timeout: Duration,
tick_rate: Option<Duration>,
mut event_handler: F,
config: notify::Config
) -> Result<Debouncer<T>, Error> {
let data = DebounceData::default();

Expand Down Expand Up @@ -320,7 +323,7 @@ pub fn new_debouncer_opt<F: DebounceEventHandler, T: Watcher>(
// can't have multiple TX, so we need to pipe that through our debouncer
Err(e) => lock.add_error(e),
}
})?;
}, config)?;

let guard = Debouncer {
watcher,
Expand All @@ -339,7 +342,7 @@ pub fn new_debouncer_opt<F: DebounceEventHandler, T: Watcher>(
pub fn new_debouncer<F: DebounceEventHandler>(
timeout: Duration,
tick_rate: Option<Duration>,
event_handler: F,
event_handler: F
) -> Result<Debouncer<RecommendedWatcher>, Error> {
new_debouncer_opt::<F, RecommendedWatcher>(timeout, tick_rate, event_handler)
new_debouncer_opt::<F, RecommendedWatcher>(timeout, tick_rate, event_handler, notify::Config::default())
}
106 changes: 68 additions & 38 deletions notify/src/config.rs
Expand Up @@ -21,42 +21,72 @@ impl RecursiveMode {
}
}

/// Runtime configuration items for watchers.
///
/// See the [`Watcher::configure`](../trait.Watcher.html#tymethod.configure) method for usage.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Config {
/// Enable or disable emitting precise event classification.
///
/// Applicable to all watchers.
///
/// When enabled, events are emitted with a `kind` set to as much precision about what kind of
/// event they are as the backend is capable of providing. When disabled (default), events are
/// instead emitted as `EventKind::Any`. `EventKind::Other` meta-events are left alone.
PreciseEvents(bool),

/// Enable or disable emitting `Notice` events.
///
/// Applicable to debounced watchers only.
///
/// When enabled, the first modify or remove event for a path is emitted immediately with a
/// [`Flag::Notice`](../event/enum.Flag.html) attribute within a debouncing period, enabling
/// applications to respond more quickly.
NoticeEvents(bool),

/// Enable or disable emitting `Ongoing` events.
///
/// Applicable to debounced watchers only.
///
/// When enabled, partial write events that are received after a `Modify(Data)` Notice but
/// before the end of a debouncing period (and the emission of a `Modify(Data)` event) are
/// passed through as `Modify(Data)` events with an `Ongoing` flag. These events are still
/// debounced, but at a lower (configurable) interval than the debouncing interval.
///
/// To enable, provide `Some(Duration)`. To disable, provide `None`.
///
/// # Errors
///
/// - `InvalidConfigValue` if the interval provided is higher than the debounce interval.
OngoingEvents(Option<Duration>),
/// Watcher Backend configuration
///
/// This contains multiple settings that may relate to only one specific backend,
/// such as to correctly configure each backend regardless of what is selected during runtime.
///
/// ```rust
/// # use std::time::Duration;
/// # use notify::Config;
/// let config = Config::default()
/// .with_poll_interval(Duration::from_secs(2))
/// .with_compare_contents(true);
/// ```
///
/// Some options can be changed during runtime, others have to be set when creating the watcher backend.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Config {
/// See [BackendConfig::with_poll_interval]
poll_interval: Duration,

/// See [BackendConfig::with_compare_contents]
compare_contents: bool,
}

impl Config {
/// For [crate::PollWatcher]
///
/// Interval between each rescan attempt. This can be extremely expensive for large
/// file trees so it is recommended to measure and tune accordingly.
///
/// The default poll frequency is 30 seconds.
pub fn with_poll_interval(mut self, dur: Duration) -> Self {
self.poll_interval = dur;
self
}

/// Returns current setting
pub fn poll_interval(&self) -> Duration {
self.poll_interval
}

/// For [crate::PollWatcher]
///
/// Optional feature that will evaluate the contents of changed files to determine if
/// they have indeed changed using a fast hashing algorithm. This is especially important
/// for pseudo filesystems like those on Linux under /sys and /proc which are not obligated
/// to respect any other filesystem norms such as modification timestamps, file sizes, etc.
/// By enabling this feature, performance will be significantly impacted as all files will
/// need to be read and hashed at each `poll_interval`.
///
/// This can't be changed during runtime. Off by default.
pub fn with_compare_contents(mut self, compare_contents: bool) -> Self {
self.compare_contents = compare_contents;
self
}

/// Returns current setting
pub fn compare_contents(&self) -> bool {
self.compare_contents
}
}

impl Default for Config {
fn default() -> Self {
Self {
poll_interval: Duration::from_secs(30),
compare_contents: false
}
}
}
2 changes: 1 addition & 1 deletion notify/src/fsevent.rs
Expand Up @@ -543,7 +543,7 @@ unsafe fn callback_impl(

impl Watcher for FsEventWatcher {
/// Create a new watcher.
fn new<F: EventHandler>(event_handler: F) -> Result<Self> {
fn new<F: EventHandler>(event_handler: F, _config: Config) -> Result<Self> {
Self::from_event_handler(Arc::new(Mutex::new(event_handler)))
}

Expand Down
2 changes: 1 addition & 1 deletion notify/src/inotify.rs
Expand Up @@ -617,7 +617,7 @@ impl INotifyWatcher {

impl Watcher for INotifyWatcher {
/// Create a new watcher.
fn new<F: EventHandler>(event_handler: F) -> Result<Self> {
fn new<F: EventHandler>(event_handler: F, _config: Config) -> Result<Self> {
Self::from_event_handler(Box::new(event_handler))
}

Expand Down
4 changes: 2 additions & 2 deletions notify/src/kqueue.rs
Expand Up @@ -5,7 +5,7 @@
//! pieces of kernel code termed filters.

use super::event::*;
use super::{Error, EventHandler, RecursiveMode, Result, Watcher};
use super::{Error, EventHandler, RecursiveMode, Result, Watcher, Config};
use crate::{unbounded, Receiver, Sender};
use kqueue::{EventData, EventFilter, FilterFlag, Ident};
use std::collections::HashMap;
Expand Down Expand Up @@ -405,7 +405,7 @@ impl KqueueWatcher {

impl Watcher for KqueueWatcher {
/// Create a new watcher.
fn new<F: EventHandler>(event_handler: F) -> Result<Self> {
fn new<F: EventHandler>(event_handler: F, _config: Config) -> Result<Self> {
Self::from_event_handler(Box::new(event_handler))
}

Expand Down

0 comments on commit 29376ad

Please sign in to comment.