135 lines
3.2 KiB
Go
135 lines
3.2 KiB
Go
package hcl2template
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/hcl/v2/hclparse"
|
|
"github.com/hashicorp/packer/packer"
|
|
)
|
|
|
|
const (
|
|
sourceLabel = "source"
|
|
variablesLabel = "variables"
|
|
buildLabel = "build"
|
|
communicatorLabel = "communicator"
|
|
)
|
|
|
|
var configSchema = &hcl.BodySchema{
|
|
Blocks: []hcl.BlockHeaderSchema{
|
|
{Type: sourceLabel, LabelNames: []string{"type", "name"}},
|
|
{Type: variablesLabel},
|
|
{Type: buildLabel},
|
|
{Type: communicatorLabel, LabelNames: []string{"type", "name"}},
|
|
},
|
|
}
|
|
|
|
type Parser struct {
|
|
*hclparse.Parser
|
|
|
|
BuilderSchemas packer.BuilderStore
|
|
|
|
ProvisionersSchemas packer.ProvisionerStore
|
|
|
|
PostProcessorsSchemas packer.PostProcessorStore
|
|
}
|
|
|
|
const (
|
|
hcl2FileExt = ".pkr.hcl"
|
|
hcl2JsonFileExt = ".pkr.json"
|
|
)
|
|
|
|
func (p *Parser) parse(filename string) (*PackerConfig, hcl.Diagnostics) {
|
|
|
|
hclFiles, jsonFiles, diags := GetHCL2Files(filename)
|
|
|
|
var files []*hcl.File
|
|
for _, filename := range hclFiles {
|
|
f, moreDiags := p.ParseHCLFile(filename)
|
|
diags = append(diags, moreDiags...)
|
|
files = append(files, f)
|
|
}
|
|
for _, filename := range jsonFiles {
|
|
f, moreDiags := p.ParseJSONFile(filename)
|
|
diags = append(diags, moreDiags...)
|
|
files = append(files, f)
|
|
}
|
|
if diags.HasErrors() {
|
|
return nil, diags
|
|
}
|
|
|
|
cfg := &PackerConfig{}
|
|
for _, file := range files {
|
|
moreDiags := p.parseFile(file, cfg)
|
|
diags = append(diags, moreDiags...)
|
|
}
|
|
|
|
return cfg, diags
|
|
}
|
|
|
|
// parseFile filename content into cfg.
|
|
//
|
|
// parseFile may be called multiple times with the same cfg on a different file.
|
|
//
|
|
// parseFile returns as complete a config as we can manage, even if there are
|
|
// errors, since a partial result can be useful for careful analysis by
|
|
// development tools such as text editor extensions.
|
|
func (p *Parser) parseFile(f *hcl.File, cfg *PackerConfig) hcl.Diagnostics {
|
|
var diags hcl.Diagnostics
|
|
|
|
content, moreDiags := f.Body.Content(configSchema)
|
|
diags = append(diags, moreDiags...)
|
|
|
|
for _, block := range content.Blocks {
|
|
switch block.Type {
|
|
case sourceLabel:
|
|
source, moreDiags := p.decodeSource(block)
|
|
diags = append(diags, moreDiags...)
|
|
if moreDiags.HasErrors() {
|
|
continue
|
|
}
|
|
|
|
ref := source.Ref()
|
|
if existing := cfg.Sources[ref]; existing != nil {
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Duplicate " + sourceLabel + " block",
|
|
Detail: fmt.Sprintf("This "+sourceLabel+" block has the "+
|
|
"same builder type and name as a previous block declared "+
|
|
"at %s. Each "+sourceLabel+" must have a unique name per builder type.",
|
|
existing.block.DefRange.Ptr()),
|
|
Subject: source.block.DefRange.Ptr(),
|
|
})
|
|
continue
|
|
}
|
|
|
|
if cfg.Sources == nil {
|
|
cfg.Sources = map[SourceRef]*Source{}
|
|
}
|
|
cfg.Sources[ref] = source
|
|
|
|
case variablesLabel:
|
|
if cfg.Variables == nil {
|
|
cfg.Variables = PackerV1Variables{}
|
|
}
|
|
|
|
moreDiags := cfg.Variables.decodeConfig(block)
|
|
if moreDiags.HasErrors() {
|
|
continue
|
|
}
|
|
diags = append(diags, moreDiags...)
|
|
|
|
case buildLabel:
|
|
build, moreDiags := p.decodeBuildConfig(block)
|
|
diags = append(diags, moreDiags...)
|
|
if moreDiags.HasErrors() {
|
|
continue
|
|
}
|
|
cfg.Builds = append(cfg.Builds, build)
|
|
|
|
}
|
|
}
|
|
|
|
return diags
|
|
}
|