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