Removed repository & remotes managers in favor of use cases

This commit is contained in:
Abdelilah El Aissaoui 2022-09-03 17:15:44 +02:00
parent 32b2c1df11
commit 7148e59eeb
11 changed files with 123 additions and 80 deletions

View File

@ -1,48 +0,0 @@
package app.git
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.RemoteSetUrlCommand
import org.eclipse.jgit.lib.Ref
import org.eclipse.jgit.transport.RemoteConfig
import org.eclipse.jgit.transport.URIish
import javax.inject.Inject
class RemotesManager @Inject constructor() {
suspend fun loadRemotes(git: Git, allRemoteBranches: List<Ref>) = withContext(Dispatchers.IO) {
val remotes = git.remoteList()
.call()
return@withContext remotes.map { remoteConfig ->
val remoteBranches = allRemoteBranches.filter { branch ->
branch.name.startsWith("refs/remotes/${remoteConfig.name}")
}
RemoteInfo(remoteConfig, remoteBranches)
}
}
suspend fun deleteRemote(git: Git, remoteName: String) = withContext(Dispatchers.IO) {
git.remoteRemove()
.setRemoteName(remoteName)
.call()
}
suspend fun addRemote(git: Git, remoteName: String, fetchUri: String) = withContext(Dispatchers.IO) {
git.remoteAdd()
.setName(remoteName)
.setUri(URIish(fetchUri))
.call()
}
suspend fun updateRemote(git: Git, remoteName: String, uri: String, uriType: RemoteSetUrlCommand.UriType) =
withContext(Dispatchers.IO) {
git.remoteSetUrl()
.setRemoteName(remoteName)
.setRemoteUri(URIish(uri))
.setUriType(uriType)
.call()
}
}
data class RemoteInfo(val remoteConfig: RemoteConfig, val branchesList: List<Ref>)

View File

@ -5,7 +5,7 @@ import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git import org.eclipse.jgit.api.Git
import javax.inject.Inject import javax.inject.Inject
class DeleteLocallyRemoteBranches @Inject constructor() { class DeleteLocallyRemoteBranchesUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, branches: List<String>): List<String> = withContext(Dispatchers.IO) { suspend operator fun invoke(git: Git, branches: List<String>): List<String> = withContext(Dispatchers.IO) {
git git
.branchDelete() .branchDelete()

View File

@ -0,0 +1,16 @@
package app.git.remotes
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.transport.URIish
import javax.inject.Inject
class AddRemoteUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, remoteName: String, fetchUri: String): Unit = withContext(Dispatchers.IO) {
git.remoteAdd()
.setName(remoteName)
.setUri(URIish(fetchUri))
.call()
}
}

View File

@ -0,0 +1,14 @@
package app.git.remotes
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import javax.inject.Inject
class DeleteRemoteUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, remoteName: String): Unit = withContext(Dispatchers.IO) {
git.remoteRemove()
.setRemoteName(remoteName)
.call()
}
}

View File

@ -0,0 +1,22 @@
package app.git.remotes
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.Ref
import javax.inject.Inject
class GetRemotesUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, allRemoteBranches: List<Ref>): List<RemoteInfo> =
withContext(Dispatchers.IO) {
val remotes = git.remoteList()
.call()
return@withContext remotes.map { remoteConfig ->
val remoteBranches = allRemoteBranches.filter { branch ->
branch.name.startsWith("refs/remotes/${remoteConfig.name}")
}
RemoteInfo(remoteConfig, remoteBranches)
}
}
}

View File

@ -0,0 +1,6 @@
package app.git.remotes
import org.eclipse.jgit.lib.Ref
import org.eclipse.jgit.transport.RemoteConfig
data class RemoteInfo(val remoteConfig: RemoteConfig, val branchesList: List<Ref>)

View File

@ -0,0 +1,19 @@
package app.git.remotes
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.RemoteSetUrlCommand
import org.eclipse.jgit.transport.URIish
import javax.inject.Inject
class UpdateRemoteUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, remoteName: String, uri: String, uriType: RemoteSetUrlCommand.UriType): Unit =
withContext(Dispatchers.IO) {
git.remoteSetUrl()
.setRemoteName(remoteName)
.setRemoteUri(URIish(uri))
.setUriType(uriType)
.call()
}
}

View File

@ -0,0 +1,18 @@
package app.git.repository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import java.io.File
import javax.inject.Inject
private const val INITIAL_BRANCH_NAME = "main"
class InitLocalRepositoryUseCase @Inject constructor() {
suspend operator fun invoke(repoDir: File): Unit = withContext(Dispatchers.IO) {
Git.init()
.setInitialBranch(INITIAL_BRANCH_NAME)
.setDirectory(repoDir)
.call()
}
}

View File

