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