cerrado @ v0.2.1

  1package service
  2
  3import (
  4	"compress/gzip"
  5	"context"
  6	"errors"
  7	"io"
  8	"log/slog"
  9
 10	"git.gabrielgio.me/cerrado/pkg/config"
 11	"git.gabrielgio.me/cerrado/pkg/git"
 12	gogit "github.com/go-git/go-git/v5"
 13	"github.com/go-git/go-git/v5/plumbing"
 14	"github.com/go-git/go-git/v5/plumbing/object"
 15)
 16
 17type (
 18	Repository struct {
 19		Name        string
 20		Description string
 21		Public      bool
 22		LastCommit  *git.CommitReference
 23		Ref         string
 24	}
 25
 26	GitService struct {
 27		configRepo configurationRepository
 28	}
 29
 30	configurationRepository interface {
 31		List() []*config.GitRepositoryConfiguration
 32		GetByName(name string) *config.GitRepositoryConfiguration
 33	}
 34)
 35
 36var ErrRepositoryNotFound = errors.New("Repository not found")
 37
 38// TODO: make it configurable
 39const timeFormat = "2006.01.02 15:04:05"
 40
 41func NewGitService(configRepo configurationRepository) *GitService {
 42	return &GitService{
 43		configRepo: configRepo,
 44	}
 45}
 46
 47func (g *GitService) ListRepositories() ([]*Repository, error) {
 48	rs := g.configRepo.List()
 49
 50	repos := make([]*Repository, 0, len(rs))
 51	for _, r := range rs {
 52		repo, err := git.OpenRepository(r.Path)
 53		if err != nil {
 54			if errors.Is(err, gogit.ErrRepositoryNotExists) {
 55				slog.Info("Path does not contain a repository", "path", r.Path)
 56				continue
 57			}
 58			return nil, err
 59		}
 60
 61		obj, err := repo.LastCommit()
 62		if err != nil {
 63			slog.Error("Error fetching last commit", "repository", r.Path, "error", err)
 64			continue
 65		}
 66
 67		head, err := repo.Head()
 68		if err != nil {
 69			slog.Error("Error fetching head", "repository", r.Path, "error", err)
 70			continue
 71		}
 72
 73		repos = append(repos, &Repository{
 74			Name:        r.Name,
 75			Description: r.Description,
 76			Public:      r.Public,
 77			LastCommit:  obj,
 78			Ref:         head.Name().Short(),
 79		})
 80	}
 81
 82	return repos, nil
 83}
 84
 85func (g *GitService) ListCommits(name, ref, from string, count int) ([]*git.CommitReference, *object.Commit, error) {
 86	r := g.configRepo.GetByName(name)
 87	if r == nil {
 88		return nil, nil, ErrRepositoryNotFound
 89	}
 90
 91	repo, err := git.OpenRepository(r.Path)
 92	if err != nil {
 93		return nil, nil, err
 94	}
 95
 96	err = repo.SetRef(ref)
 97	if err != nil {
 98		return nil, nil, err
 99	}
100	return repo.Commits(count, from)
101}
102
103func (g *GitService) LastCommit(name, ref string) (*git.CommitReference, error) {
104	r := g.configRepo.GetByName(name)
105	if r == nil {
106		return nil, ErrRepositoryNotFound
107	}
108
109	repo, err := git.OpenRepository(r.Path)
110	if err != nil {
111		return nil, err
112	}
113
114	err = repo.SetRef(ref)
115	if err != nil {
116		return nil, err
117	}
118
119	return repo.LastCommit()
120}
121
122func (g *GitService) WriteTarGZip(w io.Writer, name, ref string, prefix string) error {
123	r := g.configRepo.GetByName(name)
124	if r == nil {
125		return ErrRepositoryNotFound
126	}
127
128	repo, err := git.OpenRepository(r.Path)
129	if err != nil {
130		return err
131	}
132
133	err = repo.SetRef(ref)
134	if err != nil {
135		return err
136	}
137
138	gw := gzip.NewWriter(w)
139	defer gw.Close()
140
141	err = repo.WriteTar(gw, prefix)
142	if err != nil {
143		return err
144	}
145
146	return nil
147}
148
149func (g *GitService) Diff(name, ref string) (string, error) {
150	r := g.configRepo.GetByName(name)
151	if r == nil {
152		return "", ErrRepositoryNotFound
153	}
154
155	repo, err := git.OpenRepository(r.Path)
156	if err != nil {
157		return "", err
158	}
159
160	err = repo.SetRef(ref)
161	if err != nil {
162		return "", err
163	}
164
165	return repo.Diff()
166}
167
168func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
169	r := g.configRepo.GetByName(name)
170	if r == nil {
171		return nil, ErrRepositoryNotFound
172	}
173
174	repo, err := git.OpenRepository(r.Path)
175	if err != nil {
176		return nil, err
177	}
178	err = repo.SetRef(ref)
179	if err != nil {
180		return nil, err
181	}
182
183	return repo.Tree(path)
184}
185
186func (g *GitService) IsBinary(name, ref, path string) (bool, error) {
187	r := g.configRepo.GetByName(name)
188	if r == nil {
189		return false, ErrRepositoryNotFound
190	}
191
192	repo, err := git.OpenRepository(r.Path)
193	if err != nil {
194		return false, err
195	}
196	err = repo.SetRef(ref)
197	if err != nil {
198		return false, err
199	}
200
201	return repo.IsBinary(path)
202}
203
204func (g *GitService) GetFileContent(name, ref, path string) ([]byte, error) {
205	r := g.configRepo.GetByName(name)
206	if r == nil {
207		return nil, ErrRepositoryNotFound
208	}
209
210	repo, err := git.OpenRepository(r.Path)
211	if err != nil {
212		return nil, err
213	}
214	err = repo.SetRef(ref)
215	if err != nil {
216		return nil, err
217	}
218
219	return repo.FileContent(path)
220}
221
222func (g *GitService) GetAbout(name string) ([]byte, error) {
223	r := g.configRepo.GetByName(name)
224	if r == nil {
225		return nil, ErrRepositoryNotFound
226	}
227
228	repo, err := git.OpenRepository(r.Path)
229	if err != nil {
230		return nil, err
231	}
232	err = repo.SetRef("")
233	if err != nil {
234		return nil, err
235	}
236
237	file, err := repo.FileContent(r.About)
238	if err != nil {
239		return nil, err
240	}
241
242	return file, nil
243}
244
245func (g *GitService) GetTag(ref, name string) (*object.Commit, *git.TagReference, error) {
246	r := g.configRepo.GetByName(name)
247	if r == nil {
248		return nil, nil, ErrRepositoryNotFound
249	}
250
251	repo, err := git.OpenRepository(r.Path)
252	if err != nil {
253		return nil, nil, err
254	}
255
256	err = repo.SetRef(ref)
257	if err != nil {
258		return nil, nil, err
259	}
260
261	return repo.Tag()
262}
263
264func (g *GitService) ListTags(name string) ([]*git.TagReference, error) {
265	r := g.configRepo.GetByName(name)
266	if r == nil {
267		return nil, ErrRepositoryNotFound
268	}
269
270	repo, err := git.OpenRepository(r.Path)
271	if err != nil {
272		return nil, err
273	}
274	return repo.Tags()
275}
276
277func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
278	r := g.configRepo.GetByName(name)
279	if r == nil {
280		return nil, ErrRepositoryNotFound
281	}
282
283	repo, err := git.OpenRepository(r.Path)
284	if err != nil {
285		return nil, err
286	}
287	return repo.Branches()
288}
289
290func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
291	r := g.configRepo.GetByName(name)
292	if r == nil {
293		return nil, ErrRepositoryNotFound
294	}
295
296	repo, err := git.OpenRepository(r.Path)
297	if err != nil {
298		return nil, err
299	}
300
301	return repo.Head()
302}
303
304func (g *GitService) WriteInfoRefs(ctx context.Context, name string, w io.Writer) error {
305	r := g.configRepo.GetByName(name)
306	if r == nil {
307		return ErrRepositoryNotFound
308	}
309
310	repo, err := git.OpenRepository(r.Path)
311	if err != nil {
312		return err
313	}
314
315	return repo.WriteInfoRefs(ctx, w)
316}
317
318func (g *GitService) WriteUploadPack(ctx context.Context, name string, re io.Reader, w io.Writer) error {
319	r := g.configRepo.GetByName(name)
320	if r == nil {
321		return ErrRepositoryNotFound
322	}
323
324	repo, err := git.OpenRepository(r.Path)
325	if err != nil {
326		return err
327	}
328
329	return repo.WriteUploadPack(ctx, re, w)
330}