command.go 2.44 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
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{
59 60 61 62
		Builder:       env.Builder,
		Hook:          env.Hook,
		PostProcessor: env.PostProcessor,
		Provisioner:   env.Provisioner,
63 64 65 66
	}

	// Otherwise, get all the builds
	buildNames := tpl.BuildNames()
67
	builds := make([]packer.Build, 0, len(buildNames))
68
	for _, buildName := range buildNames {
69
		log.Printf("Creating build from template for: %s", buildName)
70
		build, err := tpl.Build(buildName, components)
71 72
		if err != nil {
			errs = append(errs, fmt.Errorf("Build '%s': %s", buildName, err))
73
			continue
74
		}
75 76

		builds = append(builds, build)
77 78
	}

79 80
	// Check the configuration of all builds
	for _, b := range builds {
81
		log.Printf("Preparing build: %s", b.Name())
82
		err := b.Prepare(nil)
83 84 85 86
		if err != nil {
			errs = append(errs, fmt.Errorf("Errors validating build '%s'. %s", b.Name(), err))
		}
	}
87

88
	if len(errs) > 0 {
89 90 91 92
		env.Ui().Error("Template validation failed. Errors are shown below.\n")
		for i, err := range errs {
			env.Ui().Error(err.Error())

Mitchell Hashimoto's avatar
fmt  
Mitchell Hashimoto committed
93
			if (i + 1) < len(errs) {
94 95 96 97
				env.Ui().Error("")
			}
		}

98 99 100 101 102 103 104 105 106 107
		return 1
	}

	env.Ui().Say("Template validated successfully.")
	return 0
}

func (Command) Synopsis() string {
	return "check that a template is valid"
}