routes/routes.go (view raw)
1package routes
2
3import (
4 "fmt"
5 "html/template"
6 "log"
7 "net/http"
8 "path/filepath"
9
10 "git.icyphox.sh/legit/config"
11 "git.icyphox.sh/legit/git"
12 "github.com/alexedwards/flow"
13 "github.com/microcosm-cc/bluemonday"
14 "github.com/russross/blackfriday/v2"
15)
16
17type deps struct {
18 c *config.Config
19}
20
21func (d *deps) Index(w http.ResponseWriter, r *http.Request) {
22 repos, err := d.getAllRepos()
23 if err != nil {
24 d.Write500(w)
25 log.Printf("reading scan path: %s", err)
26 return
27 }
28
29 tpath := filepath.Join(d.c.Dirs.Templates, "*")
30 t := template.Must(template.ParseGlob(tpath))
31
32 data := make(map[string]interface{})
33 data["meta"] = d.c.Meta
34 data["info"] = repos.Children
35
36 if err := t.ExecuteTemplate(w, "index", data); err != nil {
37 log.Println(err)
38 return
39 }
40}
41
42func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) {
43 name := repoPath(r.Context())
44 if d.isIgnored(name) {
45 d.Write404(w)
46 return
47 }
48
49 path := filepath.Join(d.c.Repo.ScanPath, name)
50
51 gr, err := git.Open(path, "")
52 if err != nil {
53 d.Write404(w)
54 return
55 }
56
57 commits, err := gr.Commits()
58 if err != nil {
59 d.Write500(w)
60 log.Println(err)
61 return
62 }
63
64 var readmeContent template.HTML
65 for _, readme := range d.c.Repo.Readme {
66 ext := filepath.Ext(readme)
67 content, _ := gr.FileContent(readme)
68 if len(content) > 0 {
69 switch ext {
70 case ".md", ".mkd", ".markdown":
71 unsafe := blackfriday.Run(
72 []byte(content),
73 blackfriday.WithExtensions(blackfriday.CommonExtensions),
74 )
75 html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
76 readmeContent = template.HTML(html)
77 default:
78 readmeContent = template.HTML(
79 fmt.Sprintf(`<pre>%s</pre>`, content),
80 )
81 }
82 break
83 }
84 }
85
86 if readmeContent == "" {
87 log.Printf("no readme found for %s", name)
88 }
89
90 mainBranch, err := gr.FindMainBranch(d.c.Repo.MainBranch)
91 if err != nil {
92 d.Write500(w)
93 log.Println(err)
94 return
95 }
96
97 tpath := filepath.Join(d.c.Dirs.Templates, "*")
98 t := template.Must(template.ParseGlob(tpath))
99
100 if len(commits) >= 3 {
101 commits = commits[:3]
102 }
103
104 data := make(map[string]any)
105 data["name"] = name
106 data["ref"] = mainBranch
107 data["readme"] = readmeContent
108 data["commits"] = commits
109 data["desc"] = getDescription(path)
110 data["servername"] = d.c.Server.Name
111 data["gomod"] = isGoModule(gr)
112
113 if err := t.ExecuteTemplate(w, "repo", data); err != nil {
114 log.Println(err)
115 return
116 }
117}
118
119func (d *deps) RepoTree(w http.ResponseWriter, r *http.Request) {
120 name := repoPath(r.Context())
121 if d.isIgnored(name) {
122 d.Write404(w)
123 return
124 }
125
126 treePath := flow.Param(r.Context(), "...")
127 ref := flow.Param(r.Context(), "ref")
128
129 path := filepath.Join(d.c.Repo.ScanPath, name)
130 gr, err := git.Open(path, ref)
131 if err != nil {
132 d.Write404(w)
133 return
134 }
135
136 files, err := gr.FileTree(treePath)
137 if err != nil {
138 d.Write500(w)
139 log.Println(err)
140 return
141 }
142
143 data := make(map[string]any)
144 data["name"] = name
145 data["ref"] = ref
146 data["parent"] = treePath
147 data["desc"] = getDescription(path)
148
149 d.listFiles(files, data, w)
150}
151
152func (d *deps) FileContent(w http.ResponseWriter, r *http.Request) {
153 name := repoPath(r.Context())
154 if d.isIgnored(name) {
155 d.Write404(w)
156 return
157 }
158 treePath := flow.Param(r.Context(), "...")
159 ref := flow.Param(r.Context(), "ref")
160
161 path := filepath.Join(d.c.Repo.ScanPath, name)
162 gr, err := git.Open(path, ref)
163 if err != nil {
164 d.Write404(w)
165 return
166 }
167
168 contents, err := gr.FileContent(treePath)
169 if err != nil {
170 d.Write500(w)
171 log.Println(err)
172 return
173 }
174 data := make(map[string]any)
175 data["name"] = name
176 data["ref"] = ref
177 data["desc"] = getDescription(path)
178 data["path"] = treePath
179
180 d.showFile(contents, data, w)
181}
182
183func (d *deps) Log(w http.ResponseWriter, r *http.Request) {
184 name := repoPath(r.Context())
185 if d.isIgnored(name) {
186 d.Write404(w)
187 return
188 }
189 ref := flow.Param(r.Context(), "ref")
190
191 path := filepath.Join(d.c.Repo.ScanPath, name)
192 gr, err := git.Open(path, ref)
193 if err != nil {
194 d.Write404(w)
195 return
196 }
197
198 commits, err := gr.Commits()
199 if err != nil {
200 d.Write500(w)
201 log.Println(err)
202 return
203 }
204
205 tpath := filepath.Join(d.c.Dirs.Templates, "*")
206 t := template.Must(template.ParseGlob(tpath))
207
208 data := make(map[string]interface{})
209 data["commits"] = commits
210 data["meta"] = d.c.Meta
211 data["name"] = name
212 data["ref"] = ref
213 data["desc"] = getDescription(path)
214 data["dotdot"] = filepath.Dir(path)
215
216 if err := t.ExecuteTemplate(w, "log", data); err != nil {
217 log.Println(err)
218 return
219 }
220}
221
222func (d *deps) Diff(w http.ResponseWriter, r *http.Request) {
223 name := repoPath(r.Context())
224 if d.isIgnored(name) {
225 d.Write404(w)
226 return
227 }
228 ref := flow.Param(r.Context(), "ref")
229
230 path := filepath.Join(d.c.Repo.ScanPath, name)
231 gr, err := git.Open(path, ref)
232 if err != nil {
233 d.Write404(w)
234 return
235 }
236
237 diff, err := gr.Diff()
238 if err != nil {
239 d.Write500(w)
240 log.Println(err)
241 return
242 }
243
244 tpath := filepath.Join(d.c.Dirs.Templates, "*")
245 t := template.Must(template.ParseGlob(tpath))
246
247 data := make(map[string]interface{})
248
249 data["commit"] = diff.Commit
250 data["stat"] = diff.Stat
251 data["diff"] = diff.Diff
252 data["meta"] = d.c.Meta
253 data["name"] = name
254 data["ref"] = ref
255 data["desc"] = getDescription(path)
256
257 if err := t.ExecuteTemplate(w, "commit", data); err != nil {
258 log.Println(err)
259 return
260 }
261}
262
263func (d *deps) Refs(w http.ResponseWriter, r *http.Request) {
264 name := repoPath(r.Context())
265 if d.isIgnored(name) {
266 d.Write404(w)
267 return
268 }
269
270 path := filepath.Join(d.c.Repo.ScanPath, name)
271 gr, err := git.Open(path, "")
272 if err != nil {
273 d.Write404(w)
274 return
275 }
276
277 tags, err := gr.Tags()
278 if err != nil {
279 // Non-fatal, we *should* have at least one branch to show.
280 log.Println(err)
281 }
282
283 branches, err := gr.Branches()
284 if err != nil {
285 d.Write500(w)
286 log.Println(err)
287 return
288 }
289
290 tpath := filepath.Join(d.c.Dirs.Templates, "*")
291 t := template.Must(template.ParseGlob(tpath))
292
293 data := make(map[string]interface{})
294
295 data["meta"] = d.c.Meta
296 data["name"] = name
297 data["branches"] = branches
298 data["tags"] = tags
299 data["desc"] = getDescription(path)
300
301 if err := t.ExecuteTemplate(w, "refs", data); err != nil {
302 log.Println(err)
303 return
304 }
305}
306
307func (d *deps) ServeStatic(w http.ResponseWriter, r *http.Request) {
308 f := flow.Param(r.Context(), "file")
309 f = filepath.Clean(filepath.Join(d.c.Dirs.Static, f))
310
311 http.ServeFile(w, r, f)
312}