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
This commit is contained in:
extrawurst 2023-10-09 15:11:13 +02:00
parent ac257c11ca
commit f535ba30d5
4 changed files with 175 additions and 2 deletions

23
Cargo.lock generated
View File

@ -1033,6 +1033,12 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]] [[package]]
name = "diffy" name = "diffy"
version = "0.3.0" version = "0.3.0"
@ -1743,6 +1749,7 @@ dependencies = [
"notify", "notify",
"num_cpus", "num_cpus",
"posthog-rs", "posthog-rs",
"pretty_assertions",
"r2d2", "r2d2",
"r2d2_sqlite", "r2d2_sqlite",
"rand 0.8.5", "rand 0.8.5",
@ -3609,6 +3616,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 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]] [[package]]
name = "primeorder" name = "primeorder"
version = "0.13.2" version = "0.13.2"
@ -6450,6 +6467,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]] [[package]]
name = "zeroize" name = "zeroize"
version = "1.6.0" version = "1.6.0"

View File

@ -7,6 +7,9 @@ rust-version = "1.57"
[build-dependencies] [build-dependencies]
tauri-build = { version = "1.5", features = [] } tauri-build = { version = "1.5", features = [] }
[dev-dependencies]
pretty_assertions = "1.4"
[dependencies] [dependencies]
anyhow = "1.0.72" anyhow = "1.0.72"
async-trait = "0.1.73" async-trait = "0.1.73"

View File

@ -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.ends_with("FETCH_HEAD")
|| check_file_path.eq(path::Path::new("logs/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("HEAD"))
|| check_file_path.eq(path::Path::new("GB_FLUSH"))
|| check_file_path.eq(path::Path::new("index")) || check_file_path.eq(path::Path::new("index"))
} else { } else {
!git_repo.is_path_ignored(file_path).unwrap_or(false) !git_repo.is_path_ignored(file_path).unwrap_or(false)

View File

@ -1,20 +1,32 @@
use std::path;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use tauri::AppHandle; 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; use super::events;
#[derive(Clone)] #[derive(Clone)]
pub struct Handler { pub struct Handler {
local_data_dir: path::PathBuf,
projects: projects::Controller, projects: projects::Controller,
users: users::Controller,
} }
impl TryFrom<&AppHandle> for Handler { impl TryFrom<&AppHandle> for Handler {
type Error = anyhow::Error; type Error = anyhow::Error;
fn try_from(value: &AppHandle) -> Result<Self, Self::Error> { fn try_from(value: &AppHandle) -> Result<Self, Self::Error> {
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 { 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( "logs/HEAD" => Ok(vec![events::Event::Emit(app_events::Event::git_activity(
&project.id, &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" => { "HEAD" => {
let head_ref = project_repository let head_ref = project_repository
.get_head() .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(())
}
}