1package service
2
3import (
4 "errors"
5 "log/slog"
6 "os"
7 "path"
8
9 "git.gabrielgio.me/cerrado/pkg/config"
10 "git.gabrielgio.me/cerrado/pkg/git"
11 "git.gabrielgio.me/cerrado/pkg/u"
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 Title string
20 Description string
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 (
36 RepositoryNotFoundErr = errors.New("Repository not found")
37)
38
39// TODO: make it configurable
40const timeFormat = "2006.01.02 15:04:05"
41
42func NewGitService(configRepo configurationRepository) *GitService {
43 return &GitService{
44 configRepo: configRepo,
45 }
46}
47
48func (g *GitService) ListRepositories() ([]*Repository, error) {
49 rs := g.configRepo.List()
50
51 repos := make([]*Repository, len(rs))
52 for i, r := range rs {
53 repo, err := git.OpenRepository(r.Path)
54 if err != nil {
55 return nil, err
56 }
57
58 obj, err := repo.LastCommit()
59 if err != nil {
60 return nil, err
61 }
62
63 head, err := repo.Head()
64 if err != nil {
65 return nil, err
66 }
67
68 d := path.Join(r.Path, "description")
69 description := ""
70 if u.FileExist(d) {
71 if b, err := os.ReadFile(d); err == nil {
72 description = string(b)
73 } else {
74 slog.Error("Error loading description file", "err", err)
75 }
76 }
77
78 baseName := path.Base(r.Path)
79 repos[i] = &Repository{
80 Name: baseName,
81 Title: baseName,
82 Description: description,
83 LastCommitDate: obj.Author.When.Format(timeFormat),
84 Ref: head.Name().Short(),
85 }
86 }
87
88 return repos, nil
89}
90
91func (g *GitService) ListCommits(name, ref string) ([]*object.Commit, error) {
92 r := g.configRepo.GetByName(name)
93 if r == nil {
94 return nil, RepositoryNotFoundErr
95 }
96
97 repo, err := git.OpenRepository(r.Path)
98 if err != nil {
99 return nil, err
100 }
101
102 err = repo.SetRef(ref)
103 if err != nil {
104 return nil, err
105 }
106 return repo.Commits()
107}
108
109func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
110 r := g.configRepo.GetByName(name)
111 if r == nil {
112 return nil, RepositoryNotFoundErr
113 }
114
115 repo, err := git.OpenRepository(r.Path)
116 if err != nil {
117 return nil, err
118 }
119 err = repo.SetRef(ref)
120 if err != nil {
121 return nil, err
122 }
123
124 return repo.Tree(path)
125}
126
127func (g *GitService) GetFileContent(name, ref, path string) (string, error) {
128 r := g.configRepo.GetByName(name)
129 if r == nil {
130 return "", RepositoryNotFoundErr
131 }
132
133 repo, err := git.OpenRepository(r.Path)
134 if err != nil {
135 return "", err
136 }
137 err = repo.SetRef(ref)
138 if err != nil {
139 return "", err
140 }
141
142 return repo.FileContent(path)
143}
144
145func (g *GitService) ListTags(name string) ([]*object.Tag, error) {
146 r := g.configRepo.GetByName(name)
147 if r == nil {
148 return nil, RepositoryNotFoundErr
149 }
150
151 repo, err := git.OpenRepository(r.Path)
152 if err != nil {
153 return nil, err
154 }
155 return repo.Tags()
156}
157
158func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
159 r := g.configRepo.GetByName(name)
160 if r == nil {
161 return nil, RepositoryNotFoundErr
162 }
163
164 repo, err := git.OpenRepository(r.Path)
165 if err != nil {
166 return nil, err
167 }
168 return repo.Branches()
169}
170
171func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
172 r := g.configRepo.GetByName(name)
173 if r == nil {
174 return nil, RepositoryNotFoundErr
175 }
176
177 repo, err := git.OpenRepository(r.Path)
178 if err != nil {
179 return nil, err
180 }
181
182 return repo.Head()
183}