git/git.go (view raw)
1package git
2
3import (
4 "fmt"
5 "sort"
6
7 "github.com/go-git/go-git/v5"
8 "github.com/go-git/go-git/v5/plumbing"
9 "github.com/go-git/go-git/v5/plumbing/object"
10)
11
12type GitRepo struct {
13 r *git.Repository
14 h plumbing.Hash
15}
16
17type TagList []*object.Tag
18
19func (self TagList) Len() int {
20 return len(self)
21}
22
23func (self TagList) Swap(i, j int) {
24 self[i], self[j] = self[j], self[i]
25}
26
27// sorting tags in reverse chronological order
28func (self TagList) Less(i, j int) bool {
29 return self[i].Tagger.When.After(self[j].Tagger.When)
30}
31
32func Open(path string, ref string) (*GitRepo, error) {
33 var err error
34 g := GitRepo{}
35 g.r, err = git.PlainOpen(path)
36 if err != nil {
37 g.r, err = git.PlainOpen(path + ".git")
38 if err != nil {
39 return nil, fmt.Errorf("opening %s: %w", path, err)
40 }
41 }
42
43 if ref == "" {
44 head, err := g.r.Head()
45 if err != nil {
46 return nil, fmt.Errorf("getting head of %s: %w", path, err)
47 }
48 g.h = head.Hash()
49 } else {
50 hash, err := g.r.ResolveRevision(plumbing.Revision(ref))
51 if err != nil {
52 return nil, fmt.Errorf("resolving rev %s for %s: %w", ref, path, err)
53 }
54 g.h = *hash
55 }
56 return &g, nil
57}
58
59func (g *GitRepo) Commits() ([]*object.Commit, error) {
60 ci, err := g.r.Log(&git.LogOptions{From: g.h})
61 if err != nil {
62 return nil, fmt.Errorf("commits from ref: %w", err)
63 }
64
65 commits := []*object.Commit{}
66 ci.ForEach(func(c *object.Commit) error {
67 commits = append(commits, c)
68 return nil
69 })
70
71 return commits, nil
72}
73
74func (g *GitRepo) LastCommit() (*object.Commit, error) {
75 c, err := g.r.CommitObject(g.h)
76 if err != nil {
77 return nil, fmt.Errorf("last commit: %w", err)
78 }
79 return c, nil
80}
81
82func (g *GitRepo) FileContent(path string) (string, error) {
83 c, err := g.r.CommitObject(g.h)
84 if err != nil {
85 return "", fmt.Errorf("commit object: %w", err)
86 }
87
88 tree, err := c.Tree()
89 if err != nil {
90 return "", fmt.Errorf("file tree: %w", err)
91 }
92
93 file, err := tree.File(path)
94 if err != nil {
95 return "", err
96 }
97
98 isbin, _ := file.IsBinary()
99
100 if !isbin {
101 return file.Contents()
102 } else {
103 return "Not displaying binary file", nil
104 }
105}
106
107func (g *GitRepo) Tags() ([]*object.Tag, error) {
108 ti, err := g.r.TagObjects()
109 if err != nil {
110 return nil, fmt.Errorf("tag objects: %w", err)
111 }
112
113 tags := []*object.Tag{}
114
115 _ = ti.ForEach(func(t *object.Tag) error {
116 for i, existing := range tags {
117 if existing.Name == t.Name {
118 if t.Tagger.When.After(existing.Tagger.When) {
119 tags[i] = t
120 }
121 return nil
122 }
123 }
124 tags = append(tags, t)
125 return nil
126 })
127
128 var tagList TagList
129 tagList = tags
130 sort.Sort(tagList)
131
132 return tags, nil
133}
134
135func (g *GitRepo) Branches() ([]*plumbing.Reference, error) {
136 bi, err := g.r.Branches()
137 if err != nil {
138 return nil, fmt.Errorf("branchs: %w", err)
139 }
140
141 branches := []*plumbing.Reference{}
142
143 _ = bi.ForEach(func(ref *plumbing.Reference) error {
144 branches = append(branches, ref)
145 return nil
146 })
147
148 return branches, nil
149}
150
151func (g *GitRepo) FindMainBranch(branches []string) (string, error) {
152 for _, b := range branches {
153 _, err := g.r.ResolveRevision(plumbing.Revision(b))
154 if err == nil {
155 return b, nil
156 }
157 }
158 return "", fmt.Errorf("unable to find main branch")
159}