Removed log manager in favor of use casess

This commit is contained in:
Abdelilah El Aissaoui 2022-08-27 04:01:26 +02:00
parent 7b1ce8b17a
commit 4e387951e1
16 changed files with 230 additions and 156 deletions

View File

@ -1,118 +0,0 @@
package app.git
import app.git.graph.GraphCommitList
import app.git.graph.GraphWalk
import app.logging.printLog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.ResetCommand
import org.eclipse.jgit.lib.Constants
import org.eclipse.jgit.lib.Ref
import org.eclipse.jgit.revwalk.RevCommit
import javax.inject.Inject
private const val TAG = "LogManager"
class LogManager @Inject constructor() {
suspend fun loadLog(git: Git, currentBranch: Ref?, hasUncommitedChanges: Boolean, commitsLimit: Int) =
withContext(Dispatchers.IO) {
val commitList = GraphCommitList()
val repositoryState = git.repository.repositoryState
printLog(TAG, "Repository state ${repositoryState.description}")
if (currentBranch != null || repositoryState.isRebasing) { // Current branch is null when there is no log (new repo) or rebasing
val logList = git.log().setMaxCount(1).call().toList()
val walk = GraphWalk(git.repository)
walk.use {
// Without this, during rebase conflicts the graph won't show the HEAD commits (new commits created
// by the rebase)
walk.markStart(walk.lookupCommit(logList.first()))
walk.markStartAllRefs(Constants.R_HEADS)
walk.markStartAllRefs(Constants.R_REMOTES)
walk.markStartAllRefs(Constants.R_TAGS)
if (hasUncommitedChanges)
commitList.addUncommitedChangesGraphCommit(logList.first())
commitList.source(walk)
commitList.fillTo(commitsLimit)
}
ensureActive()
}
commitList.calcMaxLine()
return@withContext commitList
}
suspend fun checkoutCommit(git: Git, revCommit: RevCommit) = withContext(Dispatchers.IO) {
git
.checkout()
.setName(revCommit.name)
.call()
}
suspend fun revertCommit(git: Git, revCommit: RevCommit) = withContext(Dispatchers.IO) {
git
.revert()
.include(revCommit)
.call()
}
suspend fun resetToCommit(git: Git, revCommit: RevCommit, resetType: ResetType) = withContext(Dispatchers.IO) {
val reset = when (resetType) {
ResetType.SOFT -> ResetCommand.ResetType.SOFT
ResetType.MIXED -> ResetCommand.ResetType.MIXED
ResetType.HARD -> ResetCommand.ResetType.HARD
}
git
.reset()
.setMode(reset)
.setRef(revCommit.name)
.call()
}
suspend fun latestMessage(git: Git): String = withContext(Dispatchers.IO) {
try {
val log = git.log().setMaxCount(1).call()
val latestCommitNode = log.firstOrNull()
return@withContext if (latestCommitNode == null)
""
else
latestCommitNode.fullMessage
} catch (ex: Exception) {
ex.printStackTrace()
return@withContext ""
}
}
suspend fun hasPreviousCommits(git: Git): Boolean = withContext(Dispatchers.IO) {
try {
val log = git.log().setMaxCount(1).call()
val latestCommitNode = log.firstOrNull()
return@withContext latestCommitNode != null
} catch (ex: Exception) {
ex.printStackTrace()
return@withContext false
}
}
}
enum class ResetType {
SOFT,
MIXED,
HARD,
}

View File

@ -1,4 +1,4 @@
package app.git package app.git.branches
import app.exceptions.UncommitedChangesDetectedException import app.exceptions.UncommitedChangesDetectedException
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -6,13 +6,11 @@ import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.MergeCommand import org.eclipse.jgit.api.MergeCommand
import org.eclipse.jgit.api.MergeResult import org.eclipse.jgit.api.MergeResult
import org.eclipse.jgit.api.ResetCommand
import org.eclipse.jgit.lib.Ref import org.eclipse.jgit.lib.Ref
import org.eclipse.jgit.revwalk.RevCommit
import javax.inject.Inject import javax.inject.Inject
class MergeManager @Inject constructor() { class MergeBranchUseCase @Inject constructor() {
suspend fun mergeBranch(git: Git, branch: Ref, fastForward: Boolean) = withContext(Dispatchers.IO) { suspend operator fun invoke(git: Git, branch: Ref, fastForward: Boolean) = withContext(Dispatchers.IO) {
val fastForwardMode = if (fastForward) val fastForwardMode = if (fastForward)
MergeCommand.FastForwardMode.FF MergeCommand.FastForwardMode.FF
else else
@ -28,17 +26,4 @@ class MergeManager @Inject constructor() {
throw UncommitedChangesDetectedException("Merge failed, makes sure you repository doesn't contain uncommited changes.") throw UncommitedChangesDetectedException("Merge failed, makes sure you repository doesn't contain uncommited changes.")
} }
} }
suspend fun resetRepoState(git: Git) = withContext(Dispatchers.IO) {
git.repository.writeMergeCommitMsg(null)
git.repository.writeMergeHeads(null)
git.reset().setMode(ResetCommand.ResetType.HARD).call()
}
suspend fun cherryPickCommit(git: Git, revCommit: RevCommit) = withContext(Dispatchers.IO) {
git.cherryPick()
.include(revCommit)
.call()
}
} }

