package syw import ( "bytes" "context" "mime" "os" "path" "path/filepath" "strings" "text/template" "tildegit.org/tjp/sliderule" "tildegit.org/tjp/sliderule/gopher" ) func GopherRouter(repodir string, overrides *template.Template) *sliderule.Router { tmpl, err := addTemplates(gopherTemplate, overrides) if err != nil { panic(err) } repoRouter := &sliderule.Router{} repoRouter.Use(assignRepo(repodir)) repoRouter.Route("/branches", runGopherTemplate(tmpl, "branch_list.gophermap", gopher.MenuType)) repoRouter.Route("/tags", runGopherTemplate(tmpl, "tag_list.gophermap", gopher.MenuType)) repoRouter.Route("/refs/:ref", runGopherTemplate(tmpl, "ref.gophermap", gopher.MenuType)) repoRouter.Route("/refs/:ref/tree", gopherTreePath(tmpl, false)) repoRouter.Route("/refs/:ref/tree/*path", gopherTreePath(tmpl, true)) repoRouter.Route("/diffstat/:fromref/:toref", runGopherTemplate(tmpl, "diffstat.gophertext", gopher.TextFileType)) repoRouter.Route("/diff/:fromref/:toref", runGopherTemplate(tmpl, "diff.gophertext", gopher.TextFileType)) router := &sliderule.Router{} router.Route("/", gopherRoot(repodir, tmpl)) router.Route("/:"+reponamekey, assignRepo(repodir)(runGopherTemplate(tmpl, "repo_home.gophermap", gopher.MenuType))) router.Mount("/:"+reponamekey, repoRouter) return router } func gopherRoot(repodir string, tmpl *template.Template) sliderule.Handler { return sliderule.HandlerFunc(func(ctx context.Context, request *sliderule.Request) *sliderule.Response { entries, err := os.ReadDir(repodir) if err != nil { return gopher.Error(err).Response() } names := []string{} for _, item := range entries { if Open(filepath.Join(repodir, item.Name())) != nil { names = append(names, item.Name()) } } buf := &bytes.Buffer{} obj := map[string]any{ "Repos": names, "Host": request.Hostname(), "Port": request.Port(), "Selector": request.Path, } if err := tmpl.ExecuteTemplate(buf, "repo_root.gophermap", obj); err != nil { return gopher.Error(err).Response() } return gopher.File(gopher.MenuType, buf) }) } func gopherTreePath(tmpl *template.Template, haspath bool) sliderule.Handler { return sliderule.HandlerFunc(func(ctx context.Context, request *sliderule.Request) *sliderule.Response { repo := ctx.Value(repokey).(*Repository) params := sliderule.RouteParams(ctx) t := "tree" if haspath { var err error t, err = repo.Type(ctx, params["ref"] + ":" + params["path"]) if err != nil { return gopher.Error(err).Response() } } if t != "blob" { if !haspath { params["path"] = "" } return runGopherTemplate(tmpl, "tree.gophermap", gopher.MenuType).Handle(ctx, request) } body, err := repo.Blob(ctx, params["ref"], params["path"]) if err != nil { return gopher.Error(err).Response() } filetype := gopher.MenuType ext := path.Ext(params["path"]) if ext != ".gophermap" && params["path"] != "gophermap" { mtype := mime.TypeByExtension(ext) if strings.HasPrefix(mtype, "text/") { filetype = gopher.TextFileType } else { filetype = gopher.BinaryFileType } } return gopher.File(filetype, bytes.NewBuffer(body)) }) } func runGopherTemplate(tmpl *template.Template, name string, filetype sliderule.Status) sliderule.Handler { return sliderule.HandlerFunc(func(ctx context.Context, request *sliderule.Request) *sliderule.Response { obj := map[string]any{ "Ctx": ctx, "Repo": ctx.Value(repokey), "Params": sliderule.RouteParams(ctx), "Host": request.Hostname(), "Port": request.Port(), "Selector": request.Path, } buf := &bytes.Buffer{} if err := tmpl.ExecuteTemplate(buf, name, obj); err != nil { return gopher.Error(err).Response() } return gopher.File(filetype, buf) }) }