import git.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.eclipse.jgit.api.Git import org.eclipse.jgit.diff.DiffEntry import org.eclipse.jgit.lib.Ref import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.storage.file.FileRepositoryBuilder import java.io.File class GitManager { private val preferences = GPreferences() private val statusManager = StatusManager() private val logManager = LogManager() private val remoteOperationsManager = RemoteOperationsManager() private val branchesManager = BranchesManager() private val stashManager = StashManager() private val diffManager = DiffManager() private val managerScope = CoroutineScope(SupervisorJob()) private val _repositorySelectionStatus = MutableStateFlow(RepositorySelectionStatus.None) val repositorySelectionStatus: StateFlow get() = _repositorySelectionStatus private val _processing = MutableStateFlow(false) val processing: StateFlow get() = _processing private val _lastTimeChecked = MutableStateFlow(System.currentTimeMillis()) val lastTimeChecked: StateFlow get() = _lastTimeChecked val stageStatus: StateFlow get() = statusManager.stageStatus val logStatus: StateFlow get() = logManager.logStatus val branches: StateFlow> get() = branchesManager.branches val currentBranch: StateFlow get() = branchesManager.currentBranch val stashStatus: StateFlow get() = stashManager.stashStatus val latestDirectoryOpened: File? get() = File(preferences.latestOpenedRepositoryPath).parentFile private var git: Git? = null val safeGit: Git get() { val git = this.git if (git == null) { _repositorySelectionStatus.value = RepositorySelectionStatus.None throw CancellationException() } else return git } init { val latestOpenedRepositoryPath = preferences.latestOpenedRepositoryPath if (latestOpenedRepositoryPath.isNotEmpty()) { openRepository(File(latestOpenedRepositoryPath)) } } fun openRepository(directory: File) { val gitDirectory = if (directory.name == ".git") { directory } else { val gitDir = File(directory, ".git") if (gitDir.exists() && gitDir.isDirectory) { gitDir } else directory } val builder = FileRepositoryBuilder() val repository: Repository = builder.setGitDir(gitDirectory) .readEnvironment() // scan environment GIT_* variables .findGitDir() // scan up the file system tree .build() try { repository.workTree // test if repository is valid preferences.latestOpenedRepositoryPath = gitDirectory.path _repositorySelectionStatus.value = RepositorySelectionStatus.Open(repository) git = Git(repository) refreshRepositoryInfo() } catch (ex: Exception) { ex.printStackTrace() } } fun loadLog() = managerScope.launch { logManager.loadLog(safeGit) } suspend fun loadStatus() { statusManager.loadStatus(safeGit) } fun stage(diffEntry: DiffEntry) = managerScope.launch { statusManager.stage(safeGit, diffEntry) } fun unstage(diffEntry: DiffEntry) = managerScope.launch { statusManager.unstage(safeGit, diffEntry) } fun commit(message: String) = managerScope.launch { statusManager.commit(safeGit, message) logManager.loadLog(safeGit) } val hasUncommitedChanges: StateFlow get() = statusManager.hasUncommitedChanges suspend fun diffFormat(diffEntryType: DiffEntryType): List { return diffManager.diffFormat(safeGit, diffEntryType) } fun pull() = managerScope.launch { remoteOperationsManager.pull(safeGit) } fun push() = managerScope.launch { remoteOperationsManager.push(safeGit) } private fun refreshRepositoryInfo() = managerScope.launch { statusManager.loadHasUncommitedChanges(safeGit) branchesManager.loadBranches(safeGit) stashManager.loadStashList(safeGit) loadLog() } fun stash() = managerScope.launch { stashManager.stash(safeGit) loadStatus() } fun popStash() = managerScope.launch { stashManager.popStash(safeGit) loadStatus() } fun createBranch(branchName: String) = managerScope.launch { branchesManager.createBranch(safeGit, branchName) } fun deleteBranch(branch: Ref) = managerScope.launch { branchesManager.deleteBranch(safeGit, branch) } fun resetStaged(diffEntry: DiffEntry) = managerScope.launch { statusManager.reset(safeGit, diffEntry, staged = true) } fun resetUnstaged(diffEntry: DiffEntry) = managerScope.launch { statusManager.reset(safeGit, diffEntry, staged = false) } fun statusShouldBeUpdated() { _lastTimeChecked.value = System.currentTimeMillis() } } sealed class RepositorySelectionStatus { object None : RepositorySelectionStatus() object Loading : RepositorySelectionStatus() data class Open(val repository: Repository) : RepositorySelectionStatus() }