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>
This commit is contained in:
Jonathan A. Sternberg
2025-02-06 09:45:18 -06:00
parent b76fdcaf8d
commit abc85c38f8
9 changed files with 88 additions and 43 deletions

View File

@ -1,6 +1,8 @@
package buildflags
import (
"iter"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
)
@ -34,7 +36,7 @@ func removeDupes[E comparable[E]](s []E) []E {
}
func getAndDelete(m map[string]cty.Value, attr string, gv interface{}) error {
if v, ok := m[attr]; ok {
if v, ok := m[attr]; ok && v.IsKnown() {
delete(m, attr)
return gocty.FromCtyValue(v, gv)
}
@ -44,11 +46,28 @@ func getAndDelete(m map[string]cty.Value, attr string, gv interface{}) error {
func asMap(m map[string]cty.Value) map[string]string {
out := make(map[string]string, len(m))
for k, v := range m {
out[k] = v.AsString()
if v.IsKnown() {
out[k] = v.AsString()
}
}
return out
}
func isEmpty(v cty.Value) bool {
return v.Type() == cty.String && v.AsString() == ""
func isEmptyOrUnknown(v cty.Value) bool {
return !v.IsKnown() || (v.Type() == cty.String && v.AsString() == "")
}
func eachElement(in cty.Value) iter.Seq[cty.Value] {
return func(yield func(v cty.Value) bool) {
for elem := in.ElementIterator(); elem.Next(); {
_, value := elem.Element()
if isEmptyOrUnknown(value) {
continue
}
if !yield(value) {
return
}
}
}
}