From f535ba30d59bc60fc5d162a857b0f1a6475f4700 Mon Sep 17 00:00:00 2001 From: extrawurst Date: Mon, 9 Oct 2023 15:11:13 +0200 Subject: [PATCH] trigger `flush_session` if `GB_FLUSH` file triggers watcher git event * remove GB_FLUSH after processing it * add test for flushing and deleting flush file * add more unittests for cases: * no session, file -> no flush, file deleted * session, file -> flush, file deleted * session, no file -> no flush --- Cargo.lock | 23 +++ packages/tauri/Cargo.toml | 3 + .../src/watcher/dispatchers/file_change.rs | 1 + .../src/watcher/handlers/git_file_change.rs | 150 +++++++++++++++++- 4 files changed, 175 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d9da4380..97982c992 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1033,6 +1033,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "diffy" version = "0.3.0" @@ -1743,6 +1749,7 @@ dependencies = [ "notify", "num_cpus", "posthog-rs", + "pretty_assertions", "r2d2", "r2d2_sqlite", "rand 0.8.5", @@ -3609,6 +3616,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "primeorder" version = "0.13.2" @@ -6450,6 +6467,12 @@ dependencies = [ "libc", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "zeroize" version = "1.6.0" diff --git a/packages/tauri/Cargo.toml b/packages/tauri/Cargo.toml index 44c1f0ddd..f6326afc4 100644 --- a/packages/tauri/Cargo.toml +++ b/packages/tauri/Cargo.toml @@ -7,6 +7,9 @@ rust-version = "1.57" [build-dependencies] tauri-build = { version = "1.5", features = [] } +[dev-dependencies] +pretty_assertions = "1.4" + [dependencies] anyhow = "1.0.72" async-trait = "0.1.73" diff --git a/packages/tauri/src/watcher/dispatchers/file_change.rs b/packages/tauri/src/watcher/dispatchers/file_change.rs index 4b5e800bc..45cf148ec 100644 --- a/packages/tauri/src/watcher/dispatchers/file_change.rs +++ b/packages/tauri/src/watcher/dispatchers/file_change.rs @@ -139,6 +139,7 @@ fn is_interesting_file(git_repo: &git::Repository, file_path: &path::Path) -> bo check_file_path.ends_with("FETCH_HEAD") || check_file_path.eq(path::Path::new("logs/HEAD")) || check_file_path.eq(path::Path::new("HEAD")) + || check_file_path.eq(path::Path::new("GB_FLUSH")) || check_file_path.eq(path::Path::new("index")) } else { !git_repo.is_path_ignored(file_path).unwrap_or(false) diff --git a/packages/tauri/src/watcher/handlers/git_file_change.rs b/packages/tauri/src/watcher/handlers/git_file_change.rs index 0be7282b1..2c78e06e9 100644 --- a/packages/tauri/src/watcher/handlers/git_file_change.rs +++ b/packages/tauri/src/watcher/handlers/git_file_change.rs @@ -1,20 +1,32 @@ +use std::path; + use anyhow::{Context, Result}; use tauri::AppHandle; -use crate::{analytics, events as app_events, project_repository, projects}; +use crate::{analytics, events as app_events, gb_repository, project_repository, projects, users}; use super::events; #[derive(Clone)] pub struct Handler { + local_data_dir: path::PathBuf, projects: projects::Controller, + users: users::Controller, } impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { + let local_data_dir = value + .path_resolver() + .app_local_data_dir() + .context("failed to get local data dir")?; + let project_store = projects::Controller::try_from(value)?; + let user_store = users::Controller::try_from(value)?; Ok(Self { - projects: projects::Controller::try_from(value)?, + projects: project_store, + local_data_dir, + users: user_store, }) } } @@ -40,6 +52,35 @@ impl Handler { "logs/HEAD" => Ok(vec![events::Event::Emit(app_events::Event::git_activity( &project.id, ))]), + "GB_FLUSH" => { + let user = self.users.get_user()?; + let gb_repo = gb_repository::Repository::open( + &self.local_data_dir, + &project_repository, + user.as_ref(), + ) + .context("failed to open repository")?; + + let file_path = project.path.join(".git/GB_FLUSH"); + + if file_path.exists() { + if let Err(e) = std::fs::remove_file(&file_path) { + tracing::error!(project_id, path = %file_path.display(), "GB_FLUSH file delete error: {}", e); + } + + if let Some(current_session) = gb_repo + .get_current_session() + .context("failed to get current session")? + { + return Ok(vec![events::Event::Flush( + project.id.clone(), + current_session, + )]); + } + } + + Ok(vec![]) + } "HEAD" => { let head_ref = project_repository .get_head() @@ -64,3 +105,108 @@ impl Handler { } } } + +#[cfg(test)] +mod test { + use std::fs; + + use events::Event; + use pretty_assertions::assert_eq; + + use crate::{ + test_utils::{Case, Suite}, + watcher::handlers, + }; + + use super::*; + + #[test] + fn test_flush_session() -> Result<()> { + let suite = Suite::default(); + let Case { + project, + gb_repository, + .. + } = suite.new_case(); + + assert!(gb_repository.get_current_session()?.is_none()); + create_new_session_via_new_file(&project, &suite); + assert!(gb_repository.get_current_session()?.is_some()); + + let listener = Handler { + local_data_dir: suite.local_app_data, + projects: suite.projects, + users: suite.users, + }; + + let flush_file_path = project.path.join(".git/GB_FLUSH"); + fs::write(flush_file_path.as_path(), "")?; + + let result = listener.handle("GB_FLUSH", &project.id)?; + + assert_eq!(result.len(), 1); + assert!(matches!(result[0], Event::Flush(_, _))); + + assert!(!flush_file_path.exists(), "flush file deleted"); + + Ok(()) + } + + #[test] + fn test_do_not_flush_session_if_file_is_missing() -> Result<()> { + let suite = Suite::default(); + let Case { + project, + gb_repository, + .. + } = suite.new_case(); + + assert!(gb_repository.get_current_session()?.is_none()); + create_new_session_via_new_file(&project, &suite); + assert!(gb_repository.get_current_session()?.is_some()); + + let listener = Handler { + local_data_dir: suite.local_app_data, + projects: suite.projects, + users: suite.users, + }; + + let result = listener.handle("GB_FLUSH", &project.id)?; + + assert_eq!(result.len(), 0); + + Ok(()) + } + + fn create_new_session_via_new_file(project: &projects::Project, suite: &Suite) { + fs::write(project.path.join("test.txt"), "test").unwrap(); + let file_change_listener = + handlers::project_file_change::Handler::from(&suite.local_app_data); + file_change_listener + .handle("test.txt", &project.id) + .unwrap(); + } + + #[test] + fn test_flush_deletes_flush_file_without_session_to_flush() -> Result<()> { + let suite = Suite::default(); + let Case { project, .. } = suite.new_case(); + + let listener = Handler { + local_data_dir: suite.local_app_data, + projects: suite.projects, + users: suite.users, + }; + + let flush_file_path = project.path.join(".git/GB_FLUSH"); + fs::write(flush_file_path.as_path(), "")?; + + let result = listener.handle("GB_FLUSH", &project.id)?; + + assert_eq!(result.len(), 0); + + assert!(!flush_file_path.exists(), "flush file deleted"); + + Ok(()) + } +}