From 0b896a0ce2d274f18fc4efc5d2ce3ed7dbd9dba5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 13 Jun 2013 10:03:44 -0700 Subject: [PATCH] command/validate: validates templates --- command/validate/commang.go | 87 +++++++++++++++++++++++++++++++++ command/validate/help.go | 16 ++++++ config.go | 3 +- plugin/command-validate/main.go | 10 ++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 command/validate/commang.go create mode 100644 command/validate/help.go create mode 100644 plugin/command-validate/main.go diff --git a/command/validate/commang.go b/command/validate/commang.go new file mode 100644 index 000000000..05bfb8e55 --- /dev/null +++ b/command/validate/commang.go @@ -0,0 +1,87 @@ +package validate + +import ( + "flag" + "fmt" + "github.com/mitchellh/packer/packer" + "io/ioutil" + "log" + "strings" +) + +type Command byte + +func (Command) Help() string { + return strings.TrimSpace(helpString) +} + +func (c Command) Run(env packer.Environment, args []string) int { + var cfgSyntaxOnly bool + + cmdFlags := flag.NewFlagSet("validate", flag.ContinueOnError) + cmdFlags.Usage = func() { env.Ui().Say(c.Help()) } + cmdFlags.BoolVar(&cfgSyntaxOnly, "syntax-only", false, "check syntax only") + if err := cmdFlags.Parse(args); err != nil { + return 1 + } + + args = cmdFlags.Args() + if len(args) != 1 { + cmdFlags.Usage() + return 1 + } + + // Read the file into a byte array so that we can parse the template + log.Printf("Reading template: %s", args[0]) + tplData, err := ioutil.ReadFile(args[0]) + if err != nil { + env.Ui().Error(fmt.Sprintf("Failed to read template file: %s", err)) + return 1 + } + + // Parse the template into a machine-usable format + log.Println("Parsing template...") + tpl, err := packer.ParseTemplate(tplData) + if err != nil { + env.Ui().Error(fmt.Sprintf("Failed to parse template: %s", err)) + return 1 + } + + if cfgSyntaxOnly { + env.Ui().Say("Syntax-only check passed. Everything looks okay.") + return 0 + } + + errs := make([]error, 0) + + // The component finder for our builds + components := &packer.ComponentFinder{ + Builder: env.Builder, + Hook: env.Hook, + Provisioner: env.Provisioner, + } + + // Otherwise, get all the builds + buildNames := tpl.BuildNames() + builds := make([]packer.Build, len(buildNames)) + for i, buildName := range buildNames { + var err error + builds[i], err = tpl.Build(buildName, components) + if err != nil { + errs = append(errs, fmt.Errorf("Build '%s': %s", buildName, err)) + } + } + + if len(errs) > 0 { + err = &packer.MultiError{errs} + env.Ui().Error(fmt.Sprintf("Template validation failed. %s", err)) + return 1 + } + + env.Ui().Say("Template validated successfully.") + return 0 +} + +func (Command) Synopsis() string { + return "check that a template is valid" +} diff --git a/command/validate/help.go b/command/validate/help.go new file mode 100644 index 000000000..73ca004a3 --- /dev/null +++ b/command/validate/help.go @@ -0,0 +1,16 @@ +package validate + +const helpString = ` +Usage: packer validate TEMPLATE + + Checks the template is valid by parsing the template and also + checking the configuration with the various builders, provisioners, etc. + + If it is not valid, the errors will be shown and the command will exit + with a non-zero exit status. If it is valid, it will exit with a zero + exit status. + +Options: + + -syntax-only Only check syntax. Do not verify config of the template. +` diff --git a/config.go b/config.go index f92a6126e..efe088d53 100644 --- a/config.go +++ b/config.go @@ -23,7 +23,8 @@ const defaultConfig = ` }, "commands": { - "build": "packer-command-build" + "build": "packer-command-build", + "validate": "packer-command-validate" }, "provisioners": { diff --git a/plugin/command-validate/main.go b/plugin/command-validate/main.go new file mode 100644 index 000000000..af093294e --- /dev/null +++ b/plugin/command-validate/main.go @@ -0,0 +1,10 @@ +package main + +import ( + "github.com/mitchellh/packer/command/validate" + "github.com/mitchellh/packer/packer/plugin" +) + +func main() { + plugin.ServeCommand(new(validate.Command)) +}