all repos — legit @ 203fb6c58a465ef712ca3e2998af25989433157d

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	"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}