Translate notify::Event to fsevent::Event on linux (#7545)

This isn't exactly a great solution, but it's a step in the right
direction, and it's simple allowing us to quickly unblock linux. Without
this (or an equivalent) PR linux builds are broken.

I spent a bunch of time investigating using notify on macos, and have a
branch with that working and FakeFs updated to use notify events.
unfortunately I think this would come with some drawbacks. Primarily
that files that don't yet exist yet aren't handled as well as with using
events directly leading to some less than ideal tradeoffs.

This PR is very much a placeholder for a better cross platform solution.
Most problematically, it only fills in the portion of fsevent::Event
that is currently used, despite there being a lot more information in
the ones collected from macos. At the very least a followup PR should
hide those implementation details behind a cross platform Event type so
that if people try and access data that hasn't been translated, they
find out about it.

Release Notes:

- N/A
This commit is contained in:
gmorenz 2024-02-08 11:35:37 -05:00 committed by GitHub
parent 006e7a77d5
commit 17c203fef9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 416 additions and 406 deletions

View file

@ -1,15 +1,15 @@
pub mod repository;
use anyhow::{anyhow, Result};
#[cfg(target_os = "macos")]
pub use fsevent::Event;
#[cfg(target_os = "macos")]
use fsevent::EventStream;
#[cfg(not(target_os = "macos"))]
pub use notify::Event;
use fsevent::StreamFlags;
#[cfg(not(target_os = "macos"))]
use notify::{Config, Watcher};
use notify::{Config, EventKind, Watcher};
use futures::{future::BoxFuture, Stream, StreamExt};
use git2::Repository as LibGitRepository;
@ -292,15 +292,30 @@ impl Fs for RealFs {
return Box::pin(rx);
}
let mut watcher = notify::recommended_watcher(move |res| match res {
Ok(event) => {
let _ = tx.try_send(vec![event]);
}
Err(err) => {
log::error!("watch error: {}", err);
}
})
.unwrap();
let mut watcher =
notify::recommended_watcher(move |res: Result<notify::Event, _>| match res {
Ok(event) => {
let flags = match event.kind {
// ITEM_REMOVED is currently the only flag we care about
EventKind::Remove(_) => StreamFlags::ITEM_REMOVED,
_ => StreamFlags::NONE,
};
let events = event
.paths
.into_iter()
.map(|path| Event {
event_id: 0,
flags,
path,
})
.collect::<Vec<_>>();
let _ = tx.try_send(events);
}
Err(err) => {
log::error!("watch error: {}", err);
}
})
.unwrap();
watcher
.configure(Config::default().with_poll_interval(latency))
@ -330,20 +345,10 @@ impl Fs for RealFs {
}
}
#[cfg(target_os = "macos")]
pub fn fs_events_paths(events: Vec<Event>) -> Vec<PathBuf> {
events.into_iter().map(|event| event.path).collect()
}
#[cfg(not(target_os = "macos"))]
pub fn fs_events_paths(events: Vec<Event>) -> Vec<PathBuf> {
events
.into_iter()
.map(|event| event.paths.into_iter())
.flatten()
.collect()
}
#[cfg(any(test, feature = "test-support"))]
pub struct FakeFs {
// Use an unfair lock to ensure tests are deterministic.