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 },
168 }
169 templates.WritePageTemplate(w, gitList)
170 return nil
171}
172
173func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
174 ext.SetHTML(w)
175 name := r.PathValue("name")
176 ref := r.PathValue("ref")
177 rest := r.PathValue("rest")
178
179 file, err := g.gitService.GetFileContent(name, ref, rest)
180 if err != nil {
181 return err
182 }
183
184 filename := filepath.Base(rest)
185 lexer := GetLexers(filename)
186 style := styles.Get("xcode")
187 formatter := html.New(
188 html.WithLineNumbers(true),
189 )
190 iterator, err := lexer.Tokenise(nil, file)
191 if err != nil {
192 return err
193 }
194
195 var code bytes.Buffer
196 err = formatter.Format(&code, style, iterator)
197 if err != nil {
198 return err
199 }
200
201 gitList := &templates.GitItemPage{
202 Name: name,
203 Ref: ref,
204 GitItemBase: &templates.GitItemBlobPage{
205 File: rest,
206 Content: code.Bytes(),
207 },
208 }
209 templates.WritePageTemplate(w, gitList)
210 return nil
211}
212
213func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error {
214 ext.SetHTML(w)
215 name := r.PathValue("name")
216 ref := r.PathValue("ref")
217
218 commits, err := g.gitService.ListCommits(name, ref)
219 if err != nil {
220 return err
221 }
222
223 gitList := &templates.GitItemPage{
224 Name: name,
225 Ref: ref,
226 GitItemBase: &templates.GitItemLogPage{
227 Commits: commits,
228 },
229 }
230 templates.WritePageTemplate(w, gitList)
231 return nil
232}
233
234func GetLexers(filename string) chroma.Lexer {
235 if filename == "APKBUILD" {
236 return lexers.Get("sh")
237 }
238
239 lexer := lexers.Get(filename)
240
241 if lexer == nil {
242 lexer = lexers.Get("txt")
243 }
244 return lexer
245}