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) >= 5 {
110 commits = commits[:5]
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
153 d.listFiles(files, data, w)
154 return
155}
156
157func (d *deps) FileContent(w http.ResponseWriter, r *http.Request) {
158 name := flow.Param(r.Context(), "name")
159 treePath := flow.Param(r.Context(), "...")
160 ref := flow.Param(r.Context(), "ref")
161
162 name = filepath.Clean(name)
163 path := filepath.Join(d.c.Repo.ScanPath, name)
164 gr, err := git.Open(path, ref)
165 if err != nil {
166 d.Write404(w)
167 return
168 }
169
170 contents, err := gr.FileContent(treePath)
171 data := make(map[string]any)
172 data["name"] = name
173 data["ref"] = ref
174
175 d.showFile(contents, data, w)
176 return
177}
178
179func (d *deps) Log(w http.ResponseWriter, r *http.Request) {
180 name := flow.Param(r.Context(), "name")
181 ref := flow.Param(r.Context(), "ref")
182
183 path := filepath.Join(d.c.Repo.ScanPath, name)
184 gr, err := git.Open(path, ref)
185 if err != nil {
186 d.Write404(w)
187 return
188 }
189
190 commits, err := gr.Commits()
191 if err != nil {
192 d.Write500(w)
193 log.Println(err)
194 return
195 }
196
197 tpath := filepath.Join(d.c.Dirs.Templates, "*")
198 t := template.Must(template.ParseGlob(tpath))
199
200 data := make(map[string]interface{})
201 data["commits"] = commits
202 data["meta"] = d.c.Meta
203 data["name"] = name
204 data["ref"] = ref
205
206 if err := t.ExecuteTemplate(w, "log", data); err != nil {
207 log.Println(err)
208 return
209 }
210}
211
212func (d *deps) Diff(w http.ResponseWriter, r *http.Request) {
213 name := flow.Param(r.Context(), "name")
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 diff, err := gr.Diff()
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
235 data["commit"] = diff.Commit
236 data["stat"] = diff.Stat
237 data["diff"] = diff.Diff
238 data["meta"] = d.c.Meta
239 data["name"] = name
240 data["ref"] = ref
241
242 if err := t.ExecuteTemplate(w, "commit", data); err != nil {
243 log.Println(err)
244 return
245 }
246}
247
248func (d *deps) Refs(w http.ResponseWriter, r *http.Request) {
249 name := flow.Param(r.Context(), "name")
250
251 path := filepath.Join(d.c.Repo.ScanPath, name)
252 gr, err := git.Open(path, "")
253 if err != nil {
254 d.Write404(w)
255 return
256 }
257
258 tags, err := gr.Tags()
259 if err != nil {
260 // Non-fatal, we *should* have at least one branch to show.
261 log.Println(err)
262 }
263
264 branches, err := gr.Branches()
265 if err != nil {
266 log.Println(err)
267 d.Write500(w)
268 return
269 }
270
271 tpath := filepath.Join(d.c.Dirs.Templates, "*")
272 t := template.Must(template.ParseGlob(tpath))
273
274 data := make(map[string]interface{})
275
276 data["meta"] = d.c.Meta
277 data["name"] = name
278 data["branches"] = branches
279 data["tags"] = tags
280
281 if err := t.ExecuteTemplate(w, "refs", data); err != nil {
282 log.Println(err)
283 return
284 }
285}
286
287func (d *deps) ServeStatic(w http.ResponseWriter, r *http.Request) {
288 f := flow.Param(r.Context(), "file")
289 f = filepath.Clean(filepath.Join(d.c.Dirs.Static, f))
290
291 http.ServeFile(w, r, f)
292}
293
294func getDescription(path string) (desc string) {
295 db, err := os.ReadFile(filepath.Join(path, "description"))
296 if err == nil {
297 desc = string(db)
298 } else {
299 desc = ""
300 }
301 return
302}