Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix readme and examples #395

Merged
merged 1 commit into from Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
110 changes: 12 additions & 98 deletions README.md
Expand Up @@ -9,38 +9,32 @@

_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]
- [Examples][examples]
- [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 +62,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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do still talk about that in lib.rs. It's a planned feature but for now completely wrong. As we always emit 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 +95,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 Expand Up @@ -215,3 +128,4 @@ Written by [Félix Saparelli] and awesome [contributors].
[wiki]: https://github.com/notify-rs/notify/wiki
[xi-editor]: https://xi-editor.io/
[watchfiles]: https://watchfiles.helpmanual.io/
[examples]: examples/
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)
}
}
}
21 changes: 13 additions & 8 deletions examples/poll_sysfs.rs
@@ -1,10 +1,13 @@
use notify::poll::PollWatcherConfig;
use notify::{PollWatcher, RecursiveMode, Watcher};
use std::path::Path;
use std::time::Duration;

/// Example for watching kernel internal filesystems like `/sys` and `/proc`
/// These can't be watched by the default backend or unconfigured pollwatcher
/// 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 std::path::Path;
use std::time::Duration;

let mut paths: Vec<_> = std::env::args()
.skip(1)
.map(|arg| Path::new(&arg).to_path_buf())
Expand All @@ -23,17 +26,19 @@ fn not_windows_main() -> notify::Result<()> {
}

println!("watching {:?}...", paths);

// configure pollwatcher backend
let config = PollWatcherConfig {
compare_contents: true,
compare_contents: true, // crucial part for pseudo filesystems
poll_interval: Duration::from_secs(2),
};
let (tx, rx) = std::sync::mpsc::channel();
// create pollwatcher backend
let mut watcher = PollWatcher::with_config(tx, config)?;
for path in paths {
// watch all paths
watcher.watch(&path, RecursiveMode::Recursive)?;
}

// print all events, never returns
for res in rx {
match res {
Ok(event) => println!("changed: {:?}", event),
Expand Down