diff --git a/src/main/kotlin/app/git/FileChangesWatcher.kt b/src/main/kotlin/app/git/FileChangesWatcher.kt new file mode 100644 index 0000000..3017ce3 --- /dev/null +++ b/src/main/kotlin/app/git/FileChangesWatcher.kt @@ -0,0 +1,52 @@ +package app.git + +import kotlinx.coroutines.flow.flow +import java.io.IOException +import java.nio.file.* +import java.nio.file.StandardWatchEventKinds.* +import java.nio.file.attribute.BasicFileAttributes +import javax.inject.Inject + + +class FileChangesWatcher @Inject constructor() { + suspend fun watchDirectoryPath(pathStr: String, ignoredDirsPath: List) = flow { + val watchService = FileSystems.getDefault().newWatchService() + + val path = Paths.get(pathStr) + + path.register( + watchService, + ENTRY_CREATE, + ENTRY_DELETE, + ENTRY_MODIFY + ) + + // register directory and sub-directories + Files.walkFileTree(path, object : SimpleFileVisitor() { + @Throws(IOException::class) + override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult { + val isIgnoredDirectory = ignoredDirsPath.any { "$pathStr/$it" == dir.toString() } + + return if(!isIgnoredDirectory) { + dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY) + FileVisitResult.CONTINUE + } else { + FileVisitResult.SKIP_SUBTREE + } + } + }) + + var key: WatchKey + while (watchService.take().also { key = it } != null) { + this.emit(Unit) + for (event: WatchEvent<*> in key.pollEvents()) { + println( + "Event kind:" + event.kind() + + ". File affected: " + event.context() + "." + ) + } + key.reset() + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/app/git/GitManager.kt b/src/main/kotlin/app/git/GitManager.kt index 17e8d91..55bbb7f 100644 --- a/src/main/kotlin/app/git/GitManager.kt +++ b/src/main/kotlin/app/git/GitManager.kt @@ -15,7 +15,10 @@ import app.AppStateManager import app.app.Error import app.app.ErrorsManager import app.app.newErrorNow +import app.extensions.dirPath +import kotlinx.coroutines.flow.collect import org.eclipse.jgit.lib.ObjectId +import org.eclipse.jgit.treewalk.FileTreeIterator import java.io.File import javax.inject.Inject @@ -30,6 +33,7 @@ class GitManager @Inject constructor( private val tagsManager: TagsManager, val errorsManager: ErrorsManager, val appStateManager: AppStateManager, + private val fileChangesWatcher: FileChangesWatcher, ) { val repositoryName: String get() = safeGit.repository.directory.parentFile.name @@ -115,6 +119,9 @@ class GitManager @Inject constructor( onRepositoryChanged(repository.directory.parent) refreshRepositoryInfo() + launch { + watchRepositoryChanges() + } } catch (ex: Exception) { ex.printStackTrace() onRepositoryChanged(null) @@ -123,6 +130,21 @@ class GitManager @Inject constructor( } } + private suspend fun watchRepositoryChanges() { + val ignored = safeGit.status().call().ignoredNotInIndex.toList() + + fileChangesWatcher.watchDirectoryPath( + pathStr = safeGit.repository.directory.parent, + ignoredDirsPath = ignored, + ).collect { + safeProcessing { + println("Changes detected, loading status") + statusManager.loadHasUncommitedChanges(safeGit) + statusManager.loadStatus(safeGit) + } + } + } + fun loadLog() = managerScope.launch { coLoadLog() } diff --git a/src/main/kotlin/app/git/StatusManager.kt b/src/main/kotlin/app/git/StatusManager.kt index 4f596b9..d24f2b1 100644 --- a/src/main/kotlin/app/git/StatusManager.kt +++ b/src/main/kotlin/app/git/StatusManager.kt @@ -35,24 +35,30 @@ class StatusManager @Inject constructor() { } suspend fun loadStatus(git: Git) = withContext(Dispatchers.IO) { + val previousStatus = _stageStatus.value _stageStatus.value = StageStatus.Loading - loadHasUncommitedChanges(git) + try { + loadHasUncommitedChanges(git) - val staged = git - .diff() - .setCached(true) - .call() + val staged = git + .diff() + .setCached(true) + .call() - ensureActive() + ensureActive() - val unstaged = git - .diff() - .call() + val unstaged = git + .diff() + .call() - ensureActive() + ensureActive() + _stageStatus.value = StageStatus.Loaded(staged, unstaged) + } catch(ex: Exception) { + _stageStatus.value = previousStatus + throw ex + } - _stageStatus.value = StageStatus.Loaded(staged, unstaged) } suspend fun stage(git: Git, diffEntry: DiffEntry) = withContext(Dispatchers.IO) {