Fix Docker M1 Mac watcher failure and release v0.17.5

This commit is contained in:
Chip Senkbeil 2022-08-18 02:38:36 -05:00
parent 7849567c0f
commit 3b3e74462c
No known key found for this signature in database
GPG Key ID: 35EF1F8EC72A4131
7 changed files with 70 additions and 38 deletions

View File

@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.17.5] - 2022-08-18
### Fixed
- Handle `RecommendedWatcher` failing with an unsupported OS function on M1 Mac
architecture running a Linux container via Docker
([notify #423](https://github.com/notify-rs/notify/issues/423))
## [0.17.4] - 2022-08-18
### Fixed

8
Cargo.lock generated
View File

@ -709,7 +709,7 @@ dependencies = [
[[package]]
name = "distant"
version = "0.17.3"
version = "0.17.5"
dependencies = [
"anyhow",
"assert_cmd",
@ -750,7 +750,7 @@ dependencies = [
[[package]]
name = "distant-core"
version = "0.17.3"
version = "0.17.5"
dependencies = [
"assert_fs",
"async-trait",
@ -784,7 +784,7 @@ dependencies = [
[[package]]
name = "distant-net"
version = "0.17.3"
version = "0.17.5"
dependencies = [
"async-trait",
"bytes",
@ -809,7 +809,7 @@ dependencies = [
[[package]]
name = "distant-ssh2"
version = "0.17.3"
version = "0.17.5"
dependencies = [
"anyhow",
"assert_fs",

View File

@ -3,7 +3,7 @@ name = "distant"
description = "Operate on a remote computer through file and process manipulation"
categories = ["command-line-utilities"]
keywords = ["cli"]
version = "0.17.4"
version = "0.17.5"
authors = ["Chip Senkbeil <chip@senkbeil.org>"]
edition = "2021"
homepage = "https://github.com/chipsenkbeil/distant"
@ -32,7 +32,7 @@ clap_complete = "3.2.3"
config = { version = "0.13.2", default-features = false, features = ["toml"] }
derive_more = { version = "0.99.17", default-features = false, features = ["display", "from", "error", "is_variant"] }
dialoguer = { version = "0.10.2", default-features = false }
distant-core = { version = "=0.17.4", path = "distant-core", features = ["clap", "schemars"] }
distant-core = { version = "=0.17.5", path = "distant-core", features = ["clap", "schemars"] }
directories = "4.0.1"
flexi_logger = "0.23.0"
indoc = "1.0.7"
@ -54,7 +54,7 @@ winsplit = "0.1.0"
whoami = "1.2.1"
# Optional native SSH functionality
distant-ssh2 = { version = "=0.17.4", path = "distant-ssh2", default-features = false, features = ["serde"], optional = true }
distant-ssh2 = { version = "=0.17.5", path = "distant-ssh2", default-features = false, features = ["serde"], optional = true }
[target.'cfg(unix)'.dependencies]
fork = "0.1.19"

View File

@ -3,7 +3,7 @@ name = "distant-core"
description = "Core library for distant, enabling operation on a remote computer through file and process manipulation"
categories = ["network-programming"]
keywords = ["api", "async"]
version = "0.17.4"
version = "0.17.5"
authors = ["Chip Senkbeil <chip@senkbeil.org>"]
edition = "2021"
homepage = "https://github.com/chipsenkbeil/distant"
@ -19,7 +19,7 @@ async-trait = "0.1.57"
bitflags = "1.3.2"
bytes = "1.2.1"
derive_more = { version = "0.99.17", default-features = false, features = ["as_mut", "as_ref", "deref", "deref_mut", "display", "from", "error", "into", "into_iterator", "is_variant", "try_into"] }
distant-net = { version = "=0.17.4", path = "../distant-net" }
distant-net = { version = "=0.17.5", path = "../distant-net" }
futures = "0.3.21"
hex = "0.4.3"
log = "0.4.17"

View File

@ -1,8 +1,8 @@
use crate::{constants::SERVER_WATCHER_CAPACITY, data::ChangeKind, ConnectionId};
use log::*;
use notify::{
Config as WatcherConfig, Error as WatcherError, Event as WatcherEvent, RecommendedWatcher,
RecursiveMode, Watcher,
Config as WatcherConfig, Error as WatcherError, ErrorKind as WatcherErrorKind,
Event as WatcherEvent, PollWatcher, RecursiveMode, Watcher,
};
use std::{
collections::HashMap,
@ -41,10 +41,32 @@ impl WatcherState {
// with a large volume of watch requests
let (tx, rx) = mpsc::channel(SERVER_WATCHER_CAPACITY);
let mut watcher = {
let tx = tx.clone();
notify::recommended_watcher(move |res| {
match tx.try_send(match res {
macro_rules! configure_and_spawn {
($watcher:ident) => {{
// Attempt to configure watcher, but don't fail if these configurations fail
match $watcher.configure(WatcherConfig::PreciseEvents(true)) {
Ok(true) => debug!("Watcher configured for precise events"),
Ok(false) => debug!("Watcher not configured for precise events",),
Err(x) => error!("Watcher configuration for precise events failed: {}", x),
}
// Attempt to configure watcher, but don't fail if these configurations fail
match $watcher.configure(WatcherConfig::NoticeEvents(true)) {
Ok(true) => debug!("Watcher configured for notice events"),
Ok(false) => debug!("Watcher not configured for notice events",),
Err(x) => error!("Watcher configuration for notice events failed: {}", x),
}
Ok(Self {
channel: WatcherChannel { tx },
task: tokio::spawn(watcher_task($watcher, rx)),
})
}};
}
macro_rules! event_handler {
($tx:ident) => {
move |res| match $tx.try_send(match res {
Ok(x) => InnerWatcherMsg::Event { ev: x },
Err(x) => InnerWatcherMsg::Error { err: x },
}) {
@ -59,28 +81,31 @@ impl WatcherState {
warn!("Skipping watch event because watcher channel closed");
}
}
})
.map_err(|x| io::Error::new(io::ErrorKind::Other, x))?
};
}
let tx = tx.clone();
let result = {
let tx = tx.clone();
notify::recommended_watcher(event_handler!(tx))
};
// Attempt to configure watcher, but don't fail if these configurations fail
match watcher.configure(WatcherConfig::PreciseEvents(true)) {
Ok(true) => debug!("Watcher configured for precise events"),
Ok(false) => debug!("Watcher not configured for precise events",),
Err(x) => error!("Watcher configuration for precise events failed: {}", x),
match result {
Ok(mut watcher) => configure_and_spawn!(watcher),
Err(x) => match x.kind {
// notify-rs has a bug on Mac M1 with Docker and Linux, so we detect that error
// and fall back to the poll watcher if this occurs
//
// https://github.com/notify-rs/notify/issues/423
WatcherErrorKind::Io(x) if x.raw_os_error() == Some(38) => {
warn!("Recommended watcher is unsupported! Falling back to polling watcher!");
let mut watcher = PollWatcher::new(event_handler!(tx))
.map_err(|x| io::Error::new(io::ErrorKind::Other, x))?;
configure_and_spawn!(watcher)
}
_ => Err(io::Error::new(io::ErrorKind::Other, x)),
},
}
// Attempt to configure watcher, but don't fail if these configurations fail
match watcher.configure(WatcherConfig::NoticeEvents(true)) {
Ok(true) => debug!("Watcher configured for notice events"),
Ok(false) => debug!("Watcher not configured for notice events",),
Err(x) => error!("Watcher configuration for notice events failed: {}", x),
}
Ok(Self {
channel: WatcherChannel { tx },
task: tokio::spawn(watcher_task(watcher, rx)),
})
}
pub fn clone_channel(&self) -> WatcherChannel {
@ -163,7 +188,7 @@ enum InnerWatcherMsg {
},
}
async fn watcher_task(mut watcher: RecommendedWatcher, mut rx: mpsc::Receiver<InnerWatcherMsg>) {
async fn watcher_task(mut watcher: impl Watcher, mut rx: mpsc::Receiver<InnerWatcherMsg>) {
// TODO: Optimize this in some way to be more performant than
// checking every path whenever an event comes in
let mut registered_paths: Vec<RegisteredPath> = Vec::new();

View File

@ -3,7 +3,7 @@ name = "distant-net"
description = "Network library for distant, providing implementations to support client/server architecture"
categories = ["network-programming"]
keywords = ["api", "async"]
version = "0.17.4"
version = "0.17.5"
authors = ["Chip Senkbeil <chip@senkbeil.org>"]
edition = "2021"
homepage = "https://github.com/chipsenkbeil/distant"

View File

@ -2,7 +2,7 @@
name = "distant-ssh2"
description = "Library to enable native ssh-2 protocol for use with distant sessions"
categories = ["network-programming"]
version = "0.17.4"
version = "0.17.5"
authors = ["Chip Senkbeil <chip@senkbeil.org>"]
edition = "2021"
homepage = "https://github.com/chipsenkbeil/distant"
@ -20,7 +20,7 @@ async-compat = "0.2.1"
async-once-cell = "0.4.2"
async-trait = "0.1.57"
derive_more = { version = "0.99.17", default-features = false, features = ["display", "error"] }
distant-core = { version = "=0.17.4", path = "../distant-core" }
distant-core = { version = "=0.17.5", path = "../distant-core" }
futures = "0.3.21"
hex = "0.4.3"
log = "0.4.17"