cerrado @ b4204817527de481bbba5b547ef6d797600be130

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