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 return nil, fmt.Errorf("opening %s: %w", path, err)
38 }
39
40 if ref == "" {
41 head, err := g.r.Head()
42 if err != nil {
43 return nil, fmt.Errorf("getting head of %s: %w", path, err)
44 }
45 g.h = head.Hash()
46 } else {
47 hash, err := g.r.ResolveRevision(plumbing.Revision(ref))
48 if err != nil {
49 return nil, fmt.Errorf("resolving rev %s for %s: %w", ref, path, err)
50 }
51 g.h = *hash
52 }
53 return &g, nil
54}
55
56func (g *GitRepo) Commits() ([]*object.Commit, error) {
57 ci, err := g.r.Log(&git.LogOptions{From: g.h})
58 if err != nil {
59 return nil, fmt.Errorf("commits from ref: %w", err)
60 }
61
62 commits := []*object.Commit{}
63 ci.ForEach(func(c *object.Commit) error {
64 commits = append(commits, c)
65 return nil
66 })
67
68 return commits, nil
69}
70
71func (g *GitRepo) LastCommit() (*object.Commit, error) {
72 c, err := g.r.CommitObject(g.h)
73 if err != nil {
74 return nil, fmt.Errorf("last commit: %w", err)
75 }
76 return c, nil
77}
78
79func (g *GitRepo) FileContent(path string) (string, error) {
80 c, err := g.r.CommitObject(g.h)
81 if err != nil {
82 return "", fmt.Errorf("commit object: %w", err)
83 }
84
85 tree, err := c.Tree()
86 if err != nil {
87 return "", fmt.Errorf("file tree: %w", err)
88 }
89
90 file, err := tree.File(path)
91 if err != nil {
92 return "", err
93 }
94
95 isbin, _ := file.IsBinary()
96
97 if !isbin {
98 return file.Contents()
99 } else {
100 return "Not displaying binary file", nil
101 }
102}
103
104func (g *GitRepo) Tags() ([]*object.Tag, error) {
105 ti, err := g.r.TagObjects()
106 if err != nil {
107 return nil, fmt.Errorf("tag objects: %w", err)
108 }
109
110 tags := []*object.Tag{}
111
112 _ = ti.ForEach(func(t *object.Tag) error {
113 for i, existing := range tags {
114 if existing.Name == t.Name {
115 if t.Tagger.When.After(existing.Tagger.When) {
116 tags[i] = t
117 }
118 return nil
119 }
120 }
121 tags = append(tags, t)
122 return nil
123 })
124
125 var tagList TagList
126 tagList = tags
127 sort.Sort(tagList)
128
129 return tags, nil
130}
131
132func (g *GitRepo) Branches() ([]*plumbing.Reference, error) {
133 bi, err := g.r.Branches()
134 if err != nil {
135 return nil, fmt.Errorf("branchs: %w", err)
136 }
137
138 branches := []*plumbing.Reference{}
139
140 _ = bi.ForEach(func(ref *plumbing.Reference) error {
141 branches = append(branches, ref)
142 return nil
143 })
144
145 return branches, nil
146}
147
148func (g *GitRepo) FindMainBranch(branches []string) (string, error) {
149 for _, b := range branches {
150 _, err := g.r.ResolveRevision(plumbing.Revision(b))
151 if err == nil {
152 return b, nil
153 }
154 }
155 return "", fmt.Errorf("unable to find main branch")
156}