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 log.Println(len(commits))
192 if err != nil {
193 d.Write500(w)
194 log.Println(err)
195 return
196 }
197
198 tpath := filepath.Join(d.c.Dirs.Templates, "*")
199 t := template.Must(template.ParseGlob(tpath))
200
201 data := make(map[string]interface{})
202 data["commits"] = commits
203 data["meta"] = d.c.Meta
204 data["name"] = name
205 data["ref"] = ref
206
207 if err := t.ExecuteTemplate(w, "log", data); err != nil {
208 log.Println(err)
209 return
210 }
211}
212
213func (d *deps) Diff(w http.ResponseWriter, r *http.Request) {
214 name := flow.Param(r.Context(), "name")
215 ref := flow.Param(r.Context(), "ref")
216
217 path := filepath.Join(d.c.Repo.ScanPath, name)
218 gr, err := git.Open(path, ref)
219 if err != nil {
220 d.Write404(w)
221 return
222 }
223
224 diff, err := gr.Diff()
225 if err != nil {
226 d.Write500(w)
227 log.Println(err)
228 return
229 }
230
231 tpath := filepath.Join(d.c.Dirs.Templates, "*")
232 t := template.Must(template.ParseGlob(tpath))
233
234 data := make(map[string]interface{})
235
236 data["commit"] = diff.Commit
237 data["stat"] = diff.Stat
238 data["diff"] = diff.Diff
239 data["meta"] = d.c.Meta
240 data["name"] = name
241 data["ref"] = ref
242
243 if err := t.ExecuteTemplate(w, "commit", data); err != nil {
244 log.Println(err)
245 return
246 }
247}
248
249func (d *deps) Refs(w http.ResponseWriter, r *http.Request) {
250 name := flow.Param(r.Context(), "name")
251
252 path := filepath.Join(d.c.Repo.ScanPath, name)
253 gr, err := git.Open(path, "")
254 if err != nil {
255 d.Write404(w)
256 return
257 }
258
259 tags, err := gr.Tags()
260 if err != nil {
261 // Non-fatal, we *should* have at least one branch to show.
262 log.Println(err)
263 }
264
265 branches, err := gr.Branches()
266 if err != nil {
267 log.Println(err)
268 d.Write500(w)
269 return
270 }
271
272 tpath := filepath.Join(d.c.Dirs.Templates, "*")
273 t := template.Must(template.ParseGlob(tpath))
274
275 data := make(map[string]interface{})
276
277 data["meta"] = d.c.Meta
278 data["name"] = name
279 data["branches"] = branches
280 data["tags"] = tags
281
282 if err := t.ExecuteTemplate(w, "refs", data); err != nil {
283 log.Println(err)
284 return
285 }
286}
287
288func (d *deps) ServeStatic(w http.ResponseWriter, r *http.Request) {
289 f := flow.Param(r.Context(), "file")
290 f = filepath.Clean(filepath.Join(d.c.Dirs.Static, f))
291
292 http.ServeFile(w, r, f)
293}
294
295func getDescription(path string) (desc string) {
296 db, err := os.ReadFile(filepath.Join(path, "description"))
297 if err == nil {
298 desc = string(db)
299 } else {
300 desc = ""
301 }
302 return
303}