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) ([]*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 ListTags(name string) ([]*object.Tag, error)
37 ListBranches(name string) ([]*plumbing.Reference, error)
38 }
39
40 configurationRepository interface {
41 GetRootReadme() string
42 }
43)
44
45func NewGitHandler(gitService gitService, confRepo configurationRepository) *GitHandler {
46 return &GitHandler{
47 gitService: gitService,
48 readmePath: confRepo.GetRootReadme(),
49 }
50}
51
52func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) error {
53 repos, err := g.gitService.ListRepositories()
54 if err != nil {
55 return err
56 }
57
58 f, err := os.Open(g.readmePath)
59 if err != nil {
60 return err
61 }
62
63 bs, err := io.ReadAll(f)
64 if err != nil {
65 return err
66 }
67
68 extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
69 p := parser.NewWithExtensions(extensions)
70 doc := p.Parse(bs)
71
72 htmlFlag := markdownhtml.CommonFlags | markdownhtml.HrefTargetBlank
73 opts := markdownhtml.RendererOptions{Flags: htmlFlag}
74 renderer := markdownhtml.NewRenderer(opts)
75
76 bs = markdown.Render(doc, renderer)
77
78 gitList := &templates.GitListPage{
79 Respositories: repos,
80 About: bs,
81 }
82 templates.WritePageTemplate(w, gitList)
83 return nil
84}
85
86func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error {
87 ext.SetHTML(w)
88 name := r.PathValue("name")
89 ref, err := g.gitService.GetHead(name)
90 if err != nil {
91 return err
92 }
93
94 gitList := &templates.GitItemPage{
95 Name: name,
96 Ref: ref.Name().Short(),
97 GitItemBase: &templates.GitItemSummaryPage{},
98 }
99 templates.WritePageTemplate(w, gitList)
100 return nil
101}
102
103func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error {
104 ext.SetHTML(w)
105 name := r.PathValue("name")
106 ref, err := g.gitService.GetHead(name)
107 if err != nil {
108 return err
109 }
110 gitList := &templates.GitItemPage{
111 Name: name,
112 Ref: ref.Name().Short(),
113 GitItemBase: &templates.GitItemAboutPage{},
114 }
115 templates.WritePageTemplate(w, gitList)
116 return nil
117}
118
119func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error {
120 ext.SetHTML(w)
121 name := r.PathValue("name")
122
123 tags, err := g.gitService.ListTags(name)
124 if err != nil {
125 return err
126 }
127
128 branches, err := g.gitService.ListBranches(name)
129 if err != nil {
130 return err
131 }
132
133 ref, err := g.gitService.GetHead(name)
134 if err != nil {
135 return err
136 }
137
138 gitList := &templates.GitItemPage{
139 Name: name,
140 Ref: ref.Name().Short(),
141 GitItemBase: &templates.GitItemRefsPage{
142 Tags: tags,
143 Branches: branches,
144 },
145 }
146 templates.WritePageTemplate(w, gitList)
147 return nil
148}
149
150func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error {
151 ext.SetHTML(w)
152 name := r.PathValue("name")
153 ref := r.PathValue("ref")
154 rest := r.PathValue("rest")
155
156 tree, err := g.gitService.GetTree(name, ref, rest)
157 if err != nil {
158 return err
159 }
160
161 gitList := &templates.GitItemPage{
162 Name: name,
163 Ref: ref,
164 GitItemBase: &templates.GitItemTreePage{
165 CurrentPath: rest,
166 Tree: tree,
167 Ref: ref,
168 Name: name,
169 },
170 }
171 templates.WritePageTemplate(w, gitList)
172 return nil
173}
174
175func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
176 ext.SetHTML(w)
177 name := r.PathValue("name")
178 ref := r.PathValue("ref")
179 rest := r.PathValue("rest")
180
181 file, err := g.gitService.GetFileContent(name, ref, rest)
182 if err != nil {
183 return err
184 }
185
186 filename := filepath.Base(rest)
187 lexer := GetLexers(filename)
188 style := styles.Get("xcode")
189 formatter := html.New(
190 html.WithLineNumbers(true),
191 )
192 iterator, err := lexer.Tokenise(nil, file)
193 if err != nil {
194 return err
195 }
196
197 var code bytes.Buffer
198 err = formatter.Format(&code, style, iterator)
199 if err != nil {
200 return err
201 }
202
203 gitList := &templates.GitItemPage{
204 Name: name,
205 Ref: ref,
206 GitItemBase: &templates.GitItemBlobPage{
207 File: rest,
208 Content: code.Bytes(),
209 },
210 }
211 templates.WritePageTemplate(w, gitList)
212 return nil
213}
214
215func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error {
216 ext.SetHTML(w)
217 name := r.PathValue("name")
218 ref := r.PathValue("ref")
219
220 commits, err := g.gitService.ListCommits(name, ref)
221 if err != nil {
222 return err
223 }
224
225 gitList := &templates.GitItemPage{
226 Name: name,
227 Ref: ref,
228 GitItemBase: &templates.GitItemLogPage{
229 Commits: commits,
230 },
231 }
232 templates.WritePageTemplate(w, gitList)
233 return nil
234}
235
236func GetLexers(filename string) chroma.Lexer {
237 if filename == "APKBUILD" {
238 return lexers.Get("sh")
239 }
240
241 lexer := lexers.Get(filename)
242
243 if lexer == nil {
244 lexer = lexers.Get("txt")
245 }
246 return lexer
247}