From df334deca53aabdad1a5464ac24c418b4626ca6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 7 May 2024 11:58:39 +0200 Subject: [PATCH] Add `shellSplit(someString)` function to the job compiler scripts Add a function `shellSplit(string)` to the global namespace of job compiler scripts. It splits a string into an array of strings using shell/CLI semantics. For example: `shellSplit("--python-expr 'print(1 + 1)'")` will return `["--python-expr", "print(1 + 1)"]`. --- CHANGELOG.md | 1 + internal/manager/job_compilers/js_globals.go | 14 ++++++++++++++ .../manager/job_compilers/js_globals_test.go | 18 ++++++++++++++++++ internal/manager/job_compilers/scripts.go | 3 +++ 4 files changed, 36 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8ce6529..ef5bf445 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ bugs in actually-released versions. ## 3.6 - in development - Add `label` to job settings, to have full control over how they are presented in Blender's job submission GUI. If a job setting does not define a label, its `key` is used to generate one (like Flamenco 3.5 and older). +- Add `shellSplit(someString)` function to the job compiler scripts. This splits a string into an array of strings using shell/CLI semantics. ## 3.5 - released 2024-04-16 diff --git a/internal/manager/job_compilers/js_globals.go b/internal/manager/job_compilers/js_globals.go index de9dddf9..9628a988 100644 --- a/internal/manager/job_compilers/js_globals.go +++ b/internal/manager/job_compilers/js_globals.go @@ -10,6 +10,7 @@ import ( "time" "github.com/dop251/goja" + "github.com/google/shlex" "github.com/rs/zerolog/log" ) @@ -33,6 +34,19 @@ func jsFormatTimestampLocal(timestamp time.Time) string { return timestamp.Local().Format("2006-01-02_150405") } +// jsShellSplit splits a string into its parts, using CLI/shell semantics. +func jsShellSplit(vm *goja.Runtime, someCLIArgs string) []string { + split, err := shlex.Split(someCLIArgs) + + if err != nil { + // Generate a JS exception by panicing with a Goja Value. + exception := vm.ToValue(err) + panic(exception) + } + + return split +} + type ErrInvalidRange struct { Range string // The frame range that was invalid. Message string // The error message diff --git a/internal/manager/job_compilers/js_globals_test.go b/internal/manager/job_compilers/js_globals_test.go index e78b15d8..4029f1ef 100644 --- a/internal/manager/job_compilers/js_globals_test.go +++ b/internal/manager/job_compilers/js_globals_test.go @@ -5,10 +5,28 @@ package job_compilers import ( "testing" + "github.com/dop251/goja" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +func TestShellSplitHappy(t *testing.T) { + expect := []string{"--python-expr", "print(1 + 1)"} + actual := jsShellSplit(nil, "--python-expr 'print(1 + 1)'") + assert.Equal(t, expect, actual) +} + +func TestShellSplitFailure(t *testing.T) { + vm := goja.New() + + testFunc := func() { + jsShellSplit(vm, "--python-expr invalid_quoting(1 + 1)'") + } + // Testing that a goja.Value is used for the panic is a bit tricky, so just + // test that the function panics. + assert.Panics(t, testFunc) +} + func TestFrameChunkerHappyBlenderStyle(t *testing.T) { chunks, err := jsFrameChunker("1..10,20..25,40,3..8", 4) require.NoError(t, err) diff --git a/internal/manager/job_compilers/scripts.go b/internal/manager/job_compilers/scripts.go index efba10e9..92ad4e83 100644 --- a/internal/manager/job_compilers/scripts.go +++ b/internal/manager/job_compilers/scripts.go @@ -140,6 +140,9 @@ func newGojaVM(registry *require.Registry) *goja.Runtime { mustSet("alert", jsAlert) mustSet("frameChunker", jsFrameChunker) mustSet("formatTimestampLocal", jsFormatTimestampLocal) + mustSet("shellSplit", func(cliArgs string) []string { + return jsShellSplit(vm, cliArgs) + }) // Pre-import some useful modules. registry.Enable(vm)