View File

@ -0,0 +1,21 @@
package app.git.log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import javax.inject.Inject
class CheckHasPreviousCommitsUseCase @Inject constructor() {
suspend operator fun invoke(git: Git): Boolean = withContext(Dispatchers.IO) {
try {
val log = git.log().setMaxCount(1).call()
val latestCommitNode = log.firstOrNull()
return@withContext latestCommitNode != null
} catch (ex: Exception) {
ex.printStackTrace()
return@withContext false
}
}
}

View File

@ -0,0 +1,16 @@
package app.git.log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.revwalk.RevCommit
import javax.inject.Inject
class CheckoutCommitUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, revCommit: RevCommit): Unit = withContext(Dispatchers.IO) {
git
.checkout()
.setName(revCommit.name)
.call()
}
}

View File

@ -0,0 +1,16 @@
package app.git.log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.CherryPickResult
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.revwalk.RevCommit
import javax.inject.Inject
class CherryPickCommitUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, revCommit: RevCommit): CherryPickResult = withContext(Dispatchers.IO) {
git.cherryPick()
.include(revCommit)
.call()
}
}

View File

@ -0,0 +1,24 @@
package app.git.log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import javax.inject.Inject
class GetLastCommitMessageUseCase @Inject constructor() {
suspend operator fun invoke(git: Git): String = withContext(Dispatchers.IO) {
try {
val log = git.log().setMaxCount(1).call()
val latestCommitNode = log.firstOrNull()
return@withContext if (latestCommitNode == null)
""
else
latestCommitNode.fullMessage
} catch (ex: Exception) {
ex.printStackTrace()
return@withContext ""
}
}
}

View File

@ -0,0 +1,49 @@
package app.git.log
import app.git.graph.GraphCommitList
import app.git.graph.GraphWalk
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.Constants
import org.eclipse.jgit.lib.Ref
import javax.inject.Inject
class GetLogUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, currentBranch: Ref?, hasUncommitedChanges: Boolean, commitsLimit: Int) =
withContext(Dispatchers.IO) {
val commitList = GraphCommitList()
val repositoryState = git.repository.repositoryState
if (currentBranch != null || repositoryState.isRebasing) { // Current branch is null when there is no log (new repo) or rebasing
val logList = git.log().setMaxCount(1).call().toList()
val walk = GraphWalk(git.repository)
walk.use {
// Without this, during rebase conflicts the graph won't show the HEAD commits (new commits created
// by the rebase)
walk.markStart(walk.lookupCommit(logList.first()))
walk.markStartAllRefs(Constants.R_HEADS)
walk.markStartAllRefs(Constants.R_REMOTES)
walk.markStartAllRefs(Constants.R_TAGS)
if (hasUncommitedChanges)
commitList.addUncommitedChangesGraphCommit(logList.first())
commitList.source(walk)
commitList.fillTo(commitsLimit)
}
ensureActive()
}
commitList.calcMaxLine()
return@withContext commitList
}
}

View File

@ -0,0 +1,30 @@
package app.git.log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.ResetCommand
import org.eclipse.jgit.revwalk.RevCommit
import javax.inject.Inject
class ResetToCommitUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, revCommit: RevCommit, resetType: ResetType): Unit =
withContext(Dispatchers.IO) {
val reset = when (resetType) {
ResetType.SOFT -> ResetCommand.ResetType.SOFT
ResetType.MIXED -> ResetCommand.ResetType.MIXED
ResetType.HARD -> ResetCommand.ResetType.HARD
}
git
.reset()
.setMode(reset)
.setRef(revCommit.name)
.call()
}
}
enum class ResetType {
SOFT,
MIXED,
HARD,
}

