Commit cceb9c04 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

packer: Clean up some of the JSON syntax stuff

parent fdb0131e
## 0.1.4 (unreleased) ## 0.1.4 (unreleased)
IMPROVEMENTS:
* core: Template syntax errors now show line and character number. [GH-56]
## 0.1.3 (July 1, 2013) ## 0.1.3 (July 1, 2013)
......
...@@ -57,29 +57,6 @@ type rawProvisionerConfig struct { ...@@ -57,29 +57,6 @@ type rawProvisionerConfig struct {
rawConfig interface{} rawConfig interface{}
} }
// displaySyntaxError returns a location for the json syntax error
// Adapted from:
// https://groups.google.com/forum/#!topic/golang-nuts/fizimmXtVfc
func displaySyntaxError(js []byte, syntaxError error) (err error) {
syntax, ok := syntaxError.(*json.SyntaxError)
if !ok {
err = syntaxError
return
}
newline := []byte{'\x0a'}
space := []byte{' '}
start, end := bytes.LastIndex(js[:syntax.Offset], newline)+1, len(js)
if idx := bytes.Index(js[start:], newline); idx >= 0 {
end = start + idx
}
line, pos := bytes.Count(js[:start], newline)+1, int(syntax.Offset) - start - 1
err = fmt.Errorf("\nError in line %d: %s \n%s\n%s^", line, syntaxError, js[start:end], bytes.Repeat(space, pos))
return
}
// ParseTemplate takes a byte slice and parses a Template from it, returning // ParseTemplate takes a byte slice and parses a Template from it, returning
// the template and possibly errors while loading the template. The error // the template and possibly errors while loading the template. The error
// could potentially be a MultiError, representing multiple errors. Knowing // could potentially be a MultiError, representing multiple errors. Knowing
...@@ -89,7 +66,27 @@ func ParseTemplate(data []byte) (t *Template, err error) { ...@@ -89,7 +66,27 @@ func ParseTemplate(data []byte) (t *Template, err error) {
var rawTpl rawTemplate var rawTpl rawTemplate
err = json.Unmarshal(data, &rawTpl) err = json.Unmarshal(data, &rawTpl)
if err != nil { if err != nil {
err = displaySyntaxError(data, err) 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'}
start := bytes.LastIndex(data[:syntaxErr.Offset], newline)+1
end := len(data)
if idx := bytes.Index(data[start:], newline); idx >= 0 {
end = start + idx
}
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 return
} }
...@@ -231,151 +228,151 @@ func parsePostProvisioner(i int, rawV interface{}) (result []map[string]interfac ...@@ -231,151 +228,151 @@ func parsePostProvisioner(i int, rawV interface{}) (result []map[string]interfac
errors = append( errors = append(
errors, errors,
fmt.Errorf("Post-processor %d.%d: sequences not allowed to be nested in sequences", i+1, j+1)) fmt.Errorf("Post-processor %d.%d: sequences not allowed to be nested in sequences", i+1, j+1))
default: default:
errors = append(errors, fmt.Errorf("Post-processor %d.%d is in a bad format.", i+1, j+1)) errors = append(errors, fmt.Errorf("Post-processor %d.%d is in a bad format.", i+1, j+1))
}
} }
}
if len(errors) == 0 { if len(errors) == 0 {
errors = nil errors = nil
}
default:
result = nil
errors = []error{fmt.Errorf("Post-processor %d is in a bad format.", i+1)}
} }
default:
result = nil return
errors = []error{fmt.Errorf("Post-processor %d is in a bad format.", i+1)}
} }
return // BuildNames returns a slice of the available names of builds that
} // this template represents.
func (t *Template) BuildNames() []string {
names := make([]string, 0, len(t.Builders))
for name, _ := range t.Builders {
names = append(names, name)
}
// BuildNames returns a slice of the available names of builds that return names
// this template represents.
func (t *Template) BuildNames() []string {
names := make([]string, 0, len(t.Builders))
for name, _ := range t.Builders {
names = append(names, name)
} }
return names // Build returns a Build for the given name.
} //
// If the build does not exist as part of this template, an error is
// returned.
func (t *Template) Build(name string, components *ComponentFinder) (b Build, err error) {
// Setup the Builder
builderConfig, ok := t.Builders[name]
if !ok {
err = fmt.Errorf("No such build found in template: %s", name)
return
}
// Build returns a Build for the given name. // We panic if there is no builder function because this is really
// // an internal bug that always needs to be fixed, not an error.
// If the build does not exist as part of this template, an error is if components.Builder == nil {
// returned. panic("no builder function")
func (t *Template) Build(name string, components *ComponentFinder) (b Build, err error) { }
// Setup the Builder
builderConfig, ok := t.Builders[name]
if !ok {
err = fmt.Errorf("No such build found in template: %s", name)
return
}
// We panic if there is no builder function because this is really // Panic if there are provisioners on the template but no provisioner
// an internal bug that always needs to be fixed, not an error. // component finder. This is always an internal error, so we panic.
if components.Builder == nil { if len(t.Provisioners) > 0 && components.Provisioner == nil {
panic("no builder function") panic("no provisioner function")
} }
// Panic if there are provisioners on the template but no provisioner builder, err := components.Builder(builderConfig.Type)
// component finder. This is always an internal error, so we panic. if err != nil {
if len(t.Provisioners) > 0 && components.Provisioner == nil { return
panic("no provisioner function") }
}
builder, err := components.Builder(builderConfig.Type) if builder == nil {
if err != nil { err = fmt.Errorf("Builder type not found: %s", builderConfig.Type)
return return
} }
if builder == nil { // Gather the Hooks
err = fmt.Errorf("Builder type not found: %s", builderConfig.Type) hooks := make(map[string][]Hook)
return for tplEvent, tplHooks := range t.Hooks {
} curHooks := make([]Hook, 0, len(tplHooks))
// Gather the Hooks for _, hookName := range tplHooks {
hooks := make(map[string][]Hook) var hook Hook
for tplEvent, tplHooks := range t.Hooks { hook, err = components.Hook(hookName)
curHooks := make([]Hook, 0, len(tplHooks)) if err != nil {
return
}
for _, hookName := range tplHooks { if hook == nil {
var hook Hook err = fmt.Errorf("Hook not found: %s", hookName)
hook, err = components.Hook(hookName) return
if err != nil { }
return
}
if hook == nil { curHooks = append(curHooks, hook)
err = fmt.Errorf("Hook not found: %s", hookName)
return
} }
curHooks = append(curHooks, hook) hooks[tplEvent] = curHooks
} }
hooks[tplEvent] = curHooks // Prepare the post-processors
} postProcessors := make([][]coreBuildPostProcessor, 0, len(t.PostProcessors))
for _, rawPPs := range t.PostProcessors {
current := make([]coreBuildPostProcessor, len(rawPPs))
for i, rawPP := range rawPPs {
pp, err := components.PostProcessor(rawPP.Type)
if err != nil {
return nil, err
}
// Prepare the post-processors if pp == nil {
postProcessors := make([][]coreBuildPostProcessor, 0, len(t.PostProcessors)) return nil, fmt.Errorf("PostProcessor type not found: %s", rawPP.Type)
for _, rawPPs := range t.PostProcessors { }
current := make([]coreBuildPostProcessor, len(rawPPs))
for i, rawPP := range rawPPs {
pp, err := components.PostProcessor(rawPP.Type)
if err != nil {
return nil, err
}
if pp == nil { current[i] = coreBuildPostProcessor{
return nil, fmt.Errorf("PostProcessor type not found: %s", rawPP.Type) processor: pp,
processorType: rawPP.Type,
config: rawPP.rawConfig,
keepInputArtifact: rawPP.KeepInputArtifact,
}
} }
current[i] = coreBuildPostProcessor{ postProcessors = append(postProcessors, current)
processor: pp,
processorType: rawPP.Type,
config: rawPP.rawConfig,
keepInputArtifact: rawPP.KeepInputArtifact,
}
} }
postProcessors = append(postProcessors, current) // Prepare the provisioners
} provisioners := make([]coreBuildProvisioner, 0, len(t.Provisioners))
for _, rawProvisioner := range t.Provisioners {
// Prepare the provisioners var provisioner Provisioner
provisioners := make([]coreBuildProvisioner, 0, len(t.Provisioners)) provisioner, err = components.Provisioner(rawProvisioner.Type)
for _, rawProvisioner := range t.Provisioners { if err != nil {
var provisioner Provisioner return
provisioner, err = components.Provisioner(rawProvisioner.Type) }
if err != nil {
return
}
if provisioner == nil { if provisioner == nil {
err = fmt.Errorf("Provisioner type not found: %s", rawProvisioner.Type) err = fmt.Errorf("Provisioner type not found: %s", rawProvisioner.Type)
return return
} }
configs := make([]interface{}, 1, 2) configs := make([]interface{}, 1, 2)
configs[0] = rawProvisioner.rawConfig configs[0] = rawProvisioner.rawConfig
if rawProvisioner.Override != nil { if rawProvisioner.Override != nil {
if override, ok := rawProvisioner.Override[name]; ok { if override, ok := rawProvisioner.Override[name]; ok {
configs = append(configs, override) configs = append(configs, override)
}
} }
coreProv := coreBuildProvisioner{provisioner, configs}
provisioners = append(provisioners, coreProv)
} }
coreProv := coreBuildProvisioner{provisioner, configs} b = &coreBuild{
provisioners = append(provisioners, coreProv) name: name,
} builder: builder,
builderConfig: builderConfig.rawConfig,
builderType: builderConfig.Type,
hooks: hooks,
postProcessors: postProcessors,
provisioners: provisioners,
}
b = &coreBuild{ return
name: name,
builder: builder,
builderConfig: builderConfig.rawConfig,
builderType: builderConfig.Type,
hooks: hooks,
postProcessors: postProcessors,
provisioners: provisioners,
} }
return
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment