134 lines
3.5 KiB
Go
134 lines
3.5 KiB
Go
package hcl2template
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/packer/packer"
|
|
)
|
|
|
|
// A source field in an HCL file will load into the Source type.
|
|
//
|
|
type Source struct {
|
|
// Type of source; ex: virtualbox-iso
|
|
Type string
|
|
// Given name; if any
|
|
Name string
|
|
|
|
block *hcl.Block
|
|
}
|
|
|
|
func (p *Parser) decodeSource(block *hcl.Block) (*Source, hcl.Diagnostics) {
|
|
source := &Source{
|
|
Type: block.Labels[0],
|
|
Name: block.Labels[1],
|
|
block: block,
|
|
}
|
|
var diags hcl.Diagnostics
|
|
|
|
if !p.BuilderSchemas.Has(source.Type) {
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
Summary: "Unknown " + buildSourceLabel + " type " + source.Type,
|
|
Subject: block.LabelRanges[0].Ptr(),
|
|
Detail: fmt.Sprintf("known builders: %v", p.BuilderSchemas.List()),
|
|
Severity: hcl.DiagError,
|
|
})
|
|
return nil, diags
|
|
}
|
|
|
|
return source, diags
|
|
}
|
|
|
|
func (p *Parser) StartBuilder(source *Source) (packer.Builder, hcl.Diagnostics, []string) {
|
|
var diags hcl.Diagnostics
|
|
|
|
builder, err := p.BuilderSchemas.Start(source.Type)
|
|
if err != nil {
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
Summary: "Failed to load " + sourceLabel + " type",
|
|
Detail: err.Error(),
|
|
Subject: &source.block.LabelRanges[0],
|
|
})
|
|
return builder, diags, nil
|
|
}
|
|
|
|
decoded, moreDiags := decodeHCL2Spec(source.block.Body, nil, builder)
|
|
diags = append(diags, moreDiags...)
|
|
if moreDiags.HasErrors() {
|
|
return nil, diags, nil
|
|
}
|
|
|
|
generatedVars, warning, err := builder.Prepare(decoded)
|
|
moreDiags = warningErrorsToDiags(source.block, warning, err)
|
|
diags = append(diags, moreDiags...)
|
|
return builder, diags, generatedVars
|
|
}
|
|
|
|
func (source *Source) Ref() SourceRef {
|
|
return SourceRef{
|
|
Type: source.Type,
|
|
Name: source.Name,
|
|
}
|
|
}
|
|
|
|
type SourceRef struct {
|
|
Type string
|
|
Name string
|
|
}
|
|
|
|
// NoSource is the zero value of sourceRef, representing the absense of an
|
|
// source.
|
|
var NoSource SourceRef
|
|
|
|
func sourceRefFromAbsTraversal(t hcl.Traversal) (SourceRef, hcl.Diagnostics) {
|
|
var diags hcl.Diagnostics
|
|
if len(t) != 3 {
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Invalid " + sourceLabel + " reference",
|
|
Detail: "A " + sourceLabel + " reference must have three parts separated by periods: the keyword \"" + sourceLabel + "\", the builder type name, and the source name.",
|
|
Subject: t.SourceRange().Ptr(),
|
|
})
|
|
return NoSource, diags
|
|
}
|
|
|
|
if t.RootName() != sourceLabel {
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Invalid " + sourceLabel + " reference",
|
|
Detail: "The first part of an source reference must be the keyword \"" + sourceLabel + "\".",
|
|
Subject: t[0].SourceRange().Ptr(),
|
|
})
|
|
return NoSource, diags
|
|
}
|
|
btStep, ok := t[1].(hcl.TraverseAttr)
|
|
if !ok {
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Invalid " + sourceLabel + " reference",
|
|
Detail: "The second part of an " + sourceLabel + " reference must be an identifier giving the builder type of the " + sourceLabel + ".",
|
|
Subject: t[1].SourceRange().Ptr(),
|
|
})
|
|
return NoSource, diags
|
|
}
|
|
nameStep, ok := t[2].(hcl.TraverseAttr)
|
|
if !ok {
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Invalid " + sourceLabel + " reference",
|
|
Detail: "The third part of an " + sourceLabel + " reference must be an identifier giving the name of the " + sourceLabel + ".",
|
|
Subject: t[2].SourceRange().Ptr(),
|
|
})
|
|
return NoSource, diags
|
|
}
|
|
|
|
return SourceRef{
|
|
Type: btStep.Name,
|
|
Name: nameStep.Name,
|
|
}, diags
|
|
}
|
|
|
|
func (r SourceRef) String() string {
|
|
return fmt.Sprintf("%s.%s", r.Type, r.Name)
|
|
}
|