all repos — legit @ e4d12fc667c9830dd5f08f827b2a70adff58a09b

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