@ -1,21 +1,14 @@
package app.git package app.git.repository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.lib.Repository
import org.eclipse.jgit.storage.file.FileRepositoryBuilder import org.eclipse.jgit.storage.file.FileRepositoryBuilder
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
private const val INITIAL_BRANCH_NAME = "main" class OpenRepositoryUseCase @Inject constructor() {
suspend operator fun invoke(directory: File): Repository = withContext(Dispatchers.IO) {
class RepositoryManager @Inject constructor() {
suspend fun getRepositoryState(git: Git) = withContext(Dispatchers.IO) {
return@withContext git.repository.repositoryState
}
fun openRepository(directory: File): Repository {
val gitDirectory = if (directory.name == ".git") { val gitDirectory = if (directory.name == ".git") {
directory directory
} else { } else {
@ -27,16 +20,9 @@ class RepositoryManager @Inject constructor() {
} }
val builder = FileRepositoryBuilder() val builder = FileRepositoryBuilder()
return builder.setGitDir(gitDirectory) return@withContext builder.setGitDir(gitDirectory)
.readEnvironment() // scan environment GIT_* variables .readEnvironment() // scan environment GIT_* variables
.findGitDir() // scan up the file system tree .findGitDir() // scan up the file system tree
.build() .build()
} }
suspend fun initLocalRepo(repoDir: File): Unit = withContext(Dispatchers.IO) {
Git.init()
.setInitialBranch(INITIAL_BRANCH_NAME)
.setDirectory(repoDir)
.call()
}
} }

View File

@ -2,9 +2,10 @@ package app.viewmodels
import app.exceptions.InvalidRemoteUrlException import app.exceptions.InvalidRemoteUrlException
import app.git.* import app.git.*
import app.git.branches.DeleteLocallyRemoteBranches import app.git.branches.DeleteLocallyRemoteBranchesUseCase
import app.git.branches.GetRemoteBranchesUseCase import app.git.branches.GetRemoteBranchesUseCase
import app.git.remote_operations.DeleteRemoteBranchUseCase import app.git.remote_operations.DeleteRemoteBranchUseCase
import app.git.remotes.*
import app.ui.dialogs.RemoteWrapper import app.ui.dialogs.RemoteWrapper
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@ -16,11 +17,14 @@ import org.eclipse.jgit.lib.Ref
import javax.inject.Inject import javax.inject.Inject
class RemotesViewModel @Inject constructor( class RemotesViewModel @Inject constructor(
private val remotesManager: RemotesManager,
private val deleteRemoteBranchUseCase: DeleteRemoteBranchUseCase,
private val tabState: TabState, private val tabState: TabState,
private val deleteRemoteBranchUseCase: DeleteRemoteBranchUseCase,
private val getRemoteBranchesUseCase: GetRemoteBranchesUseCase, private val getRemoteBranchesUseCase: GetRemoteBranchesUseCase,
private val deleteLocallyRemoteBranchesUseCase: DeleteLocallyRemoteBranches, private val getRemotesUseCase: GetRemotesUseCase,
private val deleteRemoteUseCase: DeleteRemoteUseCase,
private val addRemoteUseCase: AddRemoteUseCase,
private val updateRemoteUseCase: UpdateRemoteUseCase,
private val deleteLocallyRemoteBranchesUseCase: DeleteLocallyRemoteBranchesUseCase
) : ExpandableViewModel() { ) : ExpandableViewModel() {
private val _remotes = MutableStateFlow<List<RemoteView>>(listOf()) private val _remotes = MutableStateFlow<List<RemoteView>>(listOf())
val remotes: StateFlow<List<RemoteView>> val remotes: StateFlow<List<RemoteView>>
@ -31,7 +35,8 @@ class RemotesViewModel @Inject constructor(
.call() .call()
val allRemoteBranches = getRemoteBranchesUseCase(git) val allRemoteBranches = getRemoteBranchesUseCase(git)
remotesManager.loadRemotes(git, allRemoteBranches) getRemotesUseCase(git, allRemoteBranches)
val remoteInfoList = remotes.map { remoteConfig -> val remoteInfoList = remotes.map { remoteConfig ->
val remoteBranches = allRemoteBranches.filter { branch -> val remoteBranches = allRemoteBranches.filter { branch ->
branch.name.startsWith("refs/remotes/${remoteConfig.name}") branch.name.startsWith("refs/remotes/${remoteConfig.name}")
@ -74,7 +79,7 @@ class RemotesViewModel @Inject constructor(
refreshType = if (isNew) RefreshType.REMOTES else RefreshType.ALL_DATA, refreshType = if (isNew) RefreshType.REMOTES else RefreshType.ALL_DATA,
showError = true, showError = true,
) { git -> ) { git ->
remotesManager.deleteRemote(git, remoteName) deleteRemoteUseCase(git, remoteName)
val remoteBranches = getRemoteBranchesUseCase(git) val remoteBranches = getRemoteBranchesUseCase(git)
val remoteToDeleteBranchesNames = remoteBranches.filter { val remoteToDeleteBranchesNames = remoteBranches.filter {
@ -99,7 +104,7 @@ class RemotesViewModel @Inject constructor(
throw InvalidRemoteUrlException("Invalid empty push URI") throw InvalidRemoteUrlException("Invalid empty push URI")
} }
remotesManager.addRemote(git, selectedRemoteConfig.remoteName, selectedRemoteConfig.fetchUri) addRemoteUseCase(git, selectedRemoteConfig.remoteName, selectedRemoteConfig.fetchUri)
updateRemote(selectedRemoteConfig) // Sets both, fetch and push uri updateRemote(selectedRemoteConfig) // Sets both, fetch and push uri
} }
@ -117,14 +122,14 @@ class RemotesViewModel @Inject constructor(
throw InvalidRemoteUrlException("Invalid empty push URI") throw InvalidRemoteUrlException("Invalid empty push URI")
} }
remotesManager.updateRemote( updateRemoteUseCase(
git = git, git = git,
remoteName = selectedRemoteConfig.remoteName, remoteName = selectedRemoteConfig.remoteName,
uri = selectedRemoteConfig.fetchUri, uri = selectedRemoteConfig.fetchUri,
uriType = RemoteSetUrlCommand.UriType.FETCH uriType = RemoteSetUrlCommand.UriType.FETCH
) )
remotesManager.updateRemote( updateRemoteUseCase(
git = git, git = git,
remoteName = selectedRemoteConfig.remoteName, remoteName = selectedRemoteConfig.remoteName,
uri = selectedRemoteConfig.pushUri, uri = selectedRemoteConfig.pushUri,

View File

@ -5,6 +5,9 @@ import app.ErrorsManager
import app.credentials.CredentialsState import app.credentials.CredentialsState
import app.credentials.CredentialsStateManager import app.credentials.CredentialsStateManager
import app.git.* import app.git.*
import app.git.repository.GetRepositoryStateUseCase
import app.git.repository.InitLocalRepositoryUseCase
import app.git.repository.OpenRepositoryUseCase
import app.logging.printLog import app.logging.printLog
import app.models.AuthorInfoSimple import app.models.AuthorInfoSimple
import app.newErrorNow import app.newErrorNow
@ -43,11 +46,13 @@ class TabViewModel @Inject constructor(
val stashesViewModel: StashesViewModel, val stashesViewModel: StashesViewModel,
val commitChangesViewModel: CommitChangesViewModel, val commitChangesViewModel: CommitChangesViewModel,
val cloneViewModel: CloneViewModel, val cloneViewModel: CloneViewModel,
private val getRepositoryStateUseCase: GetRepositoryStateUseCase,
private val initLocalRepositoryUseCase: InitLocalRepositoryUseCase,
private val openRepositoryUseCase: OpenRepositoryUseCase,
private val diffViewModelProvider: Provider<DiffViewModel>, private val diffViewModelProvider: Provider<DiffViewModel>,
private val rebaseInteractiveViewModelProvider: Provider<RebaseInteractiveViewModel>, private val rebaseInteractiveViewModelProvider: Provider<RebaseInteractiveViewModel>,
private val historyViewModelProvider: Provider<HistoryViewModel>, private val historyViewModelProvider: Provider<HistoryViewModel>,
private val authorViewModelProvider: Provider<AuthorViewModel>, private val authorViewModelProvider: Provider<AuthorViewModel>,
private val repositoryManager: RepositoryManager,
private val tabState: TabState, private val tabState: TabState,
val appStateManager: AppStateManager, val appStateManager: AppStateManager,
private val fileChangesWatcher: FileChangesWatcher, private val fileChangesWatcher: FileChangesWatcher,
@ -167,7 +172,7 @@ class TabViewModel @Inject constructor(
_repositorySelectionStatus.value = RepositorySelectionStatus.Opening(directory.absolutePath) _repositorySelectionStatus.value = RepositorySelectionStatus.Opening(directory.absolutePath)
val repository: Repository = repositoryManager.openRepository(directory) val repository: Repository = openRepositoryUseCase(directory)
try { try {
repository.workTree // test if repository is valid repository.workTree // test if repository is valid
@ -188,7 +193,7 @@ class TabViewModel @Inject constructor(
} }
private suspend fun loadRepositoryState(git: Git) = withContext(Dispatchers.IO) { private suspend fun loadRepositoryState(git: Git) = withContext(Dispatchers.IO) {
val newRepoState = repositoryManager.getRepositoryState(git) val newRepoState = getRepositoryStateUseCase(git)
printLog(TAG, "Refreshing repository state $newRepoState") printLog(TAG, "Refreshing repository state $newRepoState")
_repositoryState.value = newRepoState _repositoryState.value = newRepoState
@ -364,7 +369,7 @@ class TabViewModel @Inject constructor(
showError = true, showError = true,
) { ) {
val repoDir = File(dir) val repoDir = File(dir)
repositoryManager.initLocalRepo(repoDir) initLocalRepositoryUseCase(repoDir)
openRepository(repoDir) openRepository(repoDir)
} }