all repos — legit @ 1b27f32cc21c4f85e475795c1033f4ad2d6cba52

web frontend for git, written in go

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