Skip to content

Commit

Permalink
rework docs and example documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
0xpr03 committed Aug 10, 2022
1 parent cf37946 commit 0afcc27
Show file tree
Hide file tree
Showing 16 changed files with 140 additions and 176 deletions.
108 changes: 10 additions & 98 deletions README.md
Expand Up @@ -9,38 +9,31 @@

_Cross-platform filesystem notification library for Rust._

**Caution! This is unstable code!**

You likely want either [the latest 4.0 release] or [5.0.0-pre.15].

[the latest 4.0 release]: https://github.com/notify-rs/notify/tree/v4.0.16#notify
[5.0.0-pre.15]: https://github.com/notify-rs/notify/tree/5.0.0-pre.15#notify

(Looking for desktop notifications instead? Have a look at [notify-rust] or
[alert-after]!)

- **incomplete [Guides and in-depth docs][wiki]**
- [API Documentation][docs]
- [Debouncer Documentation][debouncer]
- [Crate page][crate]
- [Changelog][changelog]
- Earliest supported Rust version: **1.47.0**
- [Upgrading from v5](UPGRADING_V4_TO_V5.md)
- Earliest supported Rust version: **1.56**
- **incomplete [Guides and in-depth docs][wiki]**

As used by: [alacritty], [cargo watch], [cobalt], [docket], [mdBook], [pax],
[rdiff], [rust-analyzer], [timetrack], [watchexec], [xi-editor], [watchfiles],
and others.

## Installation
## Base Installation

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

## Usage

The examples below are aspirational only, to preview what the final release may
have looked like. They may not work. Refer to [the API documentation][docs] instead.
A basic example

```rust
use notify::{RecommendedWatcher, RecursiveMode, Result, watcher};
Expand Down Expand Up @@ -68,100 +61,18 @@ fn main() -> Result<()> {
}
```

### With a channel

To get a channel for advanced or flexible cases, use:

```rust
let rx = watcher.channel();

loop {
match rx.recv() {
// ...
}
}
```

To pass in a channel manually:

```rust
let (tx, rx) = crossbeam_channel::unbounded();
let mut watcher: RecommendedWatcher = Watcher::with_channel(tx, Duration::from_secs(2))?;

for event in rx.iter() {
// ...
}
```

### With precise events

By default, Notify issues generic events that carry little additional
information beyond what path was affected. On some platforms, more is
available; stay aware though that how exactly that manifests varies. To enable
precise events, use:

```rust
use notify::Config;
watcher.configure(Config::PreciseEvents(true));
```

### With notice events

Sometimes you want to respond to some events straight away, but not give up the
advantages of debouncing. Notice events appear once immediately when the occur
during a debouncing period, and then a second time as usual at the end of the
debouncing period:

```rust
use notify::Config;
watcher.configure(Config::NoticeEvents(true));
```

### With ongoing events

Sometimes frequent writes may be missed or not noticed often enough. Ongoing
write events can be enabled to emit more events even while debouncing:

```rust
use notify::Config;
watcher.configure(Config::OngoingEvents(Some(Duration::from_millis(500))));
```

### Without debouncing

To receive events as they are emitted, without debouncing at all:

```rust
let mut watcher = immediate_watcher()?;
```

With a channel:

```rust
let (tx, rx) = unbounded();
let mut watcher: RecommendedWatcher = Watcher::immediate_with_channel(tx)?;
```

### Serde

Events can be serialisable via [serde]. To enable the feature:

```toml
notify = { version = "5.0.0-pre.15", features = ["serde"] }
```

## Platforms

- Linux / Android: inotify
- macOS: FSEvents
- macOS: FSEvents or kqueue, see features
- Windows: ReadDirectoryChangesW
- FreeBSD / NetBSD / OpenBSD / DragonflyBSD: kqueue
- All platforms: polling

### FSEvents

Due to the inner security model of FSEvents (see [FileSystemEventSecurity]),
some event cannot be observed easily when trying to follow files that do not
some events cannot be observed easily when trying to follow files that do not
belong to you. In this case, reverting to the pollwatcher can fix the issue,
with a slight performance cost.

Expand All @@ -183,10 +94,11 @@ Inspired by Go's [fsnotify] and Node.js's [Chokidar], born out of need for
[cargo watch], and general frustration at the non-existence of C/Rust
cross-platform notify libraries.

