about summary refs log tree commit diff stats
path: root/internal/builder/files.go
diff options
context:
space:
mode:
authorAlan Pearce2024-06-23 17:22:09 +0200
committerAlan Pearce2024-06-23 19:23:20 +0200
commitfe4a23b550b7450e6e24cd3c78dfd575122d361d (patch)
tree61e4f2158455ad8e7c05a7c8f219e909a3239263 /internal/builder/files.go
parent3a7e71544045647fa3ac702a1f0c5ad14623cb98 (diff)
downloadwebsite-fe4a23b550b7450e6e24cd3c78dfd575122d361d.tar.lz
website-fe4a23b550b7450e6e24cd3c78dfd575122d361d.tar.zst
website-fe4a23b550b7450e6e24cd3c78dfd575122d361d.zip
pre-compress generated files in production
Diffstat (limited to 'internal/builder/files.go')
-rw-r--r--internal/builder/files.go83
1 files changed, 83 insertions, 0 deletions
diff --git a/internal/builder/files.go b/internal/builder/files.go
new file mode 100644
index 0000000..57d4d2e
--- /dev/null
+++ b/internal/builder/files.go
@@ -0,0 +1,83 @@
+package builder
+
+import (
+	"compress/gzip"
+	"io"
+	"os"
+
+	"github.com/andybalholm/brotli"
+)
+
+const (
+	gzipLevel   = 6
+	brotliLevel = 9
+)
+
+type MultiWriteCloser struct {
+	writers     []io.WriteCloser
+	multiWriter io.Writer
+}
+
+func (mw *MultiWriteCloser) Write(p []byte) (n int, err error) {
+	return mw.multiWriter.Write(p)
+}
+
+func (mw *MultiWriteCloser) Close() error {
+	var lastErr error
+	for _, w := range mw.writers {
+		err := w.Close()
+		if err != nil {
+			lastErr = err
+		}
+	}
+	return lastErr
+}
+
+func openFileWrite(filename string) (*os.File, error) {
+	return os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+}
+
+func openFileGz(filename string) (*gzip.Writer, error) {
+	filenameGz := filename + ".gz"
+	f, err := openFileWrite(filenameGz)
+	if err != nil {
+		return nil, err
+	}
+	return gzip.NewWriterLevel(f, gzipLevel)
+}
+
+func openFileBrotli(filename string) (*brotli.Writer, error) {
+	filenameBrotli := filename + ".br"
+	f, err := openFileWrite(filenameBrotli)
+	if err != nil {
+		return nil, err
+	}
+	return brotli.NewWriterLevel(f, brotliLevel), nil
+}
+
+func multiOpenFile(filename string) (*MultiWriteCloser, error) {
+	r, err := openFileWrite(filename)
+	if err != nil {
+		return nil, err
+	}
+	gz, err := openFileGz(filename)
+	if err != nil {
+		return nil, err
+	}
+	br, err := openFileBrotli(filename)
+	if err != nil {
+		return nil, err
+	}
+	return &MultiWriteCloser{
+		writers:     []io.WriteCloser{r, gz, br},
+		multiWriter: io.MultiWriter(r, gz, br),
+	}, nil
+}
+
+func openFileAndVariants(filename string) (io.WriteCloser, error) {
+	if compressFiles {
+		return multiOpenFile(filename)
+	} else {
+		return openFileWrite(filename)
+	}
+}