cerrado @ d2c4023832e26d3fe3f77c9fa8581588ea812cc2

  1package git
  2
  3import (
  4	"errors"
  5	"fmt"
  6	"io"
  7
  8	"github.com/go-git/go-git/v5"
  9	"github.com/go-git/go-git/v5/plumbing"
 10	"github.com/go-git/go-git/v5/plumbing/object"
 11)
 12
 13var ()
 14
 15var (
 16	MissingRefErr  = errors.New("Reference not found")
 17	TreeForFileErr = errors.New("Trying to get tree of a file")
 18)
 19
 20type (
 21	GitRepository struct {
 22		path       string
 23		repository *git.Repository
 24
 25		ref plumbing.Hash
 26		// this is setRef when ref is setRef
 27		setRef bool
 28	}
 29)
 30
 31func OpenRepository(dir string) (*GitRepository, error) {
 32	g := &GitRepository{
 33		path: dir,
 34	}
 35
 36	repo, err := git.PlainOpen(dir)
 37	if err != nil {
 38		return nil, err
 39	}
 40	g.repository = repo
 41
 42	return g, nil
 43}
 44
 45func (g *GitRepository) SetRef(ref string) error {
 46	if ref == "" {
 47		head, err := g.repository.Head()
 48		if err != nil {
 49			return errors.Join(MissingRefErr, err)
 50		}
 51		g.ref = head.Hash()
 52	} else {
 53		hash, err := g.repository.ResolveRevision(plumbing.Revision(ref))
 54		if err != nil {
 55			return errors.Join(MissingRefErr, err)
 56		}
 57		g.ref = *hash
 58	}
 59	g.setRef = true
 60	return nil
 61}
 62
 63func (g *GitRepository) Path() string {
 64	return g.path
 65}
 66
 67func (g *GitRepository) LastCommit() (*object.Commit, error) {
 68	err := g.validateRef()
 69	if err != nil {
 70		return nil, err
 71	}
 72
 73	c, err := g.repository.CommitObject(g.ref)
 74	if err != nil {
 75		return nil, err
 76	}
 77	return c, nil
 78}
 79
 80func (g *GitRepository) Commits() ([]*object.Commit, error) {
 81	err := g.validateRef()
 82	if err != nil {
 83		return nil, err
 84	}
 85
 86	ci, err := g.repository.Log(&git.LogOptions{From: g.ref})
 87	if err != nil {
 88		return nil, fmt.Errorf("commits from ref: %w", err)
 89	}
 90
 91	commits := []*object.Commit{}
 92	// TODO: for now only load first 1000
 93	for x := 0; x < 1000; x++ {
 94		c, err := ci.Next()
 95		if err != nil && errors.Is(err, io.EOF) {
 96			break
 97		} else if err != nil {
 98			return nil, err
 99		}
100		commits = append(commits, c)
101	}
102
103	return commits, nil
104}
105
106func (g *GitRepository) Head() (*plumbing.Reference, error) {
107	return g.repository.Head()
108}
109
110func (g *GitRepository) Tags() ([]*plumbing.Reference, error) {
111	ti, err := g.repository.Tags()
112	if err != nil {
113		return nil, err
114	}
115
116	tags := []*plumbing.Reference{}
117	err = ti.ForEach(func(t *plumbing.Reference) error {
118		tags = append(tags, t)
119		return nil
120	})
121	if err != nil {
122		return nil, err
123	}
124
125	return tags, nil
126}
127
128func (g *GitRepository) Branches() ([]*plumbing.Reference, error) {
129	bs, err := g.repository.Branches()
130	if err != nil {
131		return nil, err
132	}
133
134	branches := []*plumbing.Reference{}
135	err = bs.ForEach(func(ref *plumbing.Reference) error {
136		branches = append(branches, ref)
137		return nil
138	})
139	if err != nil {
140		return nil, err
141	}
142
143	return branches, nil
144}
145
146func (g *GitRepository) Tree(path string) (*object.Tree, error) {
147	err := g.validateRef()
148	if err != nil {
149		return nil, err
150	}
151
152	c, err := g.repository.CommitObject(g.ref)
153	if err != nil {
154		return nil, err
155	}
156
157	tree, err := c.Tree()
158	if err != nil {
159		return nil, err
160	}
161
162	if path == "" {
163		return tree, nil
164	} else {
165		o, err := tree.FindEntry(path)
166		if err != nil {
167			return nil, err
168		}
169
170		if !o.Mode.IsFile() {
171			subtree, err := tree.Tree(path)
172			if err != nil {
173				return nil, err
174			}
175			return subtree, nil
176		} else {
177			return nil, TreeForFileErr
178		}
179	}
180}
181
182func (g *GitRepository) validateRef() error {
183	if !g.setRef {
184		return g.SetRef("")
185	}
186	return nil
187}
188
189func (g *GitRepository) FileContent(path string) (string, error) {
190	c, err := g.repository.CommitObject(g.ref)
191	if err != nil {
192		return "", err
193	}
194
195	tree, err := c.Tree()
196	if err != nil {
197		return "", err
198	}
199
200	file, err := tree.File(path)
201	if err != nil {
202		return "", err
203	}
204
205	isbin, err := file.IsBinary()
206	if err != nil {
207		return "", err
208	}
209
210	if !isbin {
211		return file.Contents()
212	} else {
213		return "Binary file", nil
214	}
215}