diff options
148 files changed, 357 insertions, 818 deletions
diff --git a/cmd/xesite/main.go b/cmd/xesite/main.go index ff4c92e..daf831e 100644 --- a/cmd/xesite/main.go +++ b/cmd/xesite/main.go @@ -109,6 +109,10 @@ func main() { http.Redirect(w, r, "/blog/xn--ts9h/", http.StatusMovedPermanently) }) + mux.HandleFunc("/static/manifest.json", func(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, "/static/site.webmanifest", http.StatusMovedPermanently) + }) + if *devel { mux.HandleFunc("/.within/hook/github", func(w http.ResponseWriter, r *http.Request) { if err := fs.Update(r.Context()); err != nil { diff --git a/internal/lume/lume.go b/internal/lume/lume.go index f4fc20b..8188488 100644 --- a/internal/lume/lume.go +++ b/internal/lume/lume.go @@ -1,11 +1,13 @@ package lume import ( + "archive/zip" "context" "encoding/json" "expvar" "fmt" "html/template" + "io" "io/fs" "log" "log/slog" @@ -28,13 +30,9 @@ var ( typstLocation string dhallToJSONLocation string - _ fs.FS = (*FS)(nil) - _ fs.ReadFileFS = (*FS)(nil) - _ fs.ReadDirFS = (*FS)(nil) + _ fs.FS = (*FS)(nil) opens = metrics.LabelMap{Label: "name"} - readFiles = metrics.LabelMap{Label: "name"} - readDirs = metrics.LabelMap{Label: "name"} builds = expvar.NewInt("gauge_xesite_builds") updates = expvar.NewInt("gauge_xesite_updates") updateErrors = expvar.NewInt("gauge_xesite_update_errors") @@ -59,8 +57,6 @@ func init() { } expvar.Publish("gauge_xesite_opens", &opens) - expvar.Publish("gauge_xesite_read_files", &readFiles) - expvar.Publish("gauge_xesite_read_dirs", &readDirs) } type FS struct { @@ -72,13 +68,17 @@ type FS struct { miClient *mi.Client fs fs.FS - lock sync.RWMutex + lock sync.Mutex } func (f *FS) Close() error { f.lock.Lock() defer f.lock.Unlock() + if cl, ok := f.fs.(io.Closer); ok { + cl.Close() + } + if f.repo != nil { os.RemoveAll(f.repoDir) } @@ -87,34 +87,11 @@ func (f *FS) Close() error { } func (f *FS) Open(name string) (fs.File, error) { - f.lock.RLock() - defer f.lock.RUnlock() - opens.Add(name, 1) return f.fs.Open(name) } -func (f *FS) ReadDir(name string) ([]fs.DirEntry, error) { - f.lock.RLock() - defer f.lock.RUnlock() - - readDirs.Add(name, 1) - - rdfs := f.fs.(fs.ReadDirFS) - return rdfs.ReadDir(name) -} - -func (f *FS) ReadFile(name string) ([]byte, error) { - f.lock.RLock() - defer f.lock.RUnlock() - - readFiles.Add(name, 1) - - rfs := f.fs.(fs.ReadFileFS) - return rfs.ReadFile(name) -} - type Options struct { Development bool Branch string @@ -270,12 +247,30 @@ func (f *FS) build(ctx context.Context) error { return err } - f.fs = os.DirFS(destDir) dur := time.Since(begin) lastBuildTime.Set(dur.Milliseconds()) slog.Info("built site", "dir", destDir, "time", dur.String()) + zipLoc := filepath.Join(f.opt.DataDir, "site.zip") + + if err := ZipFolder(filepath.Join(cmd.Dir, "_site"), zipLoc); err != nil { + return fmt.Errorf("lume: can't compress site folder: %w", err) + } + + if cl, ok := f.fs.(io.Closer); f.fs != nil && ok { + if err := cl.Close(); err != nil { + slog.Error("failed to close old fs", "err", err) + } + } + + fs, err := zip.OpenReader(zipLoc) + if err != nil { + return fmt.Errorf("lume: can't open zip with site content: %w", err) + } + + f.fs = fs + return nil } @@ -348,8 +343,8 @@ func (f *FS) writeConfig() error { } func (f *FS) Clacks() []string { - f.lock.RLock() - defer f.lock.RUnlock() + f.lock.Lock() + defer f.lock.Unlock() return f.conf.ClackSet } diff --git a/internal/lume/zip.go b/internal/lume/zip.go new file mode 100644 index 0000000..b3b331f --- /dev/null +++ b/internal/lume/zip.go @@ -0,0 +1,68 @@ +package lume + +import ( + "archive/zip" + "io" + "os" + "path/filepath" +) + +// ZipFolder takes a source folder and a target zip file name +// and compresses the folder contents into the zip file +func ZipFolder(source, target string) error { + // Create a zip file + fout, err := os.Create(target) + if err != nil { + return err + } + defer fout.Close() + + // Create a zip writer + w := zip.NewWriter(fout) + defer w.Close() + + // Walk through the source folder + return filepath.Walk(source, func(path string, info os.FileInfo, err error) error { + // Handle errors + if err != nil { + return err + } + + // Skip directories + if info.IsDir() { + return nil + } + + // Open the file + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + // Create a header from the file info + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + // Set the compression method to deflate + header.Method = zip.Deflate + + // Set the header name to the relative path of the file + header.Name, err = filepath.Rel(source, path) + if err != nil { + return err + } + + // Create a fout for the file header + fout, err := w.CreateHeader(header) + if err != nil { + return err + } + + // Copy the file contents to the writer + _, err = io.Copy(fout, file) + return err + }) +} diff --git a/lume/deno.lock b/lume/deno.lock index 4f3d186..99b71e3 100644 --- a/lume/deno.lock +++ b/lume/deno.lock @@ -2,8 +2,6 @@ "version": "3", "packages": { "specifiers": { - "npm:@headlessui/react": "npm:@headlessui/react@1.7.17_react@18.2.0_react-dom@18.2.0__react@18.2.0", - "npm:@heroicons/react": "npm:@heroicons/react@2.0.18_react@18.2.0", "npm:@mdx-js/mdx@2.3.0": "npm:@mdx-js/mdx@2.3.0", "npm:@tailwindcss/forms": "npm:@tailwindcss/forms@0.5.6_tailwindcss@3.3.3__postcss@8.4.29", "npm:@tailwindcss/typography": "npm:@tailwindcss/typography@0.5.10_tailwindcss@3.3.3__postcss@8.4.29", @@ -20,13 +18,11 @@ "npm:postcss-import@15.1.0": "npm:postcss-import@15.1.0_postcss@8.4.29", "npm:postcss-nesting@12.0.1": "npm:postcss-nesting@12.0.1_postcss@8.4.29_postcss-selector-parser@6.0.13", "npm:postcss@8.4.29": "npm:postcss@8.4.29", - "npm:preact": "npm:preact@10.17.1", + "npm:preact": "npm:preact@10.18.1", "npm:preact-render-to-string@6.2.1": "npm:preact-render-to-string@6.2.1_preact@10.17.1", "npm:preact@10.17.1": "npm:preact@10.17.1", - "npm:react": "npm:react@18.2.0", "npm:react-dom@18.2.0": "npm:react-dom@18.2.0_react@18.2.0", "npm:react@18.2.0": "npm:react@18.2.0", - "npm:rehype-mermaidjs": "npm:rehype-mermaidjs@2.0.0", "npm:rehype-prism-plus": "npm:rehype-prism-plus@1.6.3", "npm:rehype-raw@7.0.0": "npm:rehype-raw@7.0.0", "npm:rehype-sanitize@6.0.0": "npm:rehype-sanitize@6.0.0", @@ -42,46 +38,24 @@ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "dependencies": {} }, - "@babel/runtime@7.23.1": { - "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "@babel/runtime@7.23.2": { + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "dependencies": { "regenerator-runtime": "regenerator-runtime@0.14.0" } }, - "@braintree/sanitize-url@6.0.4": { - "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==", - "dependencies": {} - }, "@csstools/selector-specificity@3.0.0_postcss-selector-parser@6.0.13": { "integrity": "sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==", "dependencies": { "postcss-selector-parser": "postcss-selector-parser@6.0.13" } }, - "@fortawesome/fontawesome-free@6.4.2": { - "integrity": "sha512-m5cPn3e2+FDCOgi1mz0RexTUvvQibBebOUlUlW0+YrMjDTPkiJ6VTKukA1GRsvRw+12KyJndNjj0O4AgTxm2Pg==", - "dependencies": {} - }, - "@headlessui/react@1.7.17_react@18.2.0_react-dom@18.2.0__react@18.2.0": { - "integrity": "sha512-4am+tzvkqDSSgiwrsEpGWqgGo9dz8qU5M3znCkC4PgkpY4HcCZzEDEvozltGGGHIKl9jbXbZPSH5TWn4sWJdow==", - "dependencies": { - "client-only": "client-only@0.0.1", - "react": "react@18.2.0", - "react-dom": "react-dom@18.2.0_react@18.2.0" - } - }, - "@heroicons/react@2.0.18_react@18.2.0": { - "integrity": "sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw==", - "dependencies": { - "react": "react@18.2.0" - } - }, "@jridgewell/gen-mapping@0.3.3": { "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dependencies": { "@jridgewell/set-array": "@jridgewell/set-array@1.1.2", "@jridgewell/sourcemap-codec": "@jridgewell/sourcemap-codec@1.4.15", - "@jridgewell/trace-mapping": "@jridgewell/trace-mapping@0.3.19" + "@jridgewell/trace-mapping": "@jridgewell/trace-mapping@0.3.20" |
