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 "git.icyphox.sh/legit/config"
13 "git.icyphox.sh/legit/git"
14 "github.com/alexedwards/flow"
15 "github.com/dustin/go-humanize"
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 continue
42 }
43
44 c, err := gr.LastCommit()
45 if err != nil {
46 d.Write500(w)
47 log.Println(err)
48 return
49 }
50
51 desc := getDescription(path)
52
53 infos = append(infos, info{
54 Name: dir.Name(),
55 Desc: desc,
56 Idle: humanize.Time(c.Author.When),
57 d: c.Author.When,
58 })
59 }
60
61 sort.Slice(infos, func(i, j int) bool {
62 return infos[j].d.Before(infos[i].d)
63 })
64
65 tpath := filepath.Join(d.c.Dirs.Templates, "*")
66 t := template.Must(template.ParseGlob(tpath))
67
68 data := make(map[string]interface{})
69 data["meta"] = d.c.Meta
70 data["info"] = infos
71
72 if err := t.ExecuteTemplate(w, "index", data); err != nil {
73 log.Println(err)
74 return
75 }
76}
77
78func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) {
79 name := flow.Param(r.Context(), "name")
80 name = filepath.Clean(name)
81 path := filepath.Join(d.c.Repo.ScanPath, name)
82 gr, err := git.Open(path, "")
83 if err != nil {
84 d.Write404(w)
85 return
86 }
87
88 commits, err := gr.Commits()
89 if err != nil {
90 d.Write500(w)
91 log.Println(err)
92 return
93 }
94
95 var readmeContent string
96 for _, readme := range d.c.Repo.Readme {
97 readmeContent, _ = gr.FileContent(readme)
98 if readmeContent != "" {
99 break
100 }
101 }
102
103 if readmeContent == "" {
104 log.Printf("no readme found for %s", name)
105 }
106
107 mainBranch, err := gr.FindMainBranch(d.c.Repo.MainBranch)
108 if err != nil {
109 d.Write500(w)
110 log.Println(err)
111 return
112 }
113
114 tpath := filepath.Join(d.c.Dirs.Templates, "*")
115 t := template.Must(template.ParseGlob(tpath))
116
117 if len(commits) >= 3 {
118 commits = commits[:3]
119 }
120
121 data := make(map[string]any)
122 data["name"] = name
123 data["ref"] = mainBranch
124 data["readme"] = readmeContent
125 data["commits"] = commits
126 data["desc"] = getDescription(path)
127 data["servername"] = d.c.Server.Name
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}