git-pr

created pr with ps-3 on 2024-07-19T14:53:23Z · by c8ef7d19
added ps-4 on 2024-07-19T14:55:48Z · by c8ef7d19
1: 3b99dc0 < -: ------- feat: static assets
2: 8919af5 ! 1: 66cafc6 feat: static assets folder
3: 7346122 ! 2: 5e76ed3 fix(cli): access control for removing patchsets
4: d8792d5 < -: ------- feat: static folder
pr_reviewed on 2024-07-19T15:42:29Z · by 964fa508
changed status to reviewed on 2024-07-19T15:42:29Z · by 964fa508
added ps-9 on 2024-07-19T17:43:47Z · by c8ef7d19
1: cc56ea1 = 1: 0467f9e feat: static assets folder
2: ef749a4 = 2: da1730f review: typo and future enhancement comment
-: ------- > 3: c038404 refactor: per-file override for static folder
changed status to accepted on 2024-07-19T18:27:53Z · by 964fa508
cmds
checkout latest patchset:
ssh pr.pico.sh print pr-3 | git am -3
checkout any patchset in a patch request:
ssh pr.pico.sh print ps-X | git am -3
add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 3
set PR to open (enables RSS notifications):
ssh pr.pico.sh pr open 3
set PR to draft (stops RSS notifications):
ssh pr.pico.sh pr draft 3
+4 -0 Makefile #
@@ -26,3 +26,7 @@ bp: bp-setup
 	$(DOCKER_BUILDX_BUILD) -t "ghcr.io/picosh/pico/git-ssh:$(DOCKER_TAG)" --target release-ssh .
 	$(DOCKER_BUILDX_BUILD) -t "ghcr.io/picosh/pico/git-web:$(DOCKER_TAG)" --target release-web .
 .PHONY: bp
+
+smol:
+	curl https://pico.sh/smol.css -o ./static/smol.css
+.PHONY: smol
+57 -0 web.go #
@@ -6,8 +6,11 @@ import (
 	"embed"
 	"fmt"
 	"html/template"
+	"io"
+	"io/fs"
 	"log/slog"
 	"net/http"
+	"os"
 	"path/filepath"
 	"slices"
 	"strconv"
@@ -23,6 +26,9 @@ import (
 //go:embed tmpl/*
 var tmplFS embed.FS
 
+//go:embed static/*
+var staticFS embed.FS
+
 type WebCtx struct {
 	Pr        *PrCmd
 	Backend   *Backend
@@ -618,6 +624,49 @@ func chromaStyleHandler(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
+func serveFile(staticfs fs.FS) func(w http.ResponseWriter, r *http.Request) {
+	return func(w http.ResponseWriter, r *http.Request) {
+		web, err := getWebCtx(r)
+		if err != nil {
+			w.WriteHeader(http.StatusUnprocessableEntity)
+			return
+		}
+		logger := web.Logger
+
+		file := r.PathValue("file")
+		reader, err := staticfs.Open(file)
+		if err != nil {
+			logger.Error(err.Error())
+			http.Error(w, "file not found", 404)
+			return
+		}
+		contents, err := io.ReadAll(reader)
+		if err != nil {
+			logger.Error(err.Error())
+			http.Error(w, "file not found", 404)
+			return
+		}
+		contentType := http.DetectContentType(contents)
+		w.Header().Add("Content-Type", contentType)
+
+		_, err = w.Write(contents)
+		if err != nil {
+			logger.Error(err.Error())
+			http.Error(w, "server error", 500)
+			return
+		}
+	}
+}
+
+type StaticFs struct {
+	Dir string
+}
+
+func (fs *StaticFs) Open(name string) (os.File, error) {
+	fp, err := os.Open(filepath.Join(fs.Dir, name))
+	return *fp, err
+}
+
 func StartWebServer(cfg *GitCfg) {
 	addr := fmt.Sprintf("%s:%s", cfg.Host, cfg.WebPort)
 
@@ -659,6 +708,14 @@ func StartWebServer(cfg *GitCfg) {
 	http.HandleFunc("GET /", ctxMdw(ctx, repoListHandler))
 	http.HandleFunc("GET /syntax.css", ctxMdw(ctx, chromaStyleHandler))
 	http.HandleFunc("GET /rss", ctxMdw(ctx, rssHandler))
+	dir := filepath.Join(cfg.DataDir, "static")
+	var filesys fs.FS = staticFS
+	_, err = os.Stat(dir)
+	if err == nil {
+		cfg.Logger.Info("detected static folder, using instead of the default one")
+		filesys = os.DirFS(dir)
+	}
+	http.HandleFunc("GET /static/{file}", serveFile(filesys))
 
 	cfg.Logger.Info("starting web server", "addr", addr)
 	err = http.ListenAndServe(addr, nil)
Back to top