add raw file routes and allow readme to reference relative repo paths

This commit is contained in:
Iris Lightshard 2023-01-31 16:27:22 -07:00
parent 9bb6fb2afc
commit 7d3fed52ad
Signed by: Iris Lightshard
GPG key ID: 3B7FBC22144E6398
6 changed files with 47 additions and 14 deletions

View file

@ -60,7 +60,7 @@ func (g *GitRepo) LastCommit() (*object.Commit, error) {
return c, nil return c, nil
} }
func (g *GitRepo) FileContent(path string) (string, error) { func (g *GitRepo) FileContent(path string, showBinary bool) (string, error) {
c, err := g.r.CommitObject(g.h) c, err := g.r.CommitObject(g.h)
if err != nil { if err != nil {
return "", fmt.Errorf("commit object: %w", err) return "", fmt.Errorf("commit object: %w", err)
@ -78,7 +78,7 @@ func (g *GitRepo) FileContent(path string) (string, error) {
isbin, _ := file.IsBinary() isbin, _ := file.IsBinary()
if !isbin { if showBinary || !isbin {
return file.Contents() return file.Contents()
} else { } else {
return "Not displaying binary file", nil return "Not displaying binary file", nil

View file

@ -41,6 +41,7 @@ func Handlers(c *config.Config) *flow.Mux {
mux.HandleFunc("/static/:file", d.ServeStatic, "GET") mux.HandleFunc("/static/:file", d.ServeStatic, "GET")
mux.HandleFunc("/:name", d.Multiplex, "GET", "POST") mux.HandleFunc("/:name", d.Multiplex, "GET", "POST")
mux.HandleFunc("/:name/tree/:ref/...", d.RepoTree, "GET") mux.HandleFunc("/:name/tree/:ref/...", d.RepoTree, "GET")
mux.HandleFunc("/:name/blob/raw/:ref/...", d.ServeStaticInRepo, "GET")
mux.HandleFunc("/:name/blob/:ref/...", d.FileContent, "GET") mux.HandleFunc("/:name/blob/:ref/...", d.FileContent, "GET")
mux.HandleFunc("/:name/log/:ref", d.Log, "GET") mux.HandleFunc("/:name/log/:ref", d.Log, "GET")
mux.HandleFunc("/:name/commit/:ref", d.Diff, "GET") mux.HandleFunc("/:name/commit/:ref", d.Diff, "GET")

View file

@ -1,6 +1,7 @@
package routes package routes
import ( import (
"bytes"
"fmt" "fmt"
"html/template" "html/template"
"log" "log"
@ -97,6 +98,13 @@ func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) {
return return
} }
mainBranch, err := gr.FindMainBranch(d.c.Repo.MainBranch)
if err != nil {
d.Write500(w)
log.Println(err)
return
}
commits, err := gr.Commits() commits, err := gr.Commits()
if err != nil { if err != nil {
d.Write500(w) d.Write500(w)
@ -107,7 +115,7 @@ func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) {
var readmeContent template.HTML var readmeContent template.HTML
for _, readme := range d.c.Repo.Readme { for _, readme := range d.c.Repo.Readme {
ext := filepath.Ext(readme) ext := filepath.Ext(readme)
content, _ := gr.FileContent(readme) content, _ := gr.FileContent(readme, false)
if len(content) > 0 { if len(content) > 0 {
switch ext { switch ext {
case ".md", ".mkd", ".markdown": case ".md", ".mkd", ".markdown":
@ -116,7 +124,7 @@ func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) {
blackfriday.WithExtensions(blackfriday.CommonExtensions), blackfriday.WithExtensions(blackfriday.CommonExtensions),
) )
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
readmeContent = template.HTML(html) readmeContent = template.HTML(transformRelativeURLs(string(html), name, mainBranch))
default: default:
readmeContent = template.HTML( readmeContent = template.HTML(
fmt.Sprintf(`<pre>%s</pre>`, content), fmt.Sprintf(`<pre>%s</pre>`, content),
@ -130,13 +138,6 @@ func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) {
log.Printf("no readme found for %s", name) log.Printf("no readme found for %s", name)
} }
mainBranch, err := gr.FindMainBranch(d.c.Repo.MainBranch)
if err != nil {
d.Write500(w)
log.Println(err)
return
}
tpath := filepath.Join(d.c.Dirs.Templates, "*") tpath := filepath.Join(d.c.Dirs.Templates, "*")
t := template.Must(template.ParseGlob(tpath)) t := template.Must(template.ParseGlob(tpath))
@ -212,12 +213,13 @@ func (d *deps) FileContent(w http.ResponseWriter, r *http.Request) {
return return
} }
contents, err := gr.FileContent(treePath) contents, err := gr.FileContent(treePath, false)
data := make(map[string]any) data := make(map[string]any)
data["name"] = name data["name"] = name
data["ref"] = ref data["ref"] = ref
data["desc"] = getDescription(path) data["desc"] = getDescription(path)
data["path"] = treePath data["path"] = treePath
data["raw"] = fmt.Sprintf("/%s/blob/raw/%s/%s", name, ref, treePath)
d.showFile(contents, data, w) d.showFile(contents, data, w)
return return
@ -346,6 +348,26 @@ func (d *deps) Refs(w http.ResponseWriter, r *http.Request) {
} }
} }
func (d *deps) ServeStaticInRepo(w http.ResponseWriter, r *http.Request) {
f := flow.Param(r.Context(), "...")
p := flow.Param(r.Context(), "name")
ref := flow.Param(r.Context(), "ref")
repoPath := filepath.Clean(filepath.Join(d.c.Repo.ScanPath, p))
gr, err := git.Open(repoPath, ref)
if err != nil {
d.Write500(w)
return
}
contents, err := gr.FileContent(f, true)
if err != nil {
d.Write500(w)
return
}
http.ServeContent(w, r, filepath.Base(f), time.Unix(0, 0), bytes.NewReader([]byte(contents)))
}
func (d *deps) ServeStatic(w http.ResponseWriter, r *http.Request) { func (d *deps) ServeStatic(w http.ResponseWriter, r *http.Request) {
f := flow.Param(r.Context(), "file") f := flow.Param(r.Context(), "file")
f = filepath.Clean(filepath.Join(d.c.Dirs.Static, f)) f = filepath.Clean(filepath.Join(d.c.Dirs.Static, f))

View file

@ -1,14 +1,16 @@
package routes package routes
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"git.icyphox.sh/legit/git" "git.icyphox.sh/legit/git"
) )
func isGoModule(gr *git.GitRepo) bool { func isGoModule(gr *git.GitRepo) bool {
_, err := gr.FileContent("go.mod") _, err := gr.FileContent("go.mod", false)
return err == nil return err == nil
} }
@ -22,6 +24,13 @@ func getDescription(path string) (desc string) {
return return
} }
func transformRelativeURLs(html, repoName, mainBranch string) string {
return strings.ReplaceAll(
html,
"=\"./",
fmt.Sprintf("=\"/%s/blob/raw/%s/", repoName, mainBranch))
}
func (d *deps) isIgnored(name string) bool { func (d *deps) isIgnored(name string) bool {
for _, i := range d.c.Repo.Ignore { for _, i := range d.c.Repo.Ignore {
if name == i { if name == i {

View file

@ -247,6 +247,7 @@ a:hover {
gap: 1rem; gap: 1rem;
padding: 0.5rem; padding: 0.5rem;
background: var(--light-gray); background: var(--light-gray);
margin-top: 0.5rem;
} }
.file-content { .file-content {

View file

@ -7,7 +7,7 @@
<body> <body>
{{ template "nav" . }} {{ template "nav" . }}
<main> <main>
<p>{{ .path }}</p> <p>{{ .path }} (<a href="{{ .raw }}">raw</a>)</p>
<div class="file-wrapper"> <div class="file-wrapper">
<div class="line-numbers"> <div class="line-numbers">
{{- range .linecount }} {{- range .linecount }}