get builds from PackerConfig instead of parser

to allow just reading the config and to not start anything. This will allow to later on run `validate --syntax-only`.

Note that none of the builder/provisioner/post-processor config will be read but simply ignored. HCL2 still needs the body to be properly formatted and it should detect most syntax errors.
This commit is contained in:
Adrien Delorme 2020-04-29 16:36:40 +02:00
parent 2df21496b3
commit 5c2b8da63b
5 changed files with 59 additions and 67 deletions

View File

@ -104,7 +104,7 @@ func (c *BuildCommand) GetBuildsFromHCL(path string) ([]packer.Build, int) {
PostProcessorsSchemas: c.CoreConfig.Components.PostProcessorStore,
}
builds, diags := parser.Parse(path, c.varFiles, c.flagVars, c.CoreConfig.Only, c.CoreConfig.Except)
cfg, diags := parser.Parse(path, c.varFiles, c.flagVars)
{
// write HCL errors/diagnostics if any.
b := bytes.NewBuffer(nil)
@ -122,6 +122,24 @@ func (c *BuildCommand) GetBuildsFromHCL(path string) ([]packer.Build, int) {
ret = 1
}
builds, diags := cfg.GetBuilds(c.CoreConfig.Only, c.CoreConfig.Except)
{
// write HCL errors/diagnostics if any.
b := bytes.NewBuffer(nil)
err := hcl.NewDiagnosticTextWriter(b, parser.Files(), 80, false).WriteDiagnostics(diags)
if err != nil {
c.Ui.Error("could not write diagnostic: " + err.Error())
return nil, 1
}
if b.Len() != 0 {
c.Ui.Message(b.String())
}
}
ret = 0
if diags.HasErrors() {
ret = 1
}
return builds, ret
}

View File

@ -59,7 +59,7 @@ func testParse(t *testing.T, tests []parseTest) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotCfg, gotDiags := tt.parser.parse(tt.args.filename, tt.args.varFiles, tt.args.vars)
gotCfg, gotDiags := tt.parser.Parse(tt.args.filename, tt.args.varFiles, tt.args.vars)
if tt.parseWantDiags == (gotDiags == nil) {
t.Fatalf("Parser.parse() unexpected %q diagnostics.", gotDiags)
}
@ -116,7 +116,7 @@ func testParse(t *testing.T, tests []parseTest) {
return
}
gotBuilds, gotDiags := gotCfg.getBuilds(nil, nil)
gotBuilds, gotDiags := gotCfg.GetBuilds(nil, nil)
if tt.getBuildsWantDiags == (gotDiags == nil) {
t.Fatalf("Parser.getBuilds() unexpected diagnostics. %s", gotDiags)
}

View File

