1package git
2
3import (
4 "bytes"
5 "io"
6 "net/http"
7 "os"
8 "path/filepath"
9
10 "git.gabrielgio.me/cerrado/pkg/ext"
11 "git.gabrielgio.me/cerrado/pkg/service"
12 "git.gabrielgio.me/cerrado/templates"
13 "github.com/alecthomas/chroma/v2"
14 "github.com/alecthomas/chroma/v2/formatters/html"
15 "github.com/alecthomas/chroma/v2/lexers"
16 "github.com/alecthomas/chroma/v2/styles"
17 "github.com/go-git/go-git/v5/plumbing"
18 "github.com/go-git/go-git/v5/plumbing/object"
19 "github.com/gomarkdown/markdown"
20 markdownhtml "github.com/gomarkdown/markdown/html"
21 "github.com/gomarkdown/markdown/parser"
22)
23
24type (
25 GitHandler struct {
26 gitService gitService
27 readmePath string
28 }
29
30 gitService interface {
31 ListRepositories() ([]*service.Repository, error)
32 ListCommits(name string, ref string, count int) ([]*object.Commit, error)
33 GetHead(name string) (*plumbing.Reference, error)
34 GetTree(name, ref, path string) (*object.Tree, error)
35 GetFileContent(name, ref, path string) (string, error)
36 GetAbout(name string) (string, error)
37 ListTags(name string) ([]*plumbing.Reference, error)
38 ListBranches(name string) ([]*plumbing.Reference, error)
39 }
40
41 configurationRepository interface {
42 GetRootReadme() string
43 }
44)
45
46func NewGitHandler(gitService gitService, confRepo configurationRepository) *GitHandler {
47 return &GitHandler{
48 gitService: gitService,
49 readmePath: confRepo.GetRootReadme(),
50 }
51}
52
53func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) error {
54 repos, err := g.gitService.ListRepositories()
55 if err != nil {
56 return err
57 }
58
59 f, err := os.Open(g.readmePath)
60 if err != nil {
61 return err
62 }
63
64 bs, err := io.ReadAll(f)
65 if err != nil {
66 return err
67 }
68
69 extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
70 p := parser.NewWithExtensions(extensions)
71 doc := p.Parse(bs)
72
73 htmlFlag := markdownhtml.CommonFlags | markdownhtml.HrefTargetBlank
74 opts := markdownhtml.RendererOptions{Flags: htmlFlag}
75 renderer := markdownhtml.NewRenderer(opts)
76
77 bs = markdown.Render(doc, renderer)
78
79 gitList := &templates.GitListPage{
80 Respositories: repos,
81 About: bs,
82 }
83 templates.WritePageTemplate(w, gitList)
84 return nil
85}
86
87func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error {
88 ext.SetHTML(w)
89 name := r.PathValue("name")
90 ref, err := g.gitService.GetHead(name)
91 if err != nil {
92 return err
93 }
94
95 tags, err := g.gitService.ListTags(name)
96 if err != nil {
97 return err
98 }
99
100 branches, err := g.gitService.ListBranches(name)
101 if err != nil {
102 return err
103 }
104
105 commits, err := g.gitService.ListCommits(name, "", 10)
106 if err != nil {
107 return err
108 }
109
110 gitList := &templates.GitItemPage{
111 Name: name,
112 Ref: ref.Name().Short(),
113 GitItemBase: &templates.GitItemSummaryPage{
114 Tags: tags,
115 Branches: branches,
116 Commits: commits,
117 },
118 }
119 templates.WritePageTemplate(w, gitList)
120 return nil
121}
122
123func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error {
124 ext.SetHTML(w)
125 name := r.PathValue("name")
126 ref, err := g.gitService.GetHead(name)
127 if err != nil {
128 return err
129 }
130
131 file, err := g.gitService.GetAbout(name)
132 if err != nil {
133 return err
134 }
135
136 extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
137 p := parser.NewWithExtensions(extensions)
138 doc := p.Parse([]byte(file))
139
140 htmlFlag := markdownhtml.CommonFlags | markdownhtml.HrefTargetBlank
141 opts := markdownhtml.RendererOptions{Flags: htmlFlag}
142 renderer := markdownhtml.NewRenderer(opts)
143
144 bs := markdown.Render(doc, renderer)
145
146 gitList := &templates.GitItemPage{
147 Name: name,
148 Ref: ref.Name().Short(),
149 GitItemBase: &templates.GitItemAboutPage{
150 About: bs,
151 },
152 }
153 templates.WritePageTemplate(w, gitList)
154 return nil
155}
156
157func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error {
158 ext.SetHTML(w)
159 name := r.PathValue("name")
160
161 tags, err := g.gitService.ListTags(name)
162 if err != nil {
163 return err
164 }
165
166 branches, err := g.gitService.ListBranches(name)
167 if err != nil {
168 return err
169 }
170
171 ref, err := g.gitService.GetHead(name)
172 if err != nil {
173 return err
174 }
175
176 gitList := &templates.GitItemPage{
177 Name: name,
178 Ref: ref.Name().Short(),
179 GitItemBase: &templates.GitItemRefsPage{
180 Tags: tags,
181 Branches: branches,
182 },
183 }
184 templates.WritePageTemplate(w, gitList)
185 return nil
186}
187
188func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error {
189 ext.SetHTML(w)
190 name := r.PathValue("name")
191 ref := r.PathValue("ref")
192 rest := r.PathValue("rest")
193
194 tree, err := g.gitService.GetTree(name, ref, rest)
195 if err != nil {
196 return err
197 }
198
199 gitList := &templates.GitItemPage{
200 Name: name,
201 Ref: ref,
202 GitItemBase: &templates.GitItemTreePage{
203 CurrentPath: rest,
204 Tree: tree,
205 },
206 }
207 templates.WritePageTemplate(w, gitList)
208 return nil
209}
210
211func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
212 ext.SetHTML(w)
213 name := r.PathValue("name")
214 ref := r.PathValue("ref")
215 rest := r.PathValue("rest")
216
217 file, err := g.gitService.GetFileContent(name, ref, rest)
218 if err != nil {
219 return err
220 }
221
222 filename := filepath.Base(rest)
223 lexer := GetLexers(filename)
224 style := styles.Get("xcode")
225 formatter := html.New(
226 html.WithLineNumbers(true),
227 )
228 iterator, err := lexer.Tokenise(nil, file)
229 if err != nil {
230 return err
231 }
232
233 var code bytes.Buffer
234 err = formatter.Format(&code, style, iterator)
235 if err != nil {
236 return err
237 }
238
239 gitList := &templates.GitItemPage{
240 Name: name,
241 Ref: ref,
242 GitItemBase: &templates.GitItemBlobPage{
243 File: rest,
244 Content: code.Bytes(),
245 },
246 }
247 templates.WritePageTemplate(w, gitList)
248 return nil
249}
250
251func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error {
252 ext.SetHTML(w)
253 name := r.PathValue("name")
254 ref := r.PathValue("ref")
255
256 commits, err := g.gitService.ListCommits(name, ref, 1000)
257 if err != nil {
258 return err
259 }
260
261 gitList := &templates.GitItemPage{
262 Name: name,
263 Ref: ref,
264 GitItemBase: &templates.GitItemLogPage{
265 Commits: commits,
266 },
267 }
268 templates.WritePageTemplate(w, gitList)
269 return nil
270}
271
272func GetLexers(filename string) chroma.Lexer {
273 if filename == "APKBUILD" {
274 return lexers.Get("sh")
275 }
276
277 lexer := lexers.Get(filename)
278
279 if lexer == nil {
280 lexer = lexers.Get("txt")
281 }
282 return lexer
283}