summaryrefslogtreecommitdiffstats
path: root/pkg/git
diff options
context:
space:
mode:
authorAndrei Miulescu <lusu777@gmail.com>2018-08-12 19:31:27 +1000
committerAndrei Miulescu <lusu777@gmail.com>2018-08-12 19:31:27 +1000
commitdcd461d29f21a9626d5298a03283b6d8b46312c3 (patch)
tree42f43f27eb7403c60cc05805fc627debff76417b /pkg/git
parent98c22a36fdaf8806f8fafe8f1e23e53f8e97658d (diff)
Restrucure project in a way where it is more modular
Diffstat (limited to 'pkg/git')
-rw-r--r--pkg/git/branch.go37
-rw-r--r--pkg/git/branch_list_builder.go134
-rw-r--r--pkg/git/git_structs.go28
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
+}