1package git
2
3import (
4 "bytes"
5 "log/slog"
6 "net/http"
7 "path/filepath"
8
9 "git.gabrielgio.me/cerrado/pkg/ext"
10 "git.gabrielgio.me/cerrado/pkg/service"
11 "git.gabrielgio.me/cerrado/templates"
12 "github.com/alecthomas/chroma/v2"
13 "github.com/alecthomas/chroma/v2/formatters/html"
14 "github.com/alecthomas/chroma/v2/lexers"
15 "github.com/alecthomas/chroma/v2/styles"
16 "github.com/go-git/go-git/v5/plumbing"
17 "github.com/go-git/go-git/v5/plumbing/object"
18)
19
20type (
21 GitHandler struct {
22 gitService gitService
23 }
24
25 gitService interface {
26 ListRepositories() ([]*service.Repository, error)
27 ListCommits(name string, ref string) ([]*object.Commit, error)
28 GetHead(name string) (*plumbing.Reference, error)
29 GetTree(name, ref, path string) (*object.Tree, error)
30 GetFileContent(name, ref, path string) (string, error)
31 ListTags(name string) ([]*object.Tag, error)
32 ListBranches(name string) ([]*plumbing.Reference, error)
33 }
34)
35
36func NewGitHandler(gitService gitService) *GitHandler {
37 return &GitHandler{
38 gitService: gitService,
39 }
40}
41
42func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) {
43 repos, err := g.gitService.ListRepositories()
44 if err != nil {
45 slog.Error("Error listing repo", "error", err)
46 return
47 }
48
49 gitList := &templates.GitListPage{repos}
50 templates.WritePageTemplate(w, gitList)
51}
52
53func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) {
54 ext.SetHTML(w)
55 name := r.PathValue("name")
56 ref, err := g.gitService.GetHead(name)
57 if err != nil {
58 slog.Error("Error loading head", "error", err)
59 return
60 }
61
62 gitList := &templates.GitItemPage{
63 Name: name,
64 Ref: ref.Name().Short(),
65 GitItemBase: &templates.GitItemSummaryPage{},
66 }
67 templates.WritePageTemplate(w, gitList)
68}
69
70func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) {
71 ext.SetHTML(w)
72 name := r.PathValue("name")
73 ref, err := g.gitService.GetHead(name)
74 if err != nil {
75 slog.Error("Error loading head", "error", err)
76 return
77 }
78 gitList := &templates.GitItemPage{
79 Name: name,
80 Ref: ref.Name().Short(),
81 GitItemBase: &templates.GitItemAboutPage{},
82 }
83 templates.WritePageTemplate(w, gitList)
84}
85
86func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) {
87 ext.SetHTML(w)
88 name := r.PathValue("name")
89
90 tags, err := g.gitService.ListTags(name)
91 if err != nil {
92 slog.Error("Error loading tags", "error", err)
93 return
94 }
95
96 branches, err := g.gitService.ListBranches(name)
97 if err != nil {
98 slog.Error("Error loading branches", "error", err)
99 return
100 }
101
102 ref, err := g.gitService.GetHead(name)
103 if err != nil {
104 slog.Error("Error loading head", "error", err)
105 return
106 }
107
108 gitList := &templates.GitItemPage{
109 Name: name,
110 Ref: ref.Name().Short(),
111 GitItemBase: &templates.GitItemRefsPage{
112 Tags: tags,
113 Branches: branches,
114 },
115 }
116 templates.WritePageTemplate(w, gitList)
117}
118
119func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) {
120 ext.SetHTML(w)
121 name := r.PathValue("name")
122 ref := r.PathValue("ref")
123 rest := r.PathValue("rest")
124
125 tree, err := g.gitService.GetTree(name, ref, rest)
126 if err != nil {
127 slog.Error("Error loading tree", "error", err)
128 return
129 }
130
131 gitList := &templates.GitItemPage{
132 Name: name,
133 Ref: ref,
134 GitItemBase: &templates.GitItemTreePage{
135 CurrentPath: rest,
136 Tree: tree,
137 Ref: ref,
138 Name: name,
139 },
140 }
141 templates.WritePageTemplate(w, gitList)
142}
143
144func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) {
145 ext.SetHTML(w)
146 name := r.PathValue("name")
147 ref := r.PathValue("ref")
148 rest := r.PathValue("rest")
149
150 file, err := g.gitService.GetFileContent(name, ref, rest)
151 if err != nil {
152 slog.Error("Error loading blob", "error", err)
153 return
154 }
155
156 filename := filepath.Base(rest)
157 lexer := GetLexers(filename)
158 style := styles.Get("xcode")
159 formatter := html.New(
160 html.WithLineNumbers(true),
161 )
162 iterator, err := lexer.Tokenise(nil, file)
163 if err != nil {
164 slog.Error("Error tokenise", "error", err)
165 return
166 }
167
168 var code bytes.Buffer
169 err = formatter.Format(&code, style, iterator)
170 if err != nil {
171 slog.Error("Error format", "error", err)
172 return
173 }
174
175 gitList := &templates.GitItemPage{
176 Name: name,
177 Ref: ref,
178 GitItemBase: &templates.GitItemBlobPage{
179 File: rest,
180 Content: code.Bytes(),
181 },
182 }
183 templates.WritePageTemplate(w, gitList)
184}
185
186func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) {
187 ext.SetHTML(w)
188 name := r.PathValue("name")
189 ref := r.PathValue("ref")
190
191 commits, err := g.gitService.ListCommits(name, ref)
192 if err != nil {
193 slog.Error("Error loading commits", "error", err)
194 return
195 }
196
197 gitList := &templates.GitItemPage{
198 Name: name,
199 Ref: ref,
200 GitItemBase: &templates.GitItemLogPage{
201 Commits: commits,
202 },
203 }
204 templates.WritePageTemplate(w, gitList)
205}
206
207func GetLexers(filename string) chroma.Lexer {
208 if filename == "APKBUILD" {
209 return lexers.Get("sh")
210 }
211
212 lexer := lexers.Get(filename)
213
214 if lexer == nil {
215 lexer = lexers.Get("txt")
216 }
217 return lexer
218}