buildx/util/buildflags/export_cty.go
Jonathan A. Sternberg abc85c38f8
buildflags: handle unknown values from cty
Update the buildflags cty code to handle unknown values. When hcl
decodes a value with an invalid variable name, it appends a diagnostic
for the error and then returns an unknown value so it can continue
processing the file and finding more errors.

The iteration code has now been changed to use a rangefunc from go 1.23
and it skips empty or unknown values. Empty values are valid when they
are skipped and unknown values will have a diagnostic for itself.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2025-02-06 09:45:18 -06:00

85 lines
1.8 KiB
Go

package buildflags
import (
"sync"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
)
var exportEntryType = sync.OnceValue(func() cty.Type {
return cty.Map(cty.String)
})
func (e *Exports) FromCtyValue(in cty.Value, p cty.Path) error {
got := in.Type()
if got.IsTupleType() || got.IsListType() {
return e.fromCtyValue(in, p)
}
want := cty.List(exportEntryType())
return p.NewErrorf("%s", convert.MismatchMessage(got, want))
}
func (e *Exports) fromCtyValue(in cty.Value, p cty.Path) error {
*e = make([]*ExportEntry, 0, in.LengthInt())
for value := range eachElement(in) {
entry := &ExportEntry{}
if err := entry.FromCtyValue(value, p); err != nil {
return err
}
*e = append(*e, entry)
}
return nil
}
func (e Exports) ToCtyValue() cty.Value {
if len(e) == 0 {
return cty.ListValEmpty(exportEntryType())
}
vals := make([]cty.Value, len(e))
for i, entry := range e {
vals[i] = entry.ToCtyValue()
}
return cty.ListVal(vals)
}
func (e *ExportEntry) FromCtyValue(in cty.Value, p cty.Path) error {
if in.Type() == cty.String {
if err := e.UnmarshalText([]byte(in.AsString())); err != nil {
return p.NewError(err)
}
return nil
}
conv, err := convert.Convert(in, cty.Map(cty.String))
if err != nil {
return err
}
m := conv.AsValueMap()
if err := getAndDelete(m, "type", &e.Type); err != nil {
return err
}
if err := getAndDelete(m, "dest", &e.Destination); err != nil {
return err
}
e.Attrs = asMap(m)
return e.validate()
}
func (e *ExportEntry) ToCtyValue() cty.Value {
if e == nil {
return cty.NullVal(cty.Map(cty.String))
}
vals := make(map[string]cty.Value, len(e.Attrs)+2)
for k, v := range e.Attrs {
vals[k] = cty.StringVal(v)
}
vals["type"] = cty.StringVal(e.Type)
vals["dest"] = cty.StringVal(e.Destination)
return cty.MapVal(vals)
}