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 "github.com/go-git/go-git/v5/plumbing"
12 "github.com/go-git/go-git/v5/plumbing/object"
13)
14
15type (
16 Repository struct {
17 Name string
18 Description string
19 LastCommitDate string
20 Ref string
21 }
22
23 GitService struct {
24 configRepo configurationRepository
25 }
26
27 configurationRepository interface {
28 List() []*config.GitRepositoryConfiguration
29 GetByName(name string) *config.GitRepositoryConfiguration
30 }
31)
32
33var (
34 RepositoryNotFoundErr = errors.New("Repository not found")
35)
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 return nil, err
54 }
55
56 obj, err := repo.LastCommit()
57 if err != nil {
58 slog.Error("Error fetching last commit", "repository", r.Path, "error", err)
59 continue
60 }
61
62 head, err := repo.Head()
63 if err != nil {
64 slog.Error("Error fetching head", "repository", r.Path, "error", err)
65 continue
66 }
67
68 repos = append(repos, &Repository{
69 Name: r.Name,
70 Description: r.Description,
71 LastCommitDate: obj.Author.When.Format(timeFormat),
72 Ref: head.Name().Short(),
73 })
74 }
75
76 return repos, nil
77}
78
79func (g *GitService) ListCommits(name, ref string, count int) ([]*object.Commit, error) {
80 r := g.configRepo.GetByName(name)
81 if r == nil {
82 return nil, RepositoryNotFoundErr
83 }
84
85 repo, err := git.OpenRepository(r.Path)
86 if err != nil {
87 return nil, err
88 }
89
90 err = repo.SetRef(ref)
91 if err != nil {
92 return nil, err
93 }
94 return repo.Commits(count)
95}
96
97func (g *GitService) WriteTarGZip(w io.Writer, name, ref string, filename string) error {
98 r := g.configRepo.GetByName(name)
99 if r == nil {
100 return RepositoryNotFoundErr
101 }
102
103 repo, err := git.OpenRepository(r.Path)
104 if err != nil {
105 return err
106 }
107
108 err = repo.SetRef(ref)
109 if err != nil {
110 return err
111 }
112
113 gw := gzip.NewWriter(w)
114 defer gw.Close()
115
116 return repo.WriteTar(gw, filename)
117
118}
119
120func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
121 r := g.configRepo.GetByName(name)
122 if r == nil {
123 return nil, RepositoryNotFoundErr
124 }
125
126 repo, err := git.OpenRepository(r.Path)
127 if err != nil {
128 return nil, err
129 }
130 err = repo.SetRef(ref)
131 if err != nil {
132 return nil, err
133 }
134
135 return repo.Tree(path)
136}
137
138func (g *GitService) GetFileContent(name, ref, path string) (string, error) {
139 r := g.configRepo.GetByName(name)
140 if r == nil {
141 return "", RepositoryNotFoundErr
142 }
143
144 repo, err := git.OpenRepository(r.Path)
145 if err != nil {
146 return "", err
147 }
148 err = repo.SetRef(ref)
149 if err != nil {
150 return "", err
151 }
152
153 return repo.FileContent(path)
154}
155
156func (g *GitService) GetAbout(name string) (string, error) {
157 r := g.configRepo.GetByName(name)
158 if r == nil {
159 return "", RepositoryNotFoundErr
160 }
161
162 repo, err := git.OpenRepository(r.Path)
163 if err != nil {
164 return "", err
165 }
166 err = repo.SetRef("")
167 if err != nil {
168 return "", err
169 }
170
171 return repo.FileContent(r.About)
172}
173
174func (g *GitService) ListTags(name string) ([]*plumbing.Reference, error) {
175 r := g.configRepo.GetByName(name)
176 if r == nil {
177 return nil, RepositoryNotFoundErr
178 }
179
180 repo, err := git.OpenRepository(r.Path)
181 if err != nil {
182 return nil, err
183 }
184 return repo.Tags()
185}
186
187func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
188 r := g.configRepo.GetByName(name)
189 if r == nil {
190 return nil, RepositoryNotFoundErr
191 }
192
193 repo, err := git.OpenRepository(r.Path)
194 if err != nil {
195 return nil, err
196 }
197 return repo.Branches()
198}
199
200func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
201 r := g.configRepo.GetByName(name)
202 if r == nil {
203 return nil, RepositoryNotFoundErr
204 }
205
206 repo, err := git.OpenRepository(r.Path)
207 if err != nil {
208 return nil, err
209 }
210
211 return repo.Head()
212}