Probe files and directory checks are now executed in the Rust part to reduce the communication overhead between both parts

This commit is contained in:
Abdelilah El Aissaoui 2023-10-11 20:36:48 +02:00
parent 950c9398bf
commit bb47728d64
4 changed files with 40 additions and 19 deletions

View file

@ -1,6 +1,6 @@
namespace gitnuro { namespace gitnuro {
[Throws=WatcherInitError] [Throws=WatcherInitError]
void watch_directory(string path, WatchDirectoryNotifier checker); void watch_directory(string path, string git_dir_path, WatchDirectoryNotifier checker);
}; };
callback interface WatchDirectoryNotifier { callback interface WatchDirectoryNotifier {

View file

@ -12,6 +12,7 @@ const WATCH_TIMEOUT: u64 = 500;
pub fn watch_directory( pub fn watch_directory(
path: String, path: String,
git_dir_path: String,
notifier: Box<dyn WatchDirectoryNotifier>, notifier: Box<dyn WatchDirectoryNotifier>,
) -> Result<(), WatcherInitError> { ) -> Result<(), WatcherInitError> {
// Create a channel to receive the events. // Create a channel to receive the events.
@ -56,7 +57,7 @@ pub fn watch_directory(
println!("Sending single file event to Kotlin side"); println!("Sending single file event to Kotlin side");
notifier.detected_change(paths_cached.to_vec()); notifier.detected_change(paths_cached.to_vec());
} }
} else { } else if !paths_cached.is_empty() {
println!("Sending batched events to Kotlin side"); println!("Sending batched events to Kotlin side");
notifier.detected_change(paths_cached.to_vec()); notifier.detected_change(paths_cached.to_vec());
} }
@ -66,13 +67,18 @@ pub fn watch_directory(
match rx.recv_timeout(Duration::from_millis(WATCH_TIMEOUT)) { match rx.recv_timeout(Duration::from_millis(WATCH_TIMEOUT)) {
Ok(e) => { Ok(e) => {
if let Some(mut paths) = get_paths_from_event_result(&e) { if let Some(paths) = get_paths_from_event_result(&e, &git_dir_path) {
paths_cached.append(&mut paths); let mut paths_without_dirs: Vec<String> = paths
.into_iter()
.collect();
paths_cached.append(&mut paths_without_dirs);
last_update = SystemTime::now() last_update = SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.expect("We need a TARDIS to fix this") .expect("We need a TARDIS to fix this")
.as_millis(); .as_millis();
println!("Event: {e:?}"); println!("Event: {e:?}");
} }
} }
@ -91,14 +97,34 @@ pub fn watch_directory(
Ok(()) Ok(())
} }
pub fn get_paths_from_event_result(event_result: &Result<Event, Error>) -> Option<Vec<String>> { pub fn get_paths_from_event_result(event_result: &Result<Event, Error>, git_dir_path: &str) -> Option<Vec<String>> {
match event_result { match event_result {
Ok(event) => { Ok(event) => {
let events: Vec<String> = event let events: Vec<String> = event
.paths .paths
.clone() .clone()
.into_iter() .into_iter()
.filter_map(|path| path.into_os_string().into_string().ok()) .filter_map(|path| {
// Directories are not tracked by Git so we don't care about them (just about their content)
// We won't be able to check if it's a dir if it has been deleted but that's good enough
if path.is_dir() {
println!("Ignoring directory {path:#?}");
None
} else {
let path_str = path.into_os_string()
.into_string()
.ok()?;
// JGit may create .probe-UUID files for its internal stuff, we don't care about it
let probe_prefix = format!("{git_dir_path}.probe-");
if path_str.starts_with(probe_prefix.as_str()) {
println!("Ignoring .probe file");
None
} else {
Some(path_str)
}
}
})
.collect(); .collect();
if events.is_empty() { if events.is_empty() {

View file

@ -26,8 +26,10 @@ class FileChangesWatcher @Inject constructor(
suspend fun watchDirectoryPath( suspend fun watchDirectoryPath(
repository: Repository, repository: Repository,
pathStr: String
) = withContext(Dispatchers.IO) { ) = withContext(Dispatchers.IO) {
val workspacePath = repository.workTree.absolutePath
val gitRepoPath = repository.directory.absolutePath + systemSeparator
var ignoreRules = getIgnoreRulesUseCase(repository) var ignoreRules = getIgnoreRulesUseCase(repository)
val gitDirIgnoredFiles = listOf( val gitDirIgnoredFiles = listOf(
Constants.COMMIT_EDITMSG, Constants.COMMIT_EDITMSG,
@ -41,7 +43,7 @@ class FileChangesWatcher @Inject constructor(
} }
override fun detectedChange(paths: List<String>) = runBlocking { override fun detectedChange(paths: List<String>) = runBlocking {
val hasGitIgnoreChanged = paths.any { it == "$pathStr$systemSeparator.gitignore" } val hasGitIgnoreChanged = paths.any { it == "$workspacePath$systemSeparator.gitignore" }
if (hasGitIgnoreChanged) { if (hasGitIgnoreChanged) {
ignoreRules = getIgnoreRulesUseCase(repository) ignoreRules = getIgnoreRulesUseCase(repository)
@ -53,19 +55,13 @@ class FileChangesWatcher @Inject constructor(
} }
val isGitIgnoredFile = gitDirIgnoredFiles.any { ignoredFile -> val isGitIgnoredFile = gitDirIgnoredFiles.any { ignoredFile ->
"$pathStr$systemSeparator.git$systemSeparator$ignoredFile" == path "$workspacePath$systemSeparator.git$systemSeparator$ignoredFile" == path
} }
// JGit may create .probe-UUID files for its internal stuff, we should not care about it matchesAnyIgnoreRule || isGitIgnoredFile
val onlyProbeFiles = paths.all { it.contains("$systemSeparator.git$systemSeparator.probe-") }
// Ignore it if the change is the directory itself
val isGitDir = paths.count() == 1 && paths.first() == "$pathStr$systemSeparator.git$systemSeparator"
matchesAnyIgnoreRule || isGitIgnoredFile || onlyProbeFiles || isGitDir
} }
val hasGitDirChanged = paths.any { it.startsWith("$pathStr$systemSeparator.git$systemSeparator") } val hasGitDirChanged = paths.any { it.startsWith("$workspacePath$systemSeparator.git$systemSeparator") }
if (!areAllPathsIgnored) { if (!areAllPathsIgnored) {
_changesNotifier.emit(hasGitDirChanged) _changesNotifier.emit(hasGitDirChanged)
@ -73,6 +69,6 @@ class FileChangesWatcher @Inject constructor(
} }
} }
watchDirectory(pathStr, checker) watchDirectory(workspacePath, gitRepoPath, checker)
} }
} }

View file

@ -241,7 +241,6 @@ class TabViewModel @Inject constructor(
try { try {
fileChangesWatcher.watchDirectoryPath( fileChangesWatcher.watchDirectoryPath(
repository = git.repository, repository = git.repository,
pathStr = git.repository.workTree.absolutePath,
) )
} catch (ex: WatcherInitException) { } catch (ex: WatcherInitException) {
val message = when (ex) { val message = when (ex) {