diff options
Diffstat (limited to 'gopher.go')
-rw-r--r-- | gopher.go | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/gopher.go b/gopher.go new file mode 100644 index 0000000..c725d68 --- /dev/null +++ b/gopher.go @@ -0,0 +1,129 @@ +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) + }) +} |