From 3128341b934bc87f892e4951ec8fa4e4f8d9c3cc Mon Sep 17 00:00:00 2001 From: Abdelilah El Aissaoui Date: Tue, 22 Oct 2024 20:29:30 +0200 Subject: [PATCH] Fixed crash when watch init has failed --- .../exceptions/WatcherInitException.kt | 7 +- .../gitnuro/git/FileChangesWatcher.kt | 16 ++-- .../viewmodels/RepositoryOpenViewModel.kt | 86 +++++++++---------- .../gitnuro/viewmodels/TabViewModel.kt | 30 +++---- 4 files changed, 66 insertions(+), 73 deletions(-) diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/exceptions/WatcherInitException.kt b/src/main/kotlin/com/jetpackduba/gitnuro/exceptions/WatcherInitException.kt index 744758a..92fd030 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/exceptions/WatcherInitException.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/exceptions/WatcherInitException.kt @@ -1,11 +1,6 @@ package com.jetpackduba.gitnuro.exceptions -class WatcherInitException( - code: Int, - message: String = codeToMessage(code), -) : GitnuroException(message) - -private fun codeToMessage(code: Int): String { +fun codeToMessage(code: Int): String { return when (code) { 1 /*is WatcherInitException.Generic*/, 2 /*is WatcherInitException.Io*/ -> "Could not watch directory. Check if it exists and you have read permissions." 3 /*is WatcherInitException.PathNotFound*/ -> "Path not found, check if your repository still exists" diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/git/FileChangesWatcher.kt b/src/main/kotlin/com/jetpackduba/gitnuro/git/FileChangesWatcher.kt index 4225f0a..1b8b326 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/git/FileChangesWatcher.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/git/FileChangesWatcher.kt @@ -3,7 +3,6 @@ package com.jetpackduba.gitnuro.git import FileWatcher import WatchDirectoryNotifier import com.jetpackduba.gitnuro.di.TabScope -import com.jetpackduba.gitnuro.exceptions.WatcherInitException import com.jetpackduba.gitnuro.git.workspace.GetIgnoreRulesUseCase import com.jetpackduba.gitnuro.system.systemSeparator import kotlinx.coroutines.CoroutineScope @@ -25,8 +24,8 @@ class FileChangesWatcher @Inject constructor( private val getIgnoreRulesUseCase: GetIgnoreRulesUseCase, private val tabScope: CoroutineScope, ) : AutoCloseable { - private val _changesNotifier = MutableSharedFlow() - val changesNotifier: SharedFlow = _changesNotifier + private val _changesNotifier = MutableSharedFlow() + val changesNotifier: SharedFlow = _changesNotifier private val fileWatcher = FileWatcher.new() private var shouldKeepLooping = true @@ -71,14 +70,16 @@ class FileChangesWatcher @Inject constructor( if (!areAllPathsIgnored) { println("Emitting changes $hasGitIgnoreChanged") - _changesNotifier.emit(hasGitDirChanged) + _changesNotifier.emit(WatcherEvent.RepositoryChanged(hasGitDirChanged)) } } } override fun onError(code: Int) { - throw WatcherInitException(code) + tabScope.launch { + _changesNotifier.emit(WatcherEvent.WatchInitError(code)) + } } } @@ -90,4 +91,9 @@ class FileChangesWatcher @Inject constructor( fileWatcher.close() } +} + +sealed interface WatcherEvent { + data class RepositoryChanged(val hasGitDirChanged: Boolean) : WatcherEvent + data class WatchInitError(val code: Int) : WatcherEvent } \ No newline at end of file diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/RepositoryOpenViewModel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/RepositoryOpenViewModel.kt index 1d1023e..7d2f706 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/RepositoryOpenViewModel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/RepositoryOpenViewModel.kt @@ -2,7 +2,7 @@ package com.jetpackduba.gitnuro.viewmodels import com.jetpackduba.gitnuro.SharedRepositoryStateManager import com.jetpackduba.gitnuro.TaskType -import com.jetpackduba.gitnuro.exceptions.WatcherInitException +import com.jetpackduba.gitnuro.exceptions.codeToMessage import com.jetpackduba.gitnuro.git.* import com.jetpackduba.gitnuro.git.branches.CreateBranchUseCase import com.jetpackduba.gitnuro.git.rebase.RebaseInteractiveState @@ -110,6 +110,8 @@ class RepositoryOpenViewModel @Inject constructor( var authorViewModel: AuthorViewModel? = null private set + private var hasGitDirChanged = false + init { tabScope.run { launch { @@ -119,7 +121,7 @@ class RepositoryOpenViewModel @Inject constructor( } launch { - watchRepositoryChanges(tabState.git) + watchRepositoryChanges() } } } @@ -158,55 +160,53 @@ class RepositoryOpenViewModel @Inject constructor( * the app by constantly running "git status" or even full refreshes. * */ - private suspend fun watchRepositoryChanges(git: Git) = tabScope.launch(Dispatchers.IO) { - var hasGitDirChanged = false - + private suspend fun watchRepositoryChanges() = tabScope.launch(Dispatchers.IO) { launch { - fileChangesWatcher.changesNotifier.collect { latestUpdateChangedGitDir -> - val isOperationRunning = tabState.operationRunning + fileChangesWatcher.changesNotifier.collect { watcherEvent -> + when (watcherEvent) { + is WatcherEvent.RepositoryChanged -> repositoryChanged(watcherEvent.hasGitDirChanged) + is WatcherEvent.WatchInitError -> { + val message = codeToMessage(watcherEvent.code) + errorsManager.addError( + newErrorNow( + exception = Exception(message), + taskType = TaskType.CHANGES_DETECTION, + ), + ) - if (!isOperationRunning) { // Only update if there isn't any process running - printDebug(TAG, "Detected changes in the repository's directory") - - val currentTimeMillis = System.currentTimeMillis() - - if ( - latestUpdateChangedGitDir && - currentTimeMillis - tabState.lastOperation < MIN_TIME_AFTER_GIT_OPERATION - ) { - printDebug(TAG, "Git operation was executed recently, ignoring file system change") - return@collect } - - if (latestUpdateChangedGitDir) { - hasGitDirChanged = true - } - - if (isActive) { - updateApp(hasGitDirChanged) - } - - hasGitDirChanged = false - } else { - printDebug(TAG, "Ignored file events during operation") } } } + } - try { - fileChangesWatcher.watchDirectoryPath( - repository = git.repository, - ) - } catch (ex: WatcherInitException) { - val message = ex.message - if (message != null) { - errorsManager.addError( - newErrorNow( - exception = ex, - taskType = TaskType.CHANGES_DETECTION, - ), - ) + private suspend fun CoroutineScope.repositoryChanged(hasGitDirChanged: Boolean) { + val isOperationRunning = tabState.operationRunning + + if (!isOperationRunning) { // Only update if there isn't any process running + printDebug(TAG, "Detected changes in the repository's directory") + + val currentTimeMillis = System.currentTimeMillis() + + if ( + hasGitDirChanged && + currentTimeMillis - tabState.lastOperation < MIN_TIME_AFTER_GIT_OPERATION + ) { + printDebug(TAG, "Git operation was executed recently, ignoring file system change") + return } + + if (hasGitDirChanged) { + this@RepositoryOpenViewModel.hasGitDirChanged = true + } + + if (isActive) { + updateApp(hasGitDirChanged) + } + + this@RepositoryOpenViewModel.hasGitDirChanged = false + } else { + printDebug(TAG, "Ignored file events during operation") } } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt index ba592ec..afeefa3 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt @@ -1,45 +1,37 @@ package com.jetpackduba.gitnuro.viewmodels -import com.jetpackduba.gitnuro.SharedRepositoryStateManager import com.jetpackduba.gitnuro.TaskType import com.jetpackduba.gitnuro.credentials.CredentialsAccepted import com.jetpackduba.gitnuro.credentials.CredentialsState import com.jetpackduba.gitnuro.credentials.CredentialsStateManager -import com.jetpackduba.gitnuro.exceptions.WatcherInitException -import com.jetpackduba.gitnuro.git.* -import com.jetpackduba.gitnuro.git.branches.CreateBranchUseCase -import com.jetpackduba.gitnuro.git.rebase.RebaseInteractiveState +import com.jetpackduba.gitnuro.git.FileChangesWatcher +import com.jetpackduba.gitnuro.git.ProcessingState +import com.jetpackduba.gitnuro.git.RefreshType +import com.jetpackduba.gitnuro.git.TabState import com.jetpackduba.gitnuro.git.repository.InitLocalRepositoryUseCase import com.jetpackduba.gitnuro.git.repository.OpenRepositoryUseCase import com.jetpackduba.gitnuro.git.repository.OpenSubmoduleRepositoryUseCase -import com.jetpackduba.gitnuro.git.stash.StashChangesUseCase -import com.jetpackduba.gitnuro.git.workspace.StageUntrackedFileUseCase -import com.jetpackduba.gitnuro.logging.printDebug import com.jetpackduba.gitnuro.logging.printLog import com.jetpackduba.gitnuro.managers.AppStateManager import com.jetpackduba.gitnuro.managers.ErrorsManager import com.jetpackduba.gitnuro.managers.newErrorNow -import com.jetpackduba.gitnuro.models.AuthorInfoSimple -import com.jetpackduba.gitnuro.models.errorNotification -import com.jetpackduba.gitnuro.models.positiveNotification import com.jetpackduba.gitnuro.system.OpenFilePickerUseCase import com.jetpackduba.gitnuro.system.OpenUrlInBrowserUseCase import com.jetpackduba.gitnuro.system.PickerType import com.jetpackduba.gitnuro.ui.IVerticalSplitPaneConfig import com.jetpackduba.gitnuro.ui.SelectedItem -import com.jetpackduba.gitnuro.ui.TabsManager import com.jetpackduba.gitnuro.ui.VerticalSplitPaneConfig import com.jetpackduba.gitnuro.updates.Update import com.jetpackduba.gitnuro.updates.UpdatesRepository -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch import org.eclipse.jgit.api.Git -import org.eclipse.jgit.api.errors.CheckoutConflictException -import org.eclipse.jgit.blame.BlameResult import org.eclipse.jgit.lib.Repository -import org.eclipse.jgit.lib.RepositoryState -import org.eclipse.jgit.revwalk.RevCommit -import java.awt.Desktop import java.io.File import javax.inject.Inject import javax.inject.Provider