all repos — legit @ a64f9d8f14762e341a851d0e211814958e044a64

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