Variable replacement: fix issue replacing vars in nested lists

An array-of-strings in Go can become an array-of-`interface{}` when
converted to JSON and back again. Such cases are now handled properly.
This commit is contained in:
Sybren A. Stüvel 2022-07-21 16:28:38 +02:00
parent 344a62f37b
commit 27602174ae
2 changed files with 47 additions and 0 deletions

View File

@ -30,6 +30,19 @@ func replaceTaskVariables(replacer VariableReplacer, task api.AssignedTask, work
replaced[idx] = repl(v[idx]) replaced[idx] = repl(v[idx])
} }
task.Commands[cmdIndex].Parameters[key] = replaced task.Commands[cmdIndex].Parameters[key] = replaced
case []interface{}:
replaced := make([]interface{}, len(v))
for idx := range v {
switch itemValue := v[idx].(type) {
case string:
replaced[idx] = repl(itemValue)
default:
replaced[idx] = itemValue
}
}
task.Commands[cmdIndex].Parameters[key] = replaced
default: default:
continue continue
} }

View File

@ -3,6 +3,7 @@ package api_impl
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
import ( import (
"encoding/json"
"runtime" "runtime"
"testing" "testing"
@ -64,6 +65,21 @@ func TestReplaceVariables(t *testing.T) {
assert.Equal(t, 3, replacedTask.Commands[1].Parameters["{blender}"]) assert.Equal(t, 3, replacedTask.Commands[1].Parameters["{blender}"])
} }
func TestReplaceVariablesInterfaceArrays(t *testing.T) {
worker := persistence.Worker{Platform: "linux"}
conf := config.GetTestConfig()
task := jsonWash(varreplTestTask())
replacedTask := replaceTaskVariables(&conf, task, worker)
// Due to the conversion via JSON, arrays of strings are now arrays of
// interface{} and still need to be handled properly.
assert.Equal(t,
[]interface{}{"--render-out", "/shared/flamenco/render/long/sybren/blender-cloud-addon/flamenco-test__intermediate/render-smpl-0001-0084-frm-######"},
replacedTask.Commands[2].Parameters["args"],
)
}
func TestReplacePathsWindows(t *testing.T) { func TestReplacePathsWindows(t *testing.T) {
worker := persistence.Worker{Platform: "windows"} worker := persistence.Worker{Platform: "windows"}
task := varreplTestTask() task := varreplTestTask()
@ -137,3 +153,21 @@ func TestReplaceJobsVariable(t *testing.T) {
assert.Equal(t, expectPath, replacedTask.Commands[2].Parameters["filepath"]) assert.Equal(t, expectPath, replacedTask.Commands[2].Parameters["filepath"])
} }
} }
// jsonWash converts the given value to JSON and back.
// This makes sure the types are as closed to what the API will handle as
// possible, making the difference between "array of strings" and "array of
// interface{}s that happen to be strings".
func jsonWash[T any](value T) T {
bytes, err := json.Marshal(value)
if err != nil {
panic(err)
}
var jsonWashedValue T
err = json.Unmarshal(bytes, &jsonWashedValue)
if err != nil {
panic(err)
}
return jsonWashedValue
}