cerrado @ c7a8aa113a914e70e027fea93265c7232b865b5e

  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	if err != nil {
103		return nil, err
104	}
105
106	return commits, nil
107}
108
109func (g *GitRepository) Head() (*plumbing.Reference, error) {
110	return g.repository.Head()
111}
112
113func (g *GitRepository) Tags() ([]*object.Tag, error) {
114	ti, err := g.repository.TagObjects()
115	if err != nil {
116		return nil, err
117	}
118
119	tags := []*object.Tag{}
120	err = ti.ForEach(func(t *object.Tag) error {
121		tags = append(tags, t)
122		return nil
123	})
124	if err != nil {
125		return nil, err
126	}
127
128	return tags, nil
129}
130
131func (g *GitRepository) Branches() ([]*plumbing.Reference, error) {
132	bs, err := g.repository.Branches()
133	if err != nil {
134		return nil, err
135	}
136
137	branches := []*plumbing.Reference{}
138	err = bs.ForEach(func(ref *plumbing.Reference) error {
139		branches = append(branches, ref)
140		return nil
141	})
142	if err != nil {
143		return nil, err
144	}
145
146	return branches, nil
147}
148
149func (g *GitRepository) Tree(path string) (*object.Tree, error) {
150	err := g.validateRef()
151	if err != nil {
152		return nil, err
153	}
154
155	c, err := g.repository.CommitObject(g.ref)
156	if err != nil {
157		return nil, err
158	}
159
160	tree, err := c.Tree()
161	if err != nil {
162		return nil, err
163	}
164
165	if path == "" {
166		return tree, nil
167	} else {
168		o, err := tree.FindEntry(path)
169		if err != nil {
170			return nil, err
171		}
172
173		if !o.Mode.IsFile() {
174			subtree, err := tree.Tree(path)
175			if err != nil {
176				return nil, err
177			}
178			return subtree, nil
179		} else {
180			return nil, TreeForFileErr
181		}
182	}
183}
184
185func (g *GitRepository) validateRef() error {
186	if !g.setRef {
187		return g.SetRef("")
188	}
189	return nil
190}
191
192func (g *GitRepository) FileContent(path string) (string, error) {
193	c, err := g.repository.CommitObject(g.ref)
194	if err != nil {
195		return "", err
196	}
197
198	tree, err := c.Tree()
199	if err != nil {
200		return "", err
201	}
202
203	file, err := tree.File(path)
204	if err != nil {
205		return "", err
206	}
207
208	isbin, err := file.IsBinary()
209	if err != nil {
210		return "", err
211	}
212
213	if !isbin {
214		return file.Contents()
215	} else {
216		return "Binary file", nil
217	}
218}