Fix asset provisioning to strip embedded share/radiantwave root

This commit is contained in:
NeilClack
2026-08-03 02:40:51 -05:00
parent 11b25227d7
commit b54dbca2d5
3 changed files with 55 additions and 1 deletions
+1 -1
View File
@@ -150,7 +150,7 @@ func Run(bundled fs.FS) {
if err != nil {
panic(err)
}
if err := assets.Provision(bundled, config.AssetsDir); err != nil {
if err := assets.ProvisionAssets(bundled, config.AssetsDir); err != nil {
logger.Error("failed to provision bundled assets into %s: %v", config.AssetsDir, err)
}
+19
View File
@@ -11,6 +11,25 @@ import (
"path/filepath"
)
// embeddedRoot is the directory in the source tree (and therefore in the
// embedded FS) where the bundled assets live. It mirrors the nix store
// layout, but consumers expect the assets directly under the assets dir,
// so this root is stripped during provisioning.
const embeddedRoot = "share/radiantwave"
// ProvisionAssets provisions the bundled static assets (fonts, shaders, and
// terms-of-service pages) into destDir, stripping the embedded
// share/radiantwave root so the files land directly in destDir rather than
// in a nested share/radiantwave/ subdirectory. Existing files are
// overwritten so the deployed assets always match the running binary.
func ProvisionAssets(bundled fs.FS, destDir string) error {
root, err := fs.Sub(bundled, embeddedRoot)
if err != nil {
return fmt.Errorf("bundled assets missing %s root: %w", embeddedRoot, err)
}
return Provision(root, destDir)
}
// Provision copies every file from the embedded filesystem into destDir,
// preserving the relative directory structure. Existing files are
// overwritten so the deployed assets always match the running binary.
+35
View File
@@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"testing"
"testing/fstest"
)
//go:embed testdata
@@ -38,6 +39,40 @@ func TestProvisionCopiesBundledFiles(t *testing.T) {
}
}
// TestProvisionAssetsStripsEmbeddedRoot is a regression test: provisioning
// used to preserve the embedded share/radiantwave root, so assets landed in
// <dataDir>/share/radiantwave/fonts instead of <dataDir>/fonts. ProvisionAssets
// strips that root so consumers find the assets directly under the assets dir.
func TestProvisionAssetsStripsEmbeddedRoot(t *testing.T) {
fsys := fstest.MapFS{
"share/radiantwave/fonts/TestFont.ttf": &fstest.MapFile{Data: []byte("font")},
"share/radiantwave/shaders/text.frag": &fstest.MapFile{Data: []byte("frag")},
"share/radiantwave/shaders/text.vert": &fstest.MapFile{Data: []byte("vert")},
"share/radiantwave/tos/01 - WELCOME.html": &fstest.MapFile{Data: []byte("welcome")},
}
dest := t.TempDir()
if err := ProvisionAssets(fsys, dest); err != nil {
t.Fatalf("ProvisionAssets returned error: %v", err)
}
// Assets must land directly under dest, not under dest/share/radiantwave.
for _, rel := range []string{
"fonts/TestFont.ttf",
"shaders/text.frag",
"shaders/text.vert",
"tos/01 - WELCOME.html",
} {
if _, err := os.Stat(filepath.Join(dest, filepath.FromSlash(rel))); err != nil {
t.Errorf("expected %s to be provisioned directly under dest: %v", rel, err)
}
}
if _, err := os.Stat(filepath.Join(dest, "share")); !os.IsNotExist(err) {
t.Errorf("unexpected share/ directory created under dest: %v", err)
}
}
func TestProvisionOverwritesStaleFiles(t *testing.T) {
dest := t.TempDir()