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