2019-10-14 11:02:53 -04:00
|
|
|
package hcl2template
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
2019-10-15 05:34:26 -04:00
|
|
|
)
|
2019-10-14 11:02:53 -04:00
|
|
|
|
|
|
|
type Artifacts map[ArtifactRef]*Artifact
|
|
|
|
|
|
|
|
type Artifact struct {
|
|
|
|
Type string
|
|
|
|
Name string
|
|
|
|
|
|
|
|
DeclRange hcl.Range
|
|
|
|
|
|
|
|
Config hcl.Body
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Artifact) Ref() ArtifactRef {
|
|
|
|
return ArtifactRef{
|
|
|
|
Type: a.Type,
|
|
|
|
Name: a.Name,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type ArtifactRef struct {
|
|
|
|
Type string
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
// NoArtifact is the zero value of ArtifactRef, representing the absense of an
|
|
|
|
// artifact.
|
|
|
|
var NoArtifact ArtifactRef
|
|
|
|
|
|
|
|
func artifactRefFromAbsTraversal(t hcl.Traversal) (ArtifactRef, hcl.Diagnostics) {
|
|
|
|
var diags hcl.Diagnostics
|
|
|
|
if len(t) != 3 {
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
Summary: "Invalid artifact reference",
|
|
|
|
Detail: "An artifact reference must have three parts separated by periods: the keyword \"artifact\", the builder type name, and the artifact name.",
|
|
|
|
Subject: t.SourceRange().Ptr(),
|
|
|
|
})
|
|
|
|
return NoArtifact, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
if t.RootName() != "artifact" {
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
Summary: "Invalid artifact reference",
|
|
|
|
Detail: "The first part of an artifact reference must be the keyword \"artifact\".",
|
|
|
|
Subject: t[0].SourceRange().Ptr(),
|
|
|
|
})
|
|
|
|
return NoArtifact, diags
|
|
|
|
}
|
|
|
|
btStep, ok := t[1].(hcl.TraverseAttr)
|
|
|
|
if !ok {
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
Summary: "Invalid artifact reference",
|
|
|
|
Detail: "The second part of an artifact reference must be an identifier giving the builder type of the artifact.",
|
|
|
|
Subject: t[1].SourceRange().Ptr(),
|
|
|
|
})
|
|
|
|
return NoArtifact, diags
|
|
|
|
}
|
|
|
|
nameStep, ok := t[2].(hcl.TraverseAttr)
|
|
|
|
if !ok {
|
|
|
|
diags = append(diags, &hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
Summary: "Invalid artifact reference",
|
|
|
|
Detail: "The third part of an artifact reference must be an identifier giving the name of the artifact.",
|
|
|
|
Subject: t[2].SourceRange().Ptr(),
|
|
|
|
})
|
|
|
|
return NoArtifact, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
return ArtifactRef{
|
|
|
|
Type: btStep.Name,
|
|
|
|
Name: nameStep.Name,
|
|
|
|
}, diags
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r ArtifactRef) String() string {
|
|
|
|
return fmt.Sprintf("%s.%s", r.Type, r.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// decodeBodyWithoutSchema is a generic alternative to hcldec.Decode that
|
|
|
|
// just extracts whatever attributes are present and rejects any nested blocks,
|
|
|
|
// for compatibility with legacy builders that can't provide explicit schema.
|
|
|
|
func decodeBodyWithoutSchema(body hcl.Body, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|
|
|
attrs, diags := body.JustAttributes()
|
|
|
|
vals := make(map[string]cty.Value)
|
|
|
|
for name, attr := range attrs {
|
|
|
|
val, moreDiags := attr.Expr.Value(ctx)
|
|
|
|
diags = append(diags, moreDiags...)
|
|
|
|
vals[name] = val
|
|
|
|
}
|
|
|
|
return cty.ObjectVal(vals), diags
|
|
|
|
}
|