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