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:
parent
950c9398bf
commit
bb47728d64
4 changed files with 40 additions and 19 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue