all repos — legit @ 5091695e75b2db30b8926d8aa17164c84031bc77

web frontend for git

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}