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