From 5166f511d28abb0bdce045b8fd9d967697084bc6 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 9 Aug 2013 16:50:24 -0700 Subject: [PATCH] common/json: add Unmarshal with method with syntax errors --- common/command/template.go | 4 ++-- common/json/unmarshal.go | 40 +++++++++++++++++++++++++++++++++++ common/json/unmarshal_test.go | 1 + packer/template.go | 28 ++---------------------- 4 files changed, 45 insertions(+), 28 deletions(-) create mode 100644 common/json/unmarshal.go create mode 100644 common/json/unmarshal_test.go diff --git a/common/command/template.go b/common/command/template.go index 4c14dd038..5eb114fe6 100644 --- a/common/command/template.go +++ b/common/command/template.go @@ -1,9 +1,9 @@ package command import ( - "encoding/json" "errors" "fmt" + jsonutil "github.com/mitchellh/packer/common/json" "github.com/mitchellh/packer/packer" "io/ioutil" "log" @@ -116,7 +116,7 @@ func readFileVars(path string) (map[string]string, error) { } vars := make(map[string]string) - err = json.Unmarshal(bytes, &vars) + err = jsonutil.Unmarshal(bytes, &vars) if err != nil { return nil, err } diff --git a/common/json/unmarshal.go b/common/json/unmarshal.go new file mode 100644 index 000000000..cbb27f487 --- /dev/null +++ b/common/json/unmarshal.go @@ -0,0 +1,40 @@ +package json + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// Unmarshal is wrapper around json.Unmarshal that returns user-friendly +// errors when there are syntax errors. +func Unmarshal(data []byte, i interface{}) error { + err := json.Unmarshal(data, i) + if err != nil { + syntaxErr, ok := err.(*json.SyntaxError) + if !ok { + return err + } + + // We have a syntax error. Extract out the line number and friends. + // https://groups.google.com/forum/#!topic/golang-nuts/fizimmXtVfc + newline := []byte{'\x0a'} + + // Calculate the start/end position of the line where the error is + start := bytes.LastIndex(data[:syntaxErr.Offset], newline) + 1 + end := len(data) + if idx := bytes.Index(data[start:], newline); idx >= 0 { + end = start + idx + } + + // Count the line number we're on plus the offset in the line + line := bytes.Count(data[:start], newline) + 1 + pos := int(syntaxErr.Offset) - start - 1 + + err = fmt.Errorf("Error in line %d, char %d: %s\n%s", + line, pos, syntaxErr, data[start:end]) + return err + } + + return nil +} diff --git a/common/json/unmarshal_test.go b/common/json/unmarshal_test.go new file mode 100644 index 000000000..a5b981cc6 --- /dev/null +++ b/common/json/unmarshal_test.go @@ -0,0 +1 @@ +package json diff --git a/packer/template.go b/packer/template.go index 9d9a08484..66e22e921 100644 --- a/packer/template.go +++ b/packer/template.go @@ -1,10 +1,9 @@ package packer import ( - "bytes" - "encoding/json" "fmt" "github.com/mitchellh/mapstructure" + jsonutil "github.com/mitchellh/packer/common/json" "io/ioutil" "sort" ) @@ -68,31 +67,8 @@ type rawProvisionerConfig struct { // way. func ParseTemplate(data []byte) (t *Template, err error) { var rawTplInterface interface{} - err = json.Unmarshal(data, &rawTplInterface) + err = jsonutil.Unmarshal(data, &rawTplInterface) if err != nil { - syntaxErr, ok := err.(*json.SyntaxError) - if !ok { - return - } - - // We have a syntax error. Extract out the line number and friends. - // https://groups.google.com/forum/#!topic/golang-nuts/fizimmXtVfc - newline := []byte{'\x0a'} - - // Calculate the start/end position of the line where the error is - start := bytes.LastIndex(data[:syntaxErr.Offset], newline) + 1 - end := len(data) - if idx := bytes.Index(data[start:], newline); idx >= 0 { - end = start + idx - } - - // Count the line number we're on plus the offset in the line - line := bytes.Count(data[:start], newline) + 1 - pos := int(syntaxErr.Offset) - start - 1 - - err = fmt.Errorf("Error in line %d, char %d: %s\n%s", - line, pos, syntaxErr, data[start:end]) - return }