packer-cn/hcl2template/types.build.go

166 lines
4.5 KiB
Go

package hcl2template
import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsyntax"
)
const (
buildFromLabel = "from"
buildSourceLabel = "source"
buildProvisionerLabel = "provisioner"
buildPostProcessorLabel = "post-processor"
buildPostProcessorsLabel = "post-processors"
)
var buildSchema = &hcl.BodySchema{
Blocks: []hcl.BlockHeaderSchema{
{Type: buildFromLabel, LabelNames: []string{"type"}},
{Type: sourceLabel, LabelNames: []string{"reference"}},
{Type: buildProvisionerLabel, LabelNames: []string{"type"}},
{Type: buildPostProcessorLabel, LabelNames: []string{"type"}},
{Type: buildPostProcessorsLabel, LabelNames: []string{}},
},
}
var postProcessorsSchema = &hcl.BodySchema{
Blocks: []hcl.BlockHeaderSchema{
{Type: buildPostProcessorLabel, LabelNames: []string{"type"}},
},
}
// BuildBlock references an HCL 'build' block and it content, for example :
//
// build {
// sources = [
// ...
// ]
// provisioner "" { ... }
// post-processor "" { ... }
// }
type BuildBlock struct {
// Name is a string representing the named build to show in the logs
Name string
// A description of what this build does, it could be used in a inspect
// call for example.
Description string
// Sources is the list of sources that we want to start in this build block.
Sources []SourceRef
// ProvisionerBlocks references a list of HCL provisioner block that will
// will be ran against the sources.
ProvisionerBlocks []*ProvisionerBlock
// PostProcessorLists references the lists of lists of HCL post-processors
// block that will be run against the artifacts from the provisioning
// steps.
PostProcessorsLists [][]*PostProcessorBlock
HCL2Ref HCL2Ref
}
type Builds []*BuildBlock
// decodeBuildConfig is called when a 'build' block has been detected. It will
// load the references to the contents of the build block.
func (p *Parser) decodeBuildConfig(block *hcl.Block, cfg *PackerConfig) (*BuildBlock, hcl.Diagnostics) {
build := &BuildBlock{}
var b struct {
Name string `hcl:"name,optional"`
Description string `hcl:"description,optional"`
FromSources []string `hcl:"sources,optional"`
Config hcl.Body `hcl:",remain"`
}
diags := gohcl.DecodeBody(block.Body, nil, &b)
if diags.HasErrors() {
return nil, diags
}
build.Name = b.Name
build.Description = b.Description
for _, buildFrom := range b.FromSources {
ref := sourceRefFromString(buildFrom)
if ref == NoSource ||
!hclsyntax.ValidIdentifier(ref.Type) ||
!hclsyntax.ValidIdentifier(ref.Name) {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid " + sourceLabel + " reference",
Detail: "A " + sourceLabel + " type is made of three parts that are" +
"split by a dot `.`; each part must start with a letter and " +
"may contain only letters, digits, underscores, and dashes." +
"A valid source reference looks like: `source.type.name`",
Subject: block.DefRange.Ptr(),
})
continue
}
build.Sources = append(build.Sources, ref)
}
content, moreDiags := b.Config.Content(buildSchema)
diags = append(diags, moreDiags...)
if diags.HasErrors() {
return nil, diags
}
for _, block := range content.Blocks {
switch block.Type {
case sourceLabel:
ref, moreDiags := p.decodeBuildSource(block)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
continue
}
build.Sources = append(build.Sources, ref)
case buildProvisionerLabel:
p, moreDiags := p.decodeProvisioner(block, cfg)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
continue
}
build.ProvisionerBlocks = append(build.ProvisionerBlocks, p)
case buildPostProcessorLabel:
pp, moreDiags := p.decodePostProcessor(block)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
continue
}
build.PostProcessorsLists = append(build.PostProcessorsLists, []*PostProcessorBlock{pp})
case buildPostProcessorsLabel:
content, moreDiags := block.Body.Content(postProcessorsSchema)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
continue
}
errored := false
postProcessors := []*PostProcessorBlock{}
for _, block := range content.Blocks {
pp, moreDiags := p.decodePostProcessor(block)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
errored = true
break
}
postProcessors = append(postProcessors, pp)
}
if errored == false {
build.PostProcessorsLists = append(build.PostProcessorsLists, postProcessors)
}
}
}
return build, diags
}