github.com/kaixiang/packer@v0.5.2-0.20140114230416-1f5786b0d7f1/command/validate/command.go (about)

     1  package validate
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	cmdcommon "github.com/mitchellh/packer/common/command"
     7  	"github.com/mitchellh/packer/packer"
     8  	"log"
     9  	"strings"
    10  )
    11  
    12  type Command byte
    13  
    14  func (Command) Help() string {
    15  	return strings.TrimSpace(helpString)
    16  }
    17  
    18  func (c Command) Run(env packer.Environment, args []string) int {
    19  	var cfgSyntaxOnly bool
    20  	buildOptions := new(cmdcommon.BuildOptions)
    21  
    22  	cmdFlags := flag.NewFlagSet("validate", flag.ContinueOnError)
    23  	cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
    24  	cmdFlags.BoolVar(&cfgSyntaxOnly, "syntax-only", false, "check syntax only")
    25  	cmdcommon.BuildOptionFlags(cmdFlags, buildOptions)
    26  	if err := cmdFlags.Parse(args); err != nil {
    27  		return 1
    28  	}
    29  
    30  	args = cmdFlags.Args()
    31  	if len(args) != 1 {
    32  		cmdFlags.Usage()
    33  		return 1
    34  	}
    35  
    36  	if err := buildOptions.Validate(); err != nil {
    37  		env.Ui().Error(err.Error())
    38  		env.Ui().Error("")
    39  		env.Ui().Error(c.Help())
    40  		return 1
    41  	}
    42  
    43  	userVars, err := buildOptions.AllUserVars()
    44  	if err != nil {
    45  		env.Ui().Error(fmt.Sprintf("Error compiling user variables: %s", err))
    46  		env.Ui().Error("")
    47  		env.Ui().Error(c.Help())
    48  		return 1
    49  	}
    50  
    51  	// Parse the template into a machine-usable format
    52  	log.Printf("Reading template: %s", args[0])
    53  	tpl, err := packer.ParseTemplateFile(args[0], userVars)
    54  	if err != nil {
    55  		env.Ui().Error(fmt.Sprintf("Failed to parse template: %s", err))
    56  		return 1
    57  	}
    58  
    59  	if cfgSyntaxOnly {
    60  		env.Ui().Say("Syntax-only check passed. Everything looks okay.")
    61  		return 0
    62  	}
    63  
    64  	errs := make([]error, 0)
    65  	warnings := make(map[string][]string)
    66  
    67  	// The component finder for our builds
    68  	components := &packer.ComponentFinder{
    69  		Builder:       env.Builder,
    70  		Hook:          env.Hook,
    71  		PostProcessor: env.PostProcessor,
    72  		Provisioner:   env.Provisioner,
    73  	}
    74  
    75  	// Otherwise, get all the builds
    76  	builds, err := buildOptions.Builds(tpl, components)
    77  	if err != nil {
    78  		env.Ui().Error(err.Error())
    79  		return 1
    80  	}
    81  
    82  	// Check the configuration of all builds
    83  	for _, b := range builds {
    84  		log.Printf("Preparing build: %s", b.Name())
    85  		warns, err := b.Prepare()
    86  		if len(warns) > 0 {
    87  			warnings[b.Name()] = warns
    88  		}
    89  		if err != nil {
    90  			errs = append(errs, fmt.Errorf("Errors validating build '%s'. %s", b.Name(), err))
    91  		}
    92  	}
    93  
    94  	if len(errs) > 0 {
    95  		env.Ui().Error("Template validation failed. Errors are shown below.\n")
    96  		for i, err := range errs {
    97  			env.Ui().Error(err.Error())
    98  
    99  			if (i + 1) < len(errs) {
   100  				env.Ui().Error("")
   101  			}
   102  		}
   103  
   104  		return 1
   105  	}
   106  
   107  	if len(warnings) > 0 {
   108  		env.Ui().Say("Template validation succeeded, but there were some warnings.")
   109  		env.Ui().Say("These are ONLY WARNINGS, and Packer will attempt to build the")
   110  		env.Ui().Say("template despite them, but they should be paid attention to.\n")
   111  
   112  		for build, warns := range warnings {
   113  			env.Ui().Say(fmt.Sprintf("Warnings for build '%s':\n", build))
   114  			for _, warning := range warns {
   115  				env.Ui().Say(fmt.Sprintf("* %s", warning))
   116  			}
   117  		}
   118  
   119  		return 0
   120  	}
   121  
   122  	env.Ui().Say("Template validated successfully.")
   123  	return 0
   124  }
   125  
   126  func (Command) Synopsis() string {
   127  	return "check that a template is valid"
   128  }