Written by [F茅lix Saparelli] and awesome [contributors].
Originally created by [F茅lix Saparelli] and awesome [contributors].

[Chokidar]: https://github.com/paulmillr/chokidar
[FileSystemEventSecurity]: https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/FSEvents_ProgGuide/FileSystemEventSecurity/FileSystemEventSecurity.html
[debouncer]: https://github.com/notify-rs/notify/tree/main/notify-debouncer-mini
[F茅lix Saparelli]: https://passcod.name
[alacritty]: https://github.com/jwilm/alacritty
[alert-after]: https://github.com/frewsxcv/alert-after
Expand Down
13 changes: 13 additions & 0 deletions UPGRADING_V4_TO_V5.md
@@ -0,0 +1,13 @@
# Upgrading from notify v4 to v5

This guide documents changes between v4 and v5 for upgrading existing code.

Notify v5 only contains precise events. Debouncing is done by a separate crate [notify-debouncer-mini](https://github.com/notify-rs/notify/tree/main/notify-debouncer-mini).

If you've used the default debounced API, please see [here](https://github.com/notify-rs/notify/blob/main/examples/debounced.rs) for an example.

For precise events you can see [here](https://github.com/notify-rs/notify/blob/main/examples/monitor_raw.rs).

Notify v5 by default uses crossbeam-channel internally. You can disable this (required for tokio) as documented in the crate.

Plattform support in v5 now includes BSD and kqueue on macos in addition to fsevent.
2 changes: 1 addition & 1 deletion examples/Cargo.toml
Expand Up @@ -30,6 +30,6 @@ name = "watcher_kind"
path = "watcher_kind.rs"

# specifically in its own sub folder
# to prevent audit from complaining
# to prevent cargo audit from complaining
#[[example]]
#name = "hot_reload_tide"
29 changes: 15 additions & 14 deletions examples/async_monitor.rs
Expand Up @@ -5,6 +5,20 @@ use futures::{
use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher};
use std::path::Path;

/// Async, futures channel based event watching
fn main() {
let path = std::env::args()
.nth(1)
.expect("Argument 1 needs to be a path");
println!("watching {}", path);

futures::executor::block_on(async {
if let Err(e) = async_watch(path).await {
println!("error: {:?}", e)
}
});
}

fn async_watcher() -> notify::Result<(RecommendedWatcher, Receiver<notify::Result<Event>>)> {
let (mut tx, rx) = channel(1);

Expand Down Expand Up @@ -34,17 +48,4 @@ async fn async_watch<P: AsRef<Path>>(path: P) -> notify::Result<()> {
}

Ok(())
}

fn main() {
let path = std::env::args()
.nth(1)
.expect("Argument 1 needs to be a path");
println!("watching {}", path);

futures::executor::block_on(async {
if let Err(e) = async_watch(path).await {
println!("error: {:?}", e)
}
});
}
}
5 changes: 5 additions & 0 deletions examples/debounced.rs
Expand Up @@ -3,7 +3,9 @@ use std::{path::Path, time::Duration};
use notify::{RecursiveMode, Watcher};
use notify_debouncer_mini::new_debouncer;

/// Example for debouncer
fn main() {
// emit some events by changing a file
std::thread::spawn(|| {
let path = Path::new("test.txt");
let _ = std::fs::remove_file(&path);
Expand All @@ -13,15 +15,18 @@ fn main() {
}
});

// setup debouncer
let (tx, rx) = std::sync::mpsc::channel();

// No specific tickrate, max debounce time 2 seconds
let mut debouncer = new_debouncer(Duration::from_secs(2), None, tx).unwrap();

debouncer
.watcher()
.watch(Path::new("."), RecursiveMode::Recursive)
.unwrap();

// print all events, non returning
for events in rx {
for e in events {
println!("{:?}", e);
Expand Down
6 changes: 4 additions & 2 deletions examples/debounced_full_custom.rs
Expand Up @@ -5,6 +5,7 @@ use notify_debouncer_mini::new_debouncer;

/// Debouncer with custom backend and waiting for exit
fn main() {
// emit some events by changing a file
std::thread::spawn(|| {
let path = Path::new("test.txt");
let _ = std::fs::remove_file(&path);
Expand All @@ -14,15 +15,16 @@ 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();

debouncer
.watcher()
.watch(Path::new("."), RecursiveMode::Recursive)
.unwrap();

// print all events, non returning
for events in rx {
for e in events {
println!("{:?}", e);
Expand Down
2 changes: 2 additions & 0 deletions examples/hot_reload_tide/Cargo.toml
Expand Up @@ -13,4 +13,6 @@ serde_json = "1.0"
serde = "1.0.115"
notify = { version = "5.0.0-pre.15", features = ["serde"], path = "../../notify" }

# required to prevent mixing with workspace
# hack to prevent cargo audit from catching this
[workspace]
22 changes: 11 additions & 11 deletions examples/monitor_raw.rs
@@ -1,6 +1,16 @@
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::path::Path;

fn main() {
let path = std::env::args()
.nth(1)
.expect("Argument 1 needs to be a path");
println!("watching {}", path);
if let Err(e) = watch(path) {
println!("error: {:?}", e)
}
}

fn watch<P: AsRef<Path>>(path: P) -> notify::Result<()> {
let (tx, rx) = std::sync::mpsc::channel();

Expand All @@ -20,14 +30,4 @@ fn watch<P: AsRef<Path>>(path: P) -> notify::Result<()> {
}

Ok(())
}

fn main() {
let path = std::env::args()
.nth(1)
.expect("Argument 1 needs to be a path");
println!("watching {}", path);
if let Err(e) = watch(path) {
println!("error: {:?}", e)
}
}
}
19 changes: 15 additions & 4 deletions examples/watcher_kind.rs
@@ -1,16 +1,27 @@
use std::time::Duration;
use std::{path::Path, time::Duration};

use notify::{poll::PollWatcherConfig, *};
fn main() {
let (tx, _rx) = std::sync::mpsc::channel();
let _watcher: Box<dyn Watcher> = if RecommendedWatcher::kind() == WatcherKind::PollWatcher {
let (tx, rx) = std::sync::mpsc::channel();
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())
} else {
// use default config for everything else
Box::new(RecommendedWatcher::new(tx).unwrap())
};
// use _watcher here

// watch some stuff
watcher
.watch(Path::new("."), RecursiveMode::Recursive)
.unwrap();

// just print all events, this blocks forever
for e in rx {
println!("{:?}", e);
}
}
8 changes: 4 additions & 4 deletions notify-debouncer-mini/src/lib.rs
@@ -1,5 +1,5 @@
//! Debouncer for notify
//!
//!
//! # Installation
//!
//! ```toml
Expand Down Expand Up @@ -31,11 +31,11 @@
//! debouncer.watcher().watch(Path::new("."), RecursiveMode::Recursive).unwrap();
//! # }
//! ```
//!
//!
//! # Features
//!
//!
//! The following feature can be turned on or off.
//!
//!
//! - `crossbeam-channel` enabled by default, adds DebounceEventHandler support for crossbeam channels.
//! - `serde` enabled serde support for events.
#[cfg(feature = "serde")]
Expand Down
2 changes: 1 addition & 1 deletion notify/src/fsevent.rs
Expand Up @@ -15,7 +15,7 @@
#![allow(non_upper_case_globals, dead_code)]

use crate::event::*;
use crate::{Config, Error, EventHandler, RecursiveMode, Result, Watcher, unbounded, Sender};
use crate::{unbounded, Config, Error, EventHandler, RecursiveMode, Result, Sender, Watcher};
use fsevent_sys as fs;
use fsevent_sys::core_foundation as cf;
use std::collections::HashMap;
Expand Down
2 changes: 1 addition & 1 deletion notify/src/inotify.rs
Expand Up @@ -6,7 +6,7 @@

use super::event::*;
use super::{Config, Error, ErrorKind, EventHandler, RecursiveMode, Result, Watcher};
use crate::{unbounded, bounded, Sender, BoundSender, Receiver};
use crate::{bounded, unbounded, BoundSender, Receiver, Sender};
use inotify as inotify_sys;
use inotify_sys::{EventMask, Inotify, WatchDescriptor, WatchMask};
use std::collections::HashMap;
Expand Down

0 comments on commit 0afcc27

Please sign in to comment.