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 "github.com/alexedwards/flow"
13 "github.com/dustin/go-humanize"
14 "icyphox.sh/legit/config"
15 "icyphox.sh/legit/git"
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 path := filepath.Join(d.c.Repo.ScanPath, dir.Name())
39 gr, err := git.Open(path, "")
40 if err != nil {
41 d.Write500(w)
42 log.Printf("opening dir %s: %s", path, err)
43 return
44 }
45
46 c, err := gr.LastCommit()
47 if err != nil {
48 d.Write500(w)
49 log.Println(err)
50 return
51 }
52
53 desc := getDescription(path)
54
55 infos = append(infos, info{
56 Name: dir.Name(),
57 Desc: desc,
58 Idle: humanize.Time(c.Author.When),
59 d: c.Author.When,
60 })
61 }
62
63 sort.Slice(infos, func(i, j int) bool {
64 return infos[j].d.Before(infos[i].d)
65 })
66
67 tpath := filepath.Join(d.c.Dirs.Templates, "*")
68 t := template.Must(template.ParseGlob(tpath))
69
70 data := make(map[string]interface{})
71 data["meta"] = d.c.Meta
72 data["info"] = infos
73
74 if err := t.ExecuteTemplate(w, "index", data); err != nil {
75 log.Println(err)
76 return
77 }
78}
79
80func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) {
81 name := flow.Param(r.Context(), "name")
82 name = filepath.Clean(name)
83 path := filepath.Join(d.c.Repo.ScanPath, name)
84 gr, err := git.Open(path, "")
85 if err != nil {
86 d.Write404(w)
87 return
88 }
89
90 commits, err := gr.Commits()
91 if err != nil {
92 d.Write500(w)
93 log.Println(err)
94 return
95 }
96
97 var readmeContent string
98 for _, readme := range d.c.Repo.Readme {
99 readmeContent, _ = gr.FileContent(readme)
100 if readmeContent != "" {
101 break
102 }
103 }
104
105 if readmeContent == "" {
106 log.Printf("no readme found for %s", name)
107 }
108
109 mainBranch, err := gr.FindMainBranch(d.c.Repo.MainBranch)
110 if err != nil {
111 d.Write500(w)
112 log.Println(err)
113 return
114 }
115
116 tpath := filepath.Join(d.c.Dirs.Templates, "*")
117 t := template.Must(template.ParseGlob(tpath))
118
119 if len(commits) >= 3 {
120 commits = commits[:3]
121 }
122
123 data := make(map[string]any)
124 data["name"] = name
125 data["ref"] = mainBranch
126 data["readme"] = readmeContent
127 data["commits"] = commits
128 data["desc"] = getDescription(path)
129
130 if err := t.ExecuteTemplate(w, "repo", data); err != nil {
131 log.Println(err)
132 return
133 }
134
135 return
136}
137
138func (d *deps) RepoTree(w http.ResponseWriter, r *http.Request) {
139 name := flow.Param(r.Context(), "name")
140 treePath := flow.Param(r.Context(), "...")
141 ref := flow.Param(r.Context(), "ref")
142
143 name = filepath.Clean(name)
144 path := filepath.Join(d.c.Repo.ScanPath, name)
145 gr, err := git.Open(path, ref)
146 if err != nil {
147 d.Write404(w)
148 return
149 }
150
151 files, err := gr.FileTree(treePath)
152 if err != nil {
153 d.Write500(w)
154 log.Println(err)
155 return
156 }
157
158 data := make(map[string]any)
159 data["name"] = name
160 data["ref"] = ref
161 data["parent"] = treePath
162 data["desc"] = getDescription(path)
163
164 d.listFiles(files, data, w)
165 return
166}
167
168func (d *deps) FileContent(w http.ResponseWriter, r *http.Request) {
169 name := flow.Param(r.Context(), "name")
170 treePath := flow.Param(r.Context(), "...")
171 ref := flow.Param(r.Context(), "ref")
172
173 name = filepath.Clean(name)
174 path := filepath.Join(d.c.Repo.ScanPath, name)
175 gr, err := git.Open(path, ref)
176 if err != nil {
177 d.Write404(w)
178 return
179 }
180
181 contents, err := gr.FileContent(treePath)
182 data := make(map[string]any)
183 data["name"] = name
184 data["ref"] = ref
185 data["desc"] = getDescription(path)
186 data["path"] = treePath
187
188 d.showFile(contents, data, w)
189 return
190}
191
192func (d *deps) Log(w http.ResponseWriter, r *http.Request) {
193 name := flow.Param(r.Context(), "name")
194 ref := flow.Param(r.Context(), "ref")
195
196 path := filepath.Join(d.c.Repo.ScanPath, name)
197 gr, err := git.Open(path, ref)
198 if err != nil {
199 d.Write404(w)
200 return
201 }
202
203 commits, err := gr.Commits()
204 if err != nil {
205 d.Write500(w)
206 log.Println(err)
207 return
208 }
209
210 tpath := filepath.Join(d.c.Dirs.Templates, "*")
211 t := template.Must(template.ParseGlob(tpath))
212
213 data := make(map[string]interface{})
214 data["commits"] = commits
215 data["meta"] = d.c.Meta
216 data["name"] = name
217 data["ref"] = ref
218 data["desc"] = getDescription(path)
219
220 if err := t.ExecuteTemplate(w, "log", data); err != nil {
221 log.Println(err)
222 return
223 }
224}
225
226func (d *deps) Diff(w http.ResponseWriter, r *http.Request) {
227 name := flow.Param(r.Context(), "name")
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 := flow.Param(r.Context(), "name")
265
266 path := filepath.Join(d.c.Repo.ScanPath, name)
267 gr, err := git.Open(path, "")
268 if err != nil {
269 d.Write404(w)
270 return
271 }
272
273 tags, err := gr.Tags()
274 if err != nil {
275 // Non-fatal, we *should* have at least one branch to show.
276 log.Println(err)
277 }
278
279 branches, err := gr.Branches()
280 if err != nil {
281 log.Println(err)
282 d.Write500(w)
283 return
284 }
285
286 tpath := filepath.Join(d.c.Dirs.Templates, "*")
287 t := template.Must(template.ParseGlob(tpath))
288
289 data := make(map[string]interface{})
290
291 data["meta"] = d.c.Meta
292 data["name"] = name
293 data["branches"] = branches
294 data["tags"] = tags
295 data["desc"] = getDescription(path)
296
297 if err := t.ExecuteTemplate(w, "refs", data); err != nil {
298 log.Println(err)
299 return
300 }
301}
302
303func (d *deps) ServeStatic(w http.ResponseWriter, r *http.Request) {
304 f := flow.Param(r.Context(), "file")
305 f = filepath.Clean(filepath.Join(d.c.Dirs.Static, f))
306
307 http.ServeFile(w, r, f)
308}
309
310func getDescription(path string) (desc string) {
311 db, err := os.ReadFile(filepath.Join(path, "description"))
312 if err == nil {
313 desc = string(db)
314 } else {
315 desc = ""
316 }
317 return
318}