@ -52,7 +52,11 @@ const (
hcl2VarJsonFileExt = ".auto.pkrvars.json"
)
func (p *Parser) parse(filename string, varFiles []string, argVars map[string]string) (*PackerConfig, hcl.Diagnostics) {
// Parse will Parse HCL file(s) in path. Path can be a folder or a file.
//
// Parse will first Parse variables and then the rest; so that interpolation
// can happen.
func (p *Parser) Parse(filename string, varFiles []string, argVars map[string]string) (*PackerConfig, hcl.Diagnostics) {
var files []*hcl.File
var diags hcl.Diagnostics

View File

@ -7,8 +7,6 @@ import (
"github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/packer"
"github.com/zclconf/go-cty/cty"
"github.com/gobwas/glob"
)
// PackerConfig represents a loaded Packer HCL config. It will contain
@ -253,10 +251,10 @@ func (cfg *PackerConfig) getCoreBuildPostProcessors(source *SourceBlock, blocks
return res, diags
}
// getBuilds will return a list of packer Build based on the HCL2 parsed build
// GetBuilds returns a list of packer Build based on the HCL2 parsed build
// blocks. All Builders, Provisioners and Post Processors will be started and
// configured.
func (cfg *PackerConfig) getBuilds(onlyGlobs []glob.Glob, exceptGlobs []glob.Glob) ([]packer.Build, hcl.Diagnostics) {
func (cfg *PackerConfig) GetBuilds(only, except []string) ([]packer.Build, hcl.Diagnostics) {
res := []packer.Build{}
var diags hcl.Diagnostics
@ -276,7 +274,11 @@ func (cfg *PackerConfig) getBuilds(onlyGlobs []glob.Glob, exceptGlobs []glob.Glo
buildName := fmt.Sprintf("%s.%s", src.Type, src.Name)
// -only
if len(onlyGlobs) > 0 {
if len(only) > 0 {
onlyGlobs, diags := convertFilterOption(only, "only")
if diags.HasErrors() {
return nil, diags
}
include := false
for _, onlyGlob := range onlyGlobs {
if onlyGlob.Match(buildName) {
@ -290,7 +292,11 @@ func (cfg *PackerConfig) getBuilds(onlyGlobs []glob.Glob, exceptGlobs []glob.Glo
}
// -except
if len(exceptGlobs) > 0 {
if len(except) > 0 {
exceptGlobs, diags := convertFilterOption(except, "except")
if diags.HasErrors() {
return nil, diags
}
exclude := false
for _, exceptGlob := range exceptGlobs {
if exceptGlob.Match(buildName) {
@ -356,60 +362,3 @@ func (cfg *PackerConfig) getBuilds(onlyGlobs []glob.Glob, exceptGlobs []glob.Glo
}
return res, diags
}
// Convert -only and -except globs to glob.Glob instances.
func convertFilterOption(patterns []string, optionName string) ([]glob.Glob, hcl.Diagnostics) {
var globs []glob.Glob
var diags hcl.Diagnostics
for _, pattern := range patterns {
g, err := glob.Compile(pattern)
if err != nil {
diags = append(diags, &hcl.Diagnostic{
Summary: fmt.Sprintf("Invalid -%s pattern %s: %s", optionName, pattern, err),
Severity: hcl.DiagError,
})
}
globs = append(globs, g)
}
return globs, diags
}
// Parse will parse HCL file(s) in path. Path can be a folder or a file.
//
// Parse will first parse variables and then the rest; so that interpolation
// can happen.
//
// For each build block a packer.Build will be started, and for each builder,
// all provisioners and post-processors will be started.
//
// Parse then return a slice of packer.Builds; which are what packer core uses
// to run builds.
func (p *Parser) Parse(path string, varFiles []string, argVars map[string]string, onlyBuilds []string, exceptBuilds []string) ([]packer.Build, hcl.Diagnostics) {
var onlyGlobs []glob.Glob
if len(onlyBuilds) > 0 {
og, diags := convertFilterOption(onlyBuilds, "only")
if diags.HasErrors() {
return nil, diags
}
onlyGlobs = og
}
var exceptGlobs []glob.Glob
if len(exceptBuilds) > 0 {
eg, diags := convertFilterOption(exceptBuilds, "except")
if diags.HasErrors() {
return nil, diags
}
exceptGlobs = eg
}
cfg, diags := p.parse(path, varFiles, argVars)
if diags.HasErrors() {
return nil, diags
}
builds, moreDiags := cfg.getBuilds(onlyGlobs, exceptGlobs)
return builds, append(diags, moreDiags...)
}

View File

@ -1,11 +1,13 @@
package hcl2template
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/gobwas/glob"
"github.com/hashicorp/hcl/v2"
)
@ -88,3 +90,22 @@ func GetHCL2Files(filename, hclSuffix, jsonSuffix string) (hclFiles, jsonFiles [
return hclFiles, jsonFiles, diags
}
// Convert -only and -except globs to glob.Glob instances.
func convertFilterOption(patterns []string, optionName string) ([]glob.Glob, hcl.Diagnostics) {
var globs []glob.Glob
var diags hcl.Diagnostics
for _, pattern := range patterns {
g, err := glob.Compile(pattern)
if err != nil {
diags = append(diags, &hcl.Diagnostic{
Summary: fmt.Sprintf("Invalid -%s pattern %s: %s", optionName, pattern, err),
Severity: hcl.DiagError,
})
}
globs = append(globs, g)
}
return globs, diags
}