From f965f9ee04890d8d643cc9221b290f3d1372cd5c Mon Sep 17 00:00:00 2001 From: Dave Cunningham Date: Sun, 29 Oct 2017 21:41:01 -0400 Subject: [PATCH] For compatability, emit the \n within the library, not the cmd (#137) * For compatability, emit the \n within the library, not the commandline tool * Also add manifestString to library --- builtins.go | 6 ++++-- interpreter.go | 35 +++++++++++++++++++++++++++-------- jsonnet/cmd.go | 2 +- main_test.go | 6 +++--- vm.go | 3 ++- 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/builtins.go b/builtins.go index 43ed841..52b2e15 100644 --- a/builtins.go +++ b/builtins.go @@ -17,6 +17,7 @@ limitations under the License. package jsonnet import ( + "bytes" "crypto/md5" "encoding/hex" "fmt" @@ -240,11 +241,12 @@ func builtinToString(e *evaluator, xp potentialValue) (value, error) { case *valueString: return x, nil } - s, err := e.i.manifestAndSerializeJSON(e.trace, x, false, "") + var buf bytes.Buffer + err = e.i.manifestAndSerializeJSON(&buf, e.trace, x, false, "") if err != nil { return nil, err } - return makeValueString(s), nil + return makeValueString(buf.String()), nil } func builtinMakeArray(e *evaluator, szp potentialValue, funcp potentialValue) (value, error) { diff --git a/interpreter.go b/interpreter.go index cf35278..99f5bcc 100644 --- a/interpreter.go +++ b/interpreter.go @@ -723,16 +723,28 @@ func serializeJSON(v interface{}, multiline bool, indent string, buf *bytes.Buff } } -func (i *interpreter) manifestAndSerializeJSON(trace *TraceElement, v value, multiline bool, indent string) (string, error) { - var buf bytes.Buffer +func (i *interpreter) manifestAndSerializeJSON( + buf *bytes.Buffer, trace *TraceElement, v value, multiline bool, indent string) error { manifested, err := i.manifestJSON(trace, v) if err != nil { - return "", err + return err } - serializeJSON(manifested, multiline, indent, &buf) - return buf.String(), nil + serializeJSON(manifested, multiline, indent, buf) + return nil } +// manifestString expects the value to be a string and returns it. +func (i *interpreter) manifestString(buf *bytes.Buffer, trace *TraceElement, v value) error { + switch v := v.(type) { + case *valueString: + buf.WriteString(v.getString()) + return nil + default: + return makeRuntimeError(fmt.Sprint("Expected string result, got: " + v.getType().name), i.getCurrentStackTrace(trace)) + } +} + + func jsonToValue(e *evaluator, v interface{}) (value, error) { switch v := v.(type) { case nil: @@ -879,7 +891,8 @@ func makeInitialEnv(filename string, baseStd valueObject) environment { } // TODO(sbarzowski) this function takes far too many arguments - build interpreter in vm instead -func evaluate(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[string]*NativeFunction, maxStack int, importer Importer) (string, error) { +func evaluate(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[string]*NativeFunction, + maxStack int, importer Importer, stringOutput bool) (string, error) { i, err := buildInterpreter(ext, nativeFuncs, maxStack, importer) if err != nil { return "", err @@ -915,9 +928,15 @@ func evaluate(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[string] manifestationTrace := &TraceElement{ loc: &manifestationLoc, } - s, err := i.manifestAndSerializeJSON(manifestationTrace, result, true, "") + var buf bytes.Buffer + if stringOutput { + err = i.manifestString(&buf, manifestationTrace, result) + } else { + err = i.manifestAndSerializeJSON(&buf, manifestationTrace, result, true, "") + } if err != nil { return "", err } - return s, nil + buf.WriteString("\n") + return buf.String(), nil } diff --git a/jsonnet/cmd.go b/jsonnet/cmd.go index 4d50f97..fba14ab 100644 --- a/jsonnet/cmd.go +++ b/jsonnet/cmd.go @@ -114,5 +114,5 @@ func main() { fmt.Fprintf(os.Stderr, "%v\n", err.Error()) os.Exit(2) } - fmt.Println(json) + fmt.Print(json) } diff --git a/main_test.go b/main_test.go index cda3c5c..8d2ac89 100644 --- a/main_test.go +++ b/main_test.go @@ -127,8 +127,8 @@ func TestMain(t *testing.T) { // TODO(sbarzowski) perhaps somehow mark that we are processing // an error. But for now we can treat them the same. output = errFormatter.format(err) + output += "\n" } - output += "\n" if *update { err := ioutil.WriteFile(test.golden, []byte(output), 0666) if err != nil { @@ -260,13 +260,13 @@ func TestCustomImporter(t *testing.T) { }, }) input := `[import "a.jsonnet", importstr "b.jsonnet"]` - expected := `[ 4, "3 + 3" ]` + expected := `[ 4, "3 + 3" ] ` actual, err := vm.EvaluateSnippet("custom_import.jsonnet", input) if err != nil { t.Errorf("Unexpected error: %v", err) } actual = removeExcessiveWhitespace(actual) if actual != expected { - t.Errorf("Expected %v, but got %v", expected, actual) + t.Errorf("Expected %q, but got %q", expected, actual) } } diff --git a/vm.go b/vm.go index 820f3ae..62962c5 100644 --- a/vm.go +++ b/vm.go @@ -38,6 +38,7 @@ type VM struct { nativeFuncs map[string]*NativeFunction importer Importer ef ErrorFormatter + StringOutput bool } // External variable or top level argument provided before execution @@ -98,7 +99,7 @@ func (vm *VM) evaluateSnippet(filename string, snippet string) (output string, e if err != nil { return "", err } - output, err = evaluate(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importer) + output, err = evaluate(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importer, vm.StringOutput) if err != nil { return "", err }