about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAlan Pearce2024-04-25 17:13:39 +0200
committerAlan Pearce2024-04-25 17:13:39 +0200
commitd012553aaf78a436fa8871830b5d720a9e292d4b (patch)
tree291eea42535b830dd2521977d3c2f7e48604fbb6
parenta1d11d3e69650d9b43ca1b1d7b7ccc05a808d5c1 (diff)
downloadwebsite-d012553aaf78a436fa8871830b5d720a9e292d4b.tar.lz
website-d012553aaf78a436fa8871830b5d720a9e292d4b.tar.zst
website-d012553aaf78a436fa8871830b5d720a9e292d4b.zip
dev: create basic dev server to build and serve from a temporary directory
-rw-r--r--cmd/dev/main.go60
-rw-r--r--internal/server/server.go10
-rwxr-xr-xjustfile2
3 files changed, 70 insertions, 2 deletions
diff --git a/cmd/dev/main.go b/cmd/dev/main.go
new file mode 100644
index 0000000..b10a4f3
--- /dev/null
+++ b/cmd/dev/main.go
@@ -0,0 +1,60 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"log/slog"
+	"os"
+
+	"website/internal/builder"
+	"website/internal/config"
+	"website/internal/server"
+
+	"github.com/ardanlabs/conf/v3"
+	"github.com/pkg/errors"
+)
+
+type DevConfig struct {
+	Source  string     `conf:"default:.,short:s"`
+	BaseURL config.URL `conf:"default:http://localhost:3000"`
+}
+
+func main() {
+	if os.Getenv("DEBUG") != "" {
+		slog.SetLogLoggerLevel(slog.LevelDebug)
+	}
+
+	devConfig := DevConfig{}
+	help, err := conf.Parse("", &devConfig)
+	if err != nil {
+		if errors.Is(err, conf.ErrHelpWanted) {
+			fmt.Println(help)
+			os.Exit(1)
+		}
+		log.Panicf("parsing dev configuration: %v", err)
+	}
+
+	dir, err := os.MkdirTemp("", "website")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer os.RemoveAll(dir)
+	slog.Debug(fmt.Sprintf("using %s for build output", dir))
+
+	builderConfig := builder.IOConfig{
+		Source:      devConfig.Source,
+		Destination: dir,
+		BaseURL:     devConfig.BaseURL,
+	}
+	runtimeConfig := server.Config{
+		Production:    false,
+		ListenAddress: devConfig.BaseURL.Hostname(),
+		Port:          devConfig.BaseURL.Port(),
+		BaseURL:       devConfig.BaseURL,
+		Root:          dir,
+	}
+
+	builder.BuildSite(builderConfig)
+
+	server.Start(&runtimeConfig)
+}
diff --git a/internal/server/server.go b/internal/server/server.go
index e5e8df8..e5c0dc7 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -9,6 +9,7 @@ import (
 	"net"
 	"net/http"
 	"os"
+	"path"
 	"strings"
 	"time"
 
@@ -25,6 +26,7 @@ var config *cfg.Config
 
 type Config struct {
 	Production    bool    `conf:"default:false"`
+	Root          string  `conf:"default:website"`
 	ListenAddress string  `conf:"default:localhost"`
 	Port          string  `conf:"default:3000,short:p"`
 	BaseURL       cfg.URL `conf:"default:http://localhost:3000,short:b"`
@@ -111,7 +113,7 @@ func Start(runtimeConfig *Config) {
 	}
 	config = c
 
-	prefix := "website/public"
+	prefix := path.Join(runtimeConfig.Root, "public")
 	slog.Debug("registering content files", "prefix", prefix)
 	err = registerContentFiles(prefix)
 	if err != nil {
@@ -166,5 +168,9 @@ func Start(runtimeConfig *Config) {
 	})
 
 	listenAddress := net.JoinHostPort(runtimeConfig.ListenAddress, runtimeConfig.Port)
-	log.Fatal(http.ListenAndServe(listenAddress, nil))
+
+	done := make(chan bool)
+	go http.ListenAndServe(listenAddress, nil)
+	log.Printf("server listening on %s", runtimeConfig.BaseURL.String())
+	<-done
 }
diff --git a/justfile b/justfile
index e4021c0..cbaf06a 100755
--- a/justfile
+++ b/justfile
@@ -34,6 +34,8 @@ nix-build what:
 
 watch-server: (watch-flake "watchexec -r -i content -i templates go run ./cmd/server")
 
+dev: (watch-flake "watchexec -r go run ./cmd/dev")
+
 docker-stream system=(arch() + "-linux"):
     @nix build --print-out-paths .#docker-stream-{{ system }} | sh