diff --git a/internal/manager/job_compilers/job_compilers.go b/internal/manager/job_compilers/job_compilers.go index 216e3863..f611ad56 100644 --- a/internal/manager/job_compilers/job_compilers.go +++ b/internal/manager/job_compilers/job_compilers.go @@ -61,7 +61,7 @@ func Load(ts TimeService) (*Service, error) { staticFileLoader := func(path string) ([]byte, error) { // TODO: this should try different filesystems, once we allow loading from // disk as well. - content, err := loadScriptBytes(scriptsFS, path) + content, err := loadScriptBytes(getEmbeddedScriptFS(), path) if err != nil { // The 'require' module uses this to try different variations of the path // in order to find it (without .js, with .js, etc.), so don't log any of diff --git a/internal/manager/job_compilers/scripts.go b/internal/manager/job_compilers/scripts.go index 6505bb76..6b43e2f3 100644 --- a/internal/manager/job_compilers/scripts.go +++ b/internal/manager/job_compilers/scripts.go @@ -3,7 +3,6 @@ package job_compilers // SPDX-License-Identifier: GPL-3.0-or-later import ( - "embed" "fmt" "io" "io/fs" @@ -15,18 +14,10 @@ import ( "github.com/rs/zerolog/log" ) -//go:embed scripts -var scriptsFS embed.FS - // loadScripts iterates over all JavaScript files, compiles them, and stores the // result into `s.compilers`. func (s *Service) loadScripts() error { - scriptsSubFS, err := fs.Sub(scriptsFS, "scripts") - if err != nil { - return fmt.Errorf("failed to find embedded 'scripts' directory: %w", err) - } - - compilers, err := loadScriptsFrom(scriptsSubFS) + compilers, err := loadScriptsFrom(getEmbeddedScriptFS()) if err != nil { return err } diff --git a/internal/manager/job_compilers/scripts_embedded.go b/internal/manager/job_compilers/scripts_embedded.go new file mode 100644 index 00000000..d8d1d8cc --- /dev/null +++ b/internal/manager/job_compilers/scripts_embedded.go @@ -0,0 +1,28 @@ +package job_compilers + +// SPDX-License-Identifier: GPL-3.0-or-later + +import ( + "embed" + "fmt" + "io/fs" +) + +// Scripts from the `./scripts` subdirectory are embedded into the executable +// here. Note that accessing these files still requires explicit use of the +// `scripts/` subdirectory, which is abstracted away by `getEmbeddedScriptFS()`. +// It is recommended to use that function to get the embedded scripts +// filesystem. + +//go:embed scripts +var _embeddedScriptsFS embed.FS + +// getEmbeddedScriptFS returns the `fs.FS` interface that allows access to the +// embedded job compiler scripts. +func getEmbeddedScriptFS() fs.FS { + scriptsSubFS, err := fs.Sub(_embeddedScriptsFS, "scripts") + if err != nil { + panic(fmt.Sprintf("failed to find embedded 'scripts' directory: %v", err)) + } + return scriptsSubFS +} diff --git a/internal/manager/job_compilers/scripts_test.go b/internal/manager/job_compilers/scripts_test.go index 4a97f508..a51c50d2 100644 --- a/internal/manager/job_compilers/scripts_test.go +++ b/internal/manager/job_compilers/scripts_test.go @@ -1,9 +1,12 @@ package job_compilers +// SPDX-License-Identifier: GPL-3.0-or-later + import ( "os" "testing" + "github.com/rs/zerolog" "github.com/stretchr/testify/assert" ) @@ -27,6 +30,39 @@ func TestLoadScriptsFrom_on_disk_js(t *testing.T) { assert.Equal(t, expectKeys, keys(compilers)) } +func TestLoadScriptsFrom_embedded(t *testing.T) { + compilers, err := loadScriptsFrom(getEmbeddedScriptFS()) + + assert.NoError(t, err) + expectKeys := map[string]bool{ + "echo-sleep-test": true, + "simple-blender-render": true, + } + assert.Equal(t, expectKeys, keys(compilers)) +} + +func BenchmarkLoadScripts_fromEmbedded(b *testing.B) { + zerolog.SetGlobalLevel(zerolog.Disabled) + + embeddedFS := getEmbeddedScriptFS() + for i := 0; i < b.N; i++ { + compilers, err := loadScriptsFrom(embeddedFS) + assert.NoError(b, err) + assert.NotEmpty(b, compilers) + } +} + +func BenchmarkLoadScripts_fromDisk(b *testing.B) { + zerolog.SetGlobalLevel(zerolog.Disabled) + + onDiskFS := os.DirFS("scripts-for-unittest") + for i := 0; i < b.N; i++ { + compilers, err := loadScriptsFrom(onDiskFS) + assert.NoError(b, err) + assert.NotEmpty(b, compilers) + } +} + // keys returns the set of keys of the mapping. func keys[K comparable, V any](mapping map[K]V) map[K]bool { keys := map[K]bool{}