diff --git a/core/src/location/manager/watcher/macos.rs b/core/src/location/manager/watcher/macos.rs index e058cd9de..31aad1d9f 100644 --- a/core/src/location/manager/watcher/macos.rs +++ b/core/src/location/manager/watcher/macos.rs @@ -3,24 +3,22 @@ use crate::{ location::{indexer::indexer_job::indexer_job_location, manager::LocationManagerError}, }; -use std::{future::Future, time::Duration}; - use async_trait::async_trait; use notify::{ event::{CreateKind, DataChange, ModifyKind, RenameMode}, Event, EventKind, }; -use tokio::{fs, select, spawn, sync::oneshot, time::sleep}; -use tracing::{trace, warn}; +use tokio::{fs, io}; +use tracing::trace; use super::{ - utils::{create_dir, create_file, remove_event, rename, update_file}, + utils::{create_dir, file_creation_or_update, remove_event, rename}, EventHandler, }; #[derive(Debug, Default)] pub(super) struct MacOsEventHandler { - maybe_rename_sender: Option>, + rename_stack: Option, } #[async_trait] @@ -41,60 +39,27 @@ impl EventHandler for MacOsEventHandler { trace!("Received MacOS event: {:#?}", event); match event.kind { - EventKind::Create(create_kind) => match create_kind { - CreateKind::File => { - let (maybe_rename_tx, maybe_rename_rx) = oneshot::channel(); - spawn(wait_to_create( - location, - event, - library_ctx.clone(), - create_file, - maybe_rename_rx, - )); - self.maybe_rename_sender = Some(maybe_rename_tx); - } - CreateKind::Folder => { - let (maybe_rename_tx, maybe_rename_rx) = oneshot::channel(); - spawn(wait_to_create( - location, - event, - library_ctx.clone(), - create_dir, - maybe_rename_rx, - )); - self.maybe_rename_sender = Some(maybe_rename_tx); - } - other => { - trace!("Ignoring other create event: {:#?}", other); - } - }, - EventKind::Modify(ref modify_kind) => match modify_kind { - ModifyKind::Data(DataChange::Any) => { - if fs::metadata(&event.paths[0]).await?.is_file() { - update_file(location, event, library_ctx).await?; - } else { - trace!("Unexpected MacOS modify event on a directory"); + EventKind::Create(CreateKind::Folder) => { + create_dir(location, event, library_ctx.clone()).await?; + } + EventKind::Modify(ModifyKind::Data(DataChange::Content)) => { + // If a file had its content modified, then it was updated or created + file_creation_or_update(location, event, library_ctx).await?; + } + EventKind::Modify(ModifyKind::Name(RenameMode::Any)) => { + match self.rename_stack.take() { + None => { + self.rename_stack = Some(event); } + Some(from_event) => { + rename(&event.paths[0], &from_event.paths[0], location, library_ctx) + .await?; + } + } + } - // We ignore EventKind::Modify(ModifyKind::Data(DataChange::Any)) for directories - // as they're also used for removing files and directories, being emitted - // on the parent directory in this case - } - ModifyKind::Name(RenameMode::Any) => { - if let Some(rename_sender) = self.maybe_rename_sender.take() { - if !rename_sender.is_closed() && rename_sender.send(event).is_err() { - warn!("Failed to send rename event"); - } - } - } - other => { - trace!("Ignoring other modify event: {:#?}", other); - } - }, EventKind::Remove(remove_kind) => { remove_event(location, event, remove_kind, library_ctx).await?; - // An EventKind::Modify(ModifyKind::Data(DataChange::Any)) - On parent directory - // is also emitted, but we can ignore it. } other_event_kind => { trace!("Other MacOS event that we don't handle for now: {other_event_kind:#?}"); @@ -104,27 +69,3 @@ impl EventHandler for MacOsEventHandler { Ok(()) } } - -// FIX-ME: Had some troubles with borrowck, to receive a -// impl FnOnce(indexer_job_location::Data, Event, &LibraryContext) -> Fut -// as a parameter, had to move LibraryContext into the functions -async fn wait_to_create( - location: indexer_job_location::Data, - event: Event, - library_ctx: LibraryContext, - create_fn: impl FnOnce(indexer_job_location::Data, Event, LibraryContext) -> Fut, - maybe_rename_rx: oneshot::Receiver, -) -> Result<(), LocationManagerError> -where - Fut: for<'r> Future>, -{ - select! { - () = sleep(Duration::from_secs(1)) => { - create_fn(location, event, library_ctx).await - }, - Ok(rename_event) = maybe_rename_rx => { - trace!("Renaming file or directory instead of creating a new one"); - rename(&event.paths[0], &rename_event.paths[0], location, &library_ctx).await - } - } -} diff --git a/core/src/location/manager/watcher/mod.rs b/core/src/location/manager/watcher/mod.rs index 3e1a2a48e..a42792a9a 100644 --- a/core/src/location/manager/watcher/mod.rs +++ b/core/src/location/manager/watcher/mod.rs @@ -252,78 +252,77 @@ impl Drop for LocationWatcher { } /*************************************************************************************************** - * Some tests to validate our assumptions of events through different file systems * - *************************************************************************************************** - * Events dispatched on Linux: * - * Create File: * - * 1) EventKind::Create(CreateKind::File) * - * 2) EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any)) * - * or EventKind::Modify(ModifyKind::Data(DataChange::Any)) * - * 3) EventKind::Access(AccessKind::Close(AccessMode::Write))) * - * Create Directory: * - * 1) EventKind::Create(CreateKind::Folder) * - * Update File: * - * 1) EventKind::Modify(ModifyKind::Data(DataChange::Any)) * - * 2) EventKind::Access(AccessKind::Close(AccessMode::Write))) * - * Update File (rename): * - * 1) EventKind::Modify(ModifyKind::Name(RenameMode::From)) * - * 2) EventKind::Modify(ModifyKind::Name(RenameMode::To)) * - * 3) EventKind::Modify(ModifyKind::Name(RenameMode::Both)) * - * Update Directory (rename): * - * 1) EventKind::Modify(ModifyKind::Name(RenameMode::From)) * - * 2) EventKind::Modify(ModifyKind::Name(RenameMode::To)) * - * 3) EventKind::Modify(ModifyKind::Name(RenameMode::Both)) * - * Delete File: * - * 1) EventKind::Remove(RemoveKind::File) * - * Delete Directory: * - * 1) EventKind::Remove(RemoveKind::Folder) * - * * - * Events dispatched on MacOS: * - * Create File: * - * 1) EventKind::Create(CreateKind::File) * - * Create Directory: * - * 1) EventKind::Create(CreateKind::Folder) * - * Update File: * - * 1) EventKind::Modify(ModifyKind::Data(DataChange::Any)) * - * Update File (rename): * - * 1) EventKind::Create(CreateKind::File) * - * 2) EventKind::Modify(ModifyKind::Name(RenameMode::Any)) * - * Update Directory (rename): * - * 1) EventKind::Create(CreateKind::Folder) * - * 2) EventKind::Modify(ModifyKind::Name(RenameMode::Any)) * - * Delete File: * - * 1) EventKind::Remove(RemoveKind::Any) * - * 2) EventKind::Modify(ModifyKind::Data(DataChange::Any)) - On parent directory * - * Delete Directory: * - * 1) EventKind::Remove(RemoveKind::Any) * - * 2) EventKind::Modify(ModifyKind::Data(DataChange::Any)) - On parent directory * - * * - * Events dispatched on Windows: * - * Create File: * - * 1) EventKind::Create(CreateKind::Any) * - * 2) EventKind::Modify(ModifyKind::Any) * - * Create Directory: * - * 1) EventKind::Create(CreateKind::Any) * - * Update File: * - * 1) EventKind::Modify(ModifyKind::Any) * - * Update File (rename): * - * 1) EventKind::Modify(ModifyKind::Name(RenameMode::From)) * - * 2) EventKind::Modify(ModifyKind::Name(RenameMode::To)) * - * Update Directory (rename): * - * 1) EventKind::Modify(ModifyKind::Name(RenameMode::From)) * - * 2) EventKind::Modify(ModifyKind::Name(RenameMode::To)) * - * Delete File: * - * 1) EventKind::Remove(RemoveKind::Any) * - * Delete Directory: * - * 1) EventKind::Remove(RemoveKind::Any) * - * * - * Events dispatched on Android: * - * TODO * - * * - * Events dispatched on iOS: * - * TODO * - * * - **************************************************************************************************/ +* Some tests to validate our assumptions of events through different file systems * +*************************************************************************************************** +* Events dispatched on Linux: * +* Create File: * +* 1) EventKind::Create(CreateKind::File) * +* 2) EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any)) * +* or EventKind::Modify(ModifyKind::Data(DataChange::Any)) * +* 3) EventKind::Access(AccessKind::Close(AccessMode::Write))) * +* Create Directory: * +* 1) EventKind::Create(CreateKind::Folder) * +* Update File: * +* 1) EventKind::Modify(ModifyKind::Data(DataChange::Any)) * +* 2) EventKind::Access(AccessKind::Close(AccessMode::Write))) * +* Update File (rename): * +* 1) EventKind::Modify(ModifyKind::Name(RenameMode::From)) * +* 2) EventKind::Modify(ModifyKind::Name(RenameMode::To)) * +* 3) EventKind::Modify(ModifyKind::Name(RenameMode::Both)) * +* Update Directory (rename): * +* 1) EventKind::Modify(ModifyKind::Name(RenameMode::From)) * +* 2) EventKind::Modify(ModifyKind::Name(RenameMode::To)) * +* 3) EventKind::Modify(ModifyKind::Name(RenameMode::Both)) * +* Delete File: * +* 1) EventKind::Remove(RemoveKind::File) * +* Delete Directory: * +* 1) EventKind::Remove(RemoveKind::Folder) * +* * +* Events dispatched on MacOS: * +* Create File: * +* 1) EventKind::Create(CreateKind::File) * +* 2) EventKind::Modify(ModifyKind::Data(DataChange::Content)) * +* Create Directory: * +* 1) EventKind::Create(CreateKind::Folder) * +* Update File: * +* 1) EventKind::Modify(ModifyKind::Data(DataChange::Content)) * +* Update File (rename): * +* 1) EventKind::Modify(ModifyKind::Name(RenameMode::Any)) -- From * +* 2) EventKind::Modify(ModifyKind::Name(RenameMode::Any)) -- To * +* Update Directory (rename): * +* 1) EventKind::Modify(ModifyKind::Name(RenameMode::Any)) -- From * +* 2) EventKind::Modify(ModifyKind::Name(RenameMode::Any)) -- To * +* Delete File: * +* 1) EventKind::Remove(RemoveKind::File) * +* Delete Directory: * +* 1) EventKind::Remove(RemoveKind::Folder) * +* * +* Events dispatched on Windows: * +* Create File: * +* 1) EventKind::Create(CreateKind::Any) * +* 2) EventKind::Modify(ModifyKind::Any) * +* Create Directory: * +* 1) EventKind::Create(CreateKind::Any) * +* Update File: * +* 1) EventKind::Modify(ModifyKind::Any) * +* Update File (rename): * +* 1) EventKind::Modify(ModifyKind::Name(RenameMode::From)) * +* 2) EventKind::Modify(ModifyKind::Name(RenameMode::To)) * +* Update Directory (rename): * +* 1) EventKind::Modify(ModifyKind::Name(RenameMode::From)) * +* 2) EventKind::Modify(ModifyKind::Name(RenameMode::To)) * +* Delete File: * +* 1) EventKind::Remove(RemoveKind::Any) * +* Delete Directory: * +* 1) EventKind::Remove(RemoveKind::Any) * +* * +* Events dispatched on Android: * +* TODO * +* * +* Events dispatched on iOS: * +* TODO * +* * +**************************************************************************************************/ #[cfg(test)] #[allow(unused)] mod tests { @@ -376,8 +375,8 @@ mod tests { Ok(maybe_event) => { let event = maybe_event.expect("Failed to receive event"); debug!("Received event: {event:#?}"); - // In case of file creation, we expect to see an close event on write mode - if event.paths[0] == path && event.kind == expected_event { + // Using `ends_with` here due to a weird edge case on CI tests at MacOS + if event.paths[0].ends_with(path) && event.kind == expected_event { debug!("Received expected event: {expected_event:#?}"); break; }