View File

@ -0,0 +1,16 @@
package app.git.log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.revwalk.RevCommit
import javax.inject.Inject
class RevertCommitUseCase @Inject constructor() {
suspend operator fun invoke(git: Git, revCommit: RevCommit): Unit = withContext(Dispatchers.IO) {
git
.revert()
.include(revCommit)
.call()
}
}

View File

@ -0,0 +1,20 @@
package app.git.repository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.ResetCommand
import javax.inject.Inject
class ResetRepositoryStateUseCase @Inject constructor() {
suspend operator fun invoke(git: Git): Unit = withContext(Dispatchers.IO) {
git.repository.apply {
writeMergeCommitMsg(null)
writeMergeHeads(null)
}
git.reset()
.setMode(ResetCommand.ResetType.HARD)
.call()
}
}

View File

@ -0,0 +1,6 @@
package app.git.tags
import javax.inject.Inject
class GetTagsUseCase @Inject constructor() {
}

View File

@ -13,7 +13,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import app.git.ResetType import app.git.log.ResetType
import app.theme.primaryTextColor import app.theme.primaryTextColor
import app.theme.textButtonColors import app.theme.textButtonColors
import app.ui.components.PrimaryButton import app.ui.components.PrimaryButton

View File

@ -728,7 +728,7 @@ fun SplitDiffLine(
Row( Row(
modifier = Modifier modifier = Modifier
.background(backgroundColor) .background(backgroundColor)
.fillMaxHeight() .fillMaxHeight(),
) { ) {
DisableSelection { DisableSelection {
LineNumber( LineNumber(

View File

@ -13,12 +13,12 @@ import javax.inject.Inject
class BranchesViewModel @Inject constructor( class BranchesViewModel @Inject constructor(
private val rebaseManager: RebaseManager, private val rebaseManager: RebaseManager,
private val mergeManager: MergeManager,
private val pushToSpecificBranchUseCase: PushToSpecificBranchUseCase,
private val pullFromSpecificBranchUseCase: PullFromSpecificBranchUseCase,
private val tabState: TabState, private val tabState: TabState,
private val appSettings: AppSettings, private val appSettings: AppSettings,
private val pushToSpecificBranchUseCase: PushToSpecificBranchUseCase,
private val pullFromSpecificBranchUseCase: PullFromSpecificBranchUseCase,
private val getCurrentBranchUseCase: GetCurrentBranchUseCase, private val getCurrentBranchUseCase: GetCurrentBranchUseCase,
private val mergeBranchUseCase: MergeBranchUseCase,
private val getBranchesUseCase: GetBranchesUseCase, private val getBranchesUseCase: GetBranchesUseCase,
private val createBranchUseCase: CreateBranchUseCase, private val createBranchUseCase: CreateBranchUseCase,
private val deleteBranchUseCase: DeleteBranchUseCase, private val deleteBranchUseCase: DeleteBranchUseCase,
@ -32,7 +32,7 @@ class BranchesViewModel @Inject constructor(
val currentBranch: StateFlow<Ref?> val currentBranch: StateFlow<Ref?>
get() = _currentBranch get() = _currentBranch
suspend fun loadBranches(git: Git) { private suspend fun loadBranches(git: Git) {
_currentBranch.value = getCurrentBranchUseCase(git) _currentBranch.value = getCurrentBranchUseCase(git)
val branchesList = getBranchesUseCase(git).toMutableList() val branchesList = getBranchesUseCase(git).toMutableList()
@ -59,7 +59,7 @@ class BranchesViewModel @Inject constructor(
fun mergeBranch(ref: Ref) = tabState.safeProcessing( fun mergeBranch(ref: Ref) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA, refreshType = RefreshType.ALL_DATA,
) { git -> ) { git ->
mergeManager.mergeBranch(git, ref, appSettings.ffMerge) mergeBranchUseCase(git, ref, appSettings.ffMerge)
} }
fun deleteBranch(branch: Ref) = tabState.safeProcessing( fun deleteBranch(branch: Ref) = tabState.safeProcessing(

View File

@ -7,6 +7,7 @@ import app.git.*
import app.git.branches.* import app.git.branches.*
import app.git.graph.GraphCommitList import app.git.graph.GraphCommitList
import app.git.graph.GraphNode import app.git.graph.GraphNode
import app.git.log.*
import app.git.remote_operations.DeleteRemoteBranchUseCase import app.git.remote_operations.DeleteRemoteBranchUseCase
import app.git.remote_operations.PullFromSpecificBranchUseCase import app.git.remote_operations.PullFromSpecificBranchUseCase
import app.git.remote_operations.PushToSpecificBranchUseCase import app.git.remote_operations.PushToSpecificBranchUseCase
@ -39,7 +40,7 @@ private const val FIRST_INDEX = 1
private const val LOG_MIN_TIME_IN_MS_TO_SHOW_LOAD = 500L private const val LOG_MIN_TIME_IN_MS_TO_SHOW_LOAD = 500L
class LogViewModel @Inject constructor( class LogViewModel @Inject constructor(
private val logManager: LogManager, private val getLogUseCase: GetLogUseCase,
private val getStatusSummaryUseCase: GetStatusSummaryUseCase, private val getStatusSummaryUseCase: GetStatusSummaryUseCase,
private val checkHasUncommitedChangedUseCase: CheckHasUncommitedChangedUseCase, private val checkHasUncommitedChangedUseCase: CheckHasUncommitedChangedUseCase,
private val getCurrentBranchUseCase: GetCurrentBranchUseCase, private val getCurrentBranchUseCase: GetCurrentBranchUseCase,
@ -49,9 +50,13 @@ class LogViewModel @Inject constructor(
private val pushToSpecificBranchUseCase: PushToSpecificBranchUseCase, private val pushToSpecificBranchUseCase: PushToSpecificBranchUseCase,
private val pullFromSpecificBranchUseCase: PullFromSpecificBranchUseCase, private val pullFromSpecificBranchUseCase: PullFromSpecificBranchUseCase,
private val deleteRemoteBranchUseCase: DeleteRemoteBranchUseCase, private val deleteRemoteBranchUseCase: DeleteRemoteBranchUseCase,
private val checkoutCommitUseCase: CheckoutCommitUseCase,
private val revertCommitUseCase: RevertCommitUseCase,
private val resetToCommitUseCase: ResetToCommitUseCase,
private val cherryPickCommitUseCase: CherryPickCommitUseCase,
private val mergeBranchUseCase: MergeBranchUseCase,
private val rebaseManager: RebaseManager, private val rebaseManager: RebaseManager,
private val tagsManager: TagsManager, private val tagsManager: TagsManager,
private val mergeManager: MergeManager,
private val tabState: TabState, private val tabState: TabState,
private val appSettings: AppSettings, private val appSettings: AppSettings,
) { ) {
@ -113,7 +118,7 @@ class LogViewModel @Inject constructor(
} else } else
-1 -1
val log = logManager.loadLog(git, currentBranch, hasUncommitedChanges, commitsLimit) val log = getLogUseCase(git, currentBranch, hasUncommitedChanges, commitsLimit)
_logStatus.value = _logStatus.value =
LogStatus.Loaded(hasUncommitedChanges, log, currentBranch, statusSummary, commitsLimitDisplayed) LogStatus.Loaded(hasUncommitedChanges, log, currentBranch, statusSummary, commitsLimitDisplayed)
@ -147,19 +152,19 @@ class LogViewModel @Inject constructor(
fun checkoutCommit(revCommit: RevCommit) = tabState.safeProcessing( fun checkoutCommit(revCommit: RevCommit) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA, refreshType = RefreshType.ALL_DATA,
) { git -> ) { git ->
logManager.checkoutCommit(git, revCommit) checkoutCommitUseCase(git, revCommit)
} }
fun revertCommit(revCommit: RevCommit) = tabState.safeProcessing( fun revertCommit(revCommit: RevCommit) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA, refreshType = RefreshType.ALL_DATA,
) { git -> ) { git ->
logManager.revertCommit(git, revCommit) revertCommitUseCase(git, revCommit)
} }
fun resetToCommit(revCommit: RevCommit, resetType: ResetType) = tabState.safeProcessing( fun resetToCommit(revCommit: RevCommit, resetType: ResetType) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA, refreshType = RefreshType.ALL_DATA,
) { git -> ) { git ->
logManager.resetToCommit(git, revCommit, resetType = resetType) resetToCommitUseCase(git, revCommit, resetType = resetType)
} }
fun checkoutRef(ref: Ref) = tabState.safeProcessing( fun checkoutRef(ref: Ref) = tabState.safeProcessing(
@ -171,7 +176,7 @@ class LogViewModel @Inject constructor(
fun cherrypickCommit(revCommit: RevCommit) = tabState.safeProcessing( fun cherrypickCommit(revCommit: RevCommit) = tabState.safeProcessing(
refreshType = RefreshType.UNCOMMITED_CHANGES_AND_LOG, refreshType = RefreshType.UNCOMMITED_CHANGES_AND_LOG,
) { git -> ) { git ->
mergeManager.cherryPickCommit(git, revCommit) cherryPickCommitUseCase(git, revCommit)
} }
fun createBranchOnCommit(branch: String, revCommit: RevCommit) = tabState.safeProcessing( fun createBranchOnCommit(branch: String, revCommit: RevCommit) = tabState.safeProcessing(
@ -189,7 +194,7 @@ class LogViewModel @Inject constructor(
fun mergeBranch(ref: Ref) = tabState.safeProcessing( fun mergeBranch(ref: Ref) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA, refreshType = RefreshType.ALL_DATA,
) { git -> ) { git ->
mergeManager.mergeBranch(git, ref, appSettings.ffMerge) mergeBranchUseCase(git, ref, appSettings.ffMerge)
} }
fun deleteBranch(branch: Ref) = tabState.safeProcessing( fun deleteBranch(branch: Ref) = tabState.safeProcessing(

View File

@ -5,6 +5,9 @@ import app.extensions.delayedStateChange
import app.extensions.isMerging import app.extensions.isMerging
import app.extensions.isReverting import app.extensions.isReverting
import app.git.* import app.git.*
import app.git.log.CheckHasPreviousCommitsUseCase
import app.git.log.GetLastCommitMessageUseCase
import app.git.repository.ResetRepositoryStateUseCase
import app.git.workspace.* import app.git.workspace.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
@ -26,9 +29,10 @@ class StatusViewModel @Inject constructor(
private val resetEntryUseCase: ResetEntryUseCase, private val resetEntryUseCase: ResetEntryUseCase,
private val stageAllUseCase: StageAllUseCase, private val stageAllUseCase: StageAllUseCase,
private val unstageAllUseCase: UnstageAllUseCase, private val unstageAllUseCase: UnstageAllUseCase,
private val checkHasPreviousCommitsUseCase: CheckHasPreviousCommitsUseCase,
private val getLastCommitMessageUseCase: GetLastCommitMessageUseCase,
private val resetRepositoryStateUseCase: ResetRepositoryStateUseCase,
private val rebaseManager: RebaseManager, private val rebaseManager: RebaseManager,
private val mergeManager: MergeManager,
private val logManager: LogManager,
private val getStatusUseCase: GetStatusUseCase, private val getStatusUseCase: GetStatusUseCase,
private val getStagedUseCase: GetStagedUseCase, private val getStagedUseCase: GetStagedUseCase,
private val getUnstagedUseCase: GetUnstagedUseCase, private val getUnstagedUseCase: GetUnstagedUseCase,
@ -169,7 +173,7 @@ class StatusViewModel @Inject constructor(
refreshType = RefreshType.ALL_DATA, refreshType = RefreshType.ALL_DATA,
) { git -> ) { git ->
val commitMessage = if (amend && message.isBlank()) { val commitMessage = if (amend && message.isBlank()) {
logManager.latestMessage(git) getLastCommitMessageUseCase(git)
} else } else
message message
@ -192,7 +196,7 @@ class StatusViewModel @Inject constructor(
loadHasUncommitedChanges(git) loadHasUncommitedChanges(git)
val hasNowUncommitedChanges = this.lastUncommitedChangesState val hasNowUncommitedChanges = this.lastUncommitedChangesState
hasPreviousCommits = logManager.hasPreviousCommits(git) hasPreviousCommits = checkHasPreviousCommitsUseCase(git)
// Return true to update the log only if the uncommitedChanges status has changed // Return true to update the log only if the uncommitedChanges status has changed
return (hasNowUncommitedChanges != hadUncommitedChanges) return (hasNowUncommitedChanges != hadUncommitedChanges)
@ -219,7 +223,7 @@ class StatusViewModel @Inject constructor(
fun resetRepoState() = tabState.safeProcessing( fun resetRepoState() = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA, refreshType = RefreshType.ALL_DATA,
) { git -> ) { git ->
mergeManager.resetRepoState(git) resetRepositoryStateUseCase(git)
} }
fun deleteFile(statusEntry: StatusEntry) = tabState.runOperation( fun deleteFile(statusEntry: StatusEntry) = tabState.runOperation(