all repos — legit @ 4eaaf451295ce9b541769d1322543f2d982ef5b0

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