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