diff options
author | Andrei Miulescu <lusu777@gmail.com> | 2018-08-12 19:31:27 +1000 |
---|---|---|
committer | Andrei Miulescu <lusu777@gmail.com> | 2018-08-12 19:31:27 +1000 |
commit | dcd461d29f21a9626d5298a03283b6d8b46312c3 (patch) | |
tree | 42f43f27eb7403c60cc05805fc627debff76417b /pkg/git | |
parent | 98c22a36fdaf8806f8fafe8f1e23e53f8e97658d (diff) |
Restrucure project in a way where it is more modular
Diffstat (limited to 'pkg/git')
-rw-r--r-- | pkg/git/branch.go | 37 | ||||
-rw-r--r-- | pkg/git/branch_list_builder.go | 134 | ||||
-rw-r--r-- | pkg/git/git_structs.go | 28 |
3 files changed, 199 insertions, 0 deletions
diff --git a/pkg/git/branch.go b/pkg/git/branch.go new file mode 100644 index 000000000..e0fd75a73 --- /dev/null +++ b/pkg/git/branch.go @@ -0,0 +1,37 @@ +package git + +import ( + "strings" + + "github.com/fatih/color" +) + +// Branch : A git branch +type Branch struct { + Name string + Recency string +} + +// GetDisplayString returns the dispaly string of branch +// func (b *Branch) GetDisplayString() string { +// return gui.withPadding(b.Recency, 4) + gui.coloredString(b.Name, b.getColor()) +// } + +// GetColor branch color +func (b *Branch) GetColor() color.Attribute { + switch b.getType() { + case "feature": + return color.FgGreen + case "bugfix": + return color.FgYellow + case "hotfix": + return color.FgRed + default: + return color.FgWhite + } +} + +// expected to return feature/bugfix/hotfix or blank string +func (b *Branch) getType() string { + return strings.Split(b.Name, "/")[0] +} diff --git a/pkg/git/branch_list_builder.go b/pkg/git/branch_list_builder.go new file mode 100644 index 000000000..1abf11fcc --- /dev/null +++ b/pkg/git/branch_list_builder.go @@ -0,0 +1,134 @@ +package git + +import ( + "regexp" + "strings" + + "gopkg.in/src-d/go-git.v4/plumbing" +) + +// context: +// we want to only show 'safe' branches (ones that haven't e.g. been deleted) +// which `git branch -a` gives us, but we also want the recency data that +// git reflog gives us. +// So we get the HEAD, then append get the reflog branches that intersect with +// our safe branches, then add the remaining safe branches, ensuring uniqueness +// along the way + +type branchListBuilder struct{} + +func newBranchListBuilder() *branchListBuilder { + return &branchListBuilder{} +} + +func (b *branchListBuilder) obtainCurrentBranch() Branch { + // I used go-git for this, but that breaks if you've just done a git init, + // even though you're on 'master' + branchName, _ := runDirectCommand("git symbolic-ref --short HEAD") + return Branch{Name: strings.TrimSpace(branchName), Recency: " *"} +} + +func (*branchListBuilder) obtainReflogBranches() []Branch { + branches := make([]Branch, 0) + rawString, err := runDirectCommand("git reflog -n100 --pretty='%cr|%gs' --grep-reflog='checkout: moving' HEAD") + if err != nil { + return branches + } + + branchLines := splitLines(rawString) + for _, line := range branchLines { + timeNumber, timeUnit, branchName := branchInfoFromLine(line) + timeUnit = abbreviatedTimeUnit(timeUnit) + branch := Branch{Name: branchName, Recency: timeNumber + timeUnit} + branches = append(branches, branch) + } + return branches +} + +func (b *branchListBuilder) obtainSafeBranches() []Branch { + branches := make([]Branch, 0) + + bIter, err := r.Branches() + if err != nil { + panic(err) + } + err = bIter.ForEach(func(b *plumbing.Reference) error { + name := b.Name().Short() + branches = append(branches, Branch{Name: name}) + return nil + }) + + return branches +} + +func (b *branchListBuilder) appendNewBranches(finalBranches, newBranches, existingBranches []Branch, included bool) []Branch { + for _, newBranch := range newBranches { + if included == branchIncluded(newBranch.Name, existingBranches) { + finalBranches = append(finalBranches, newBranch) + } + } + return finalBranches +} + +func sanitisedReflogName(reflogBranch Branch, safeBranches []Branch) string { + for _, safeBranch := range safeBranches { + if strings.ToLower(safeBranch.Name) == strings.ToLower(reflogBranch.Name) { + return safeBranch.Name + } + } + return reflogBranch.Name +} + +func (b *branchListBuilder) build() []Branch { + branches := make([]Branch, 0) + head := b.obtainCurrentBranch() + safeBranches := b.obtainSafeBranches() + if len(safeBranches) == 0 { + return append(branches, head) + } + reflogBranches := b.obtainReflogBranches() + reflogBranches = uniqueByName(append([]Branch{head}, reflogBranches...)) + for i, reflogBranch := range reflogBranches { + reflogBranches[i].Name = sanitisedReflogName(reflogBranch, safeBranches) + } + + branches = b.appendNewBranches(branches, reflogBranches, safeBranches, true) + branches = b.appendNewBranches(branches, safeBranches, branches, false) + + return branches +} + +func uniqueByName(branches []Branch) []Branch { + finalBranches := make([]Branch, 0) + for _, branch := range branches { + if branchIncluded(branch.Name, finalBranches) { + continue + } + finalBranches = append(finalBranches, branch) + } + return finalBranches +} + +// A line will have the form '10 days ago master' so we need to strip out the +// useful information from that into timeNumber, timeUnit, and branchName +func branchInfoFromLine(line string) (string, string, string) { + r := regexp.MustCompile("\\|.*\\s") + line = r.ReplaceAllString(line, " ") + words := strings.Split(line, " ") + return words[0], words[1], words[3] +} + +func abbreviatedTimeUnit(timeUnit string) string { + r := regexp.MustCompile("s$") + timeUnit = r.ReplaceAllString(timeUnit, "") + timeUnitMap := map[string]string{ + "hour": "h", + "minute": "m", + "second": "s", + "week": "w", + "year": "y", + "day": "d", + "month": "m", + } + return timeUnitMap[timeUnit] +} diff --git a/pkg/git/git_structs.go b/pkg/git/git_structs.go new file mode 100644 index 000000000..711f25f4b --- /dev/null +++ b/pkg/git/git_structs.go @@ -0,0 +1,28 @@ +package git + +// File : A staged/unstaged file +// TODO: decide whether to give all of these the Git prefix +type File struct { + Name string + HasStagedChanges bool + HasUnstagedChanges bool + Tracked bool + Deleted bool + HasMergeConflicts bool + DisplayString string +} + +// Commit : A git commit +type Commit struct { + Sha string + Name string + Pushed bool + DisplayString string +} + +// StashEntry : A git stash entry +type StashEntry struct { + Index int + Name string + DisplayString string +} |