GitRepositoryManager/internal/commands/status_cmd.go

168 lines
4.0 KiB
Go
Raw Permalink Normal View History

2021-11-05 17:19:06 +00:00
package commands
import (
"fmt"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
2024-03-24 14:19:16 +00:00
"gitlab.com/revalus/grm/internal/config"
"path"
2024-03-24 14:19:16 +00:00
"sort"
2021-11-05 17:19:06 +00:00
)
type StatusChecker struct {
workspace string
}
func NewStatusChecker(workspace string) StatusChecker {
return StatusChecker{
workspace: workspace,
}
}
func findNumberOfCommitDiffs(srcCommit *object.Commit, dstCommit *object.Commit) int {
// This function is a helper function to get only five latest items, based on given commit
2021-11-05 17:19:06 +00:00
getFiveElementsFromHashes := func(commit *object.Commit, hashedSlice *[]string) *object.Commit {
var err error
for iter := 0; iter <= 5; iter++ {
*hashedSlice = append(*hashedSlice, commit.Hash.String())
commit, err = commit.Parents().Next()
if err != nil {
return nil
}
}
return commit
}
// Compare diff between sources by hash list (the same hash list must be present to assume the end of changes)
2021-11-05 17:19:06 +00:00
getRangeDiff := func(listFist, listSecond []string) (int, bool) {
diffRange := 0
for _, itemFirst := range listFist {
for _, itemSecond := range listSecond {
if itemFirst == itemSecond {
return diffRange, true
}
}
diffRange++
}
return diffRange, false
}
var baseCommitHashes []string
var destCommitHashes []string
// Try to find all differences, limit only to five last changes to avoid reading whole repository at once
2021-11-05 17:19:06 +00:00
for {
if srcCommit != nil {
srcCommit = getFiveElementsFromHashes(srcCommit, &baseCommitHashes)
}
if dstCommit != nil {
dstCommit = getFiveElementsFromHashes(dstCommit, &destCommitHashes)
}
diff, finished := getRangeDiff(baseCommitHashes, destCommitHashes)
if finished {
return diff
}
}
}
2021-11-08 17:30:45 +00:00
func (sc StatusChecker) Command(repoCfg config.RepositoryConfig) CommandStatus {
2021-11-05 17:19:06 +00:00
cmdStatus := CommandStatus{
Name: repoCfg.Name,
Changed: false,
Message: "",
Error: false,
}
repositoryPath := path.Join(sc.workspace, repoCfg.Dest)
repo, err := git.PlainOpen(repositoryPath)
2021-11-05 17:19:06 +00:00
if err != nil {
cmdStatus.Error = true
cmdStatus.Message = err.Error()
2021-11-08 17:30:45 +00:00
return cmdStatus
2021-11-05 17:19:06 +00:00
}
headReference, err := repo.Head()
if err != nil {
cmdStatus.Error = true
cmdStatus.Message = err.Error()
2021-11-08 17:30:45 +00:00
return cmdStatus
2021-11-05 17:19:06 +00:00
}
remotes, err := repo.Remotes()
if err != nil || len(remotes) == 0 {
cmdStatus.Error = true
cmdStatus.Message = "cannot find remote branches"
2021-11-08 17:30:45 +00:00
return cmdStatus
2021-11-05 17:19:06 +00:00
}
currentBranchCommit, err := repo.CommitObject(headReference.Hash())
if err != nil {
cmdStatus.Error = true
cmdStatus.Message = err.Error()
2021-11-08 17:30:45 +00:00
return cmdStatus
2021-11-05 17:19:06 +00:00
}
type remoteStatus struct {
ahead int
behind int
err error
}
2024-03-24 14:19:16 +00:00
var remoteNames []string
remoteStatues := make(map[string]remoteStatus)
2021-11-05 17:19:06 +00:00
for _, remote := range remotes {
remoteName := remote.Config().Name
remoteRevision, err := repo.ResolveRevision(plumbing.Revision(fmt.Sprintf("%v/%v", remoteName, headReference.Name().Short())))
if err != nil {
2024-03-24 14:19:16 +00:00
remoteStatues[remoteName] = remoteStatus{
2021-11-05 17:19:06 +00:00
err: err,
}
continue
}
remoteBranchCommit, err := repo.CommitObject(*remoteRevision)
if err != nil {
2024-03-24 14:19:16 +00:00
remoteStatues[remoteName] = remoteStatus{
2021-11-05 17:19:06 +00:00
err: err,
}
continue
}
status := remoteStatus{
ahead: findNumberOfCommitDiffs(currentBranchCommit, remoteBranchCommit),
behind: findNumberOfCommitDiffs(remoteBranchCommit, currentBranchCommit),
}
if status.ahead > 0 || status.behind > 0 {
cmdStatus.Changed = true
}
2024-03-24 14:19:16 +00:00
remoteNames = append(remoteNames, remoteName)
remoteStatues[remoteName] = status
2021-11-05 17:19:06 +00:00
}
2024-03-24 14:19:16 +00:00
sort.Strings(remoteNames)
2021-11-05 17:19:06 +00:00
cmdStatus.Message = fmt.Sprintf("branch %v", headReference.Name().Short())
2024-03-24 14:19:16 +00:00
for _, remoteName := range remoteNames {
status := remoteStatues[remoteName]
2021-11-05 17:19:06 +00:00
if status.err != nil {
cmdStatus.Message = fmt.Sprintf("%v - ( | %v | problem: %v )", cmdStatus.Message, remoteName, status.err.Error())
continue
}
cmdStatus.Message = fmt.Sprintf("%v - ( | %v | \u2191%v \u2193%v )", cmdStatus.Message, remoteName, status.ahead, status.behind)
}
2021-11-08 17:30:45 +00:00
return cmdStatus
2021-11-05 17:19:06 +00:00
}