mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 00:47:48 +08:00
Merge pull request #2384 from Usual-Coder/feature-hcl-index
bake: add `indexof` hcl func
This commit is contained in:
commit
df7a3db947
@ -1445,6 +1445,39 @@ func TestVarUnsupportedType(t *testing.T) {
|
|||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHCLIndexOfFunc(t *testing.T) {
|
||||||
|
dt := []byte(`
|
||||||
|
variable "APP_VERSIONS" {
|
||||||
|
default = [
|
||||||
|
"1.42.4",
|
||||||
|
"1.42.3"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
target "default" {
|
||||||
|
args = {
|
||||||
|
APP_VERSION = app_version
|
||||||
|
}
|
||||||
|
matrix = {
|
||||||
|
app_version = APP_VERSIONS
|
||||||
|
}
|
||||||
|
name="app-${replace(app_version, ".", "-")}"
|
||||||
|
tags = [
|
||||||
|
"app:${app_version}",
|
||||||
|
indexof(APP_VERSIONS, app_version) == 0 ? "app:latest" : "",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
c, err := ParseFile(dt, "docker-bake.hcl")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, 2, len(c.Targets))
|
||||||
|
require.Equal(t, "app-1-42-4", c.Targets[0].Name)
|
||||||
|
require.Equal(t, "app:latest", c.Targets[0].Tags[1])
|
||||||
|
require.Equal(t, "app-1-42-3", c.Targets[1].Name)
|
||||||
|
require.Empty(t, c.Targets[1].Tags[1])
|
||||||
|
}
|
||||||
|
|
||||||
func ptrstr(s interface{}) *string {
|
func ptrstr(s interface{}) *string {
|
||||||
var n *string
|
var n *string
|
||||||
if reflect.ValueOf(s).Kind() == reflect.String {
|
if reflect.ValueOf(s).Kind() == reflect.String {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/hashicorp/go-cty-funcs/uuid"
|
"github.com/hashicorp/go-cty-funcs/uuid"
|
||||||
"github.com/hashicorp/hcl/v2/ext/tryfunc"
|
"github.com/hashicorp/hcl/v2/ext/tryfunc"
|
||||||
"github.com/hashicorp/hcl/v2/ext/typeexpr"
|
"github.com/hashicorp/hcl/v2/ext/typeexpr"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
"github.com/zclconf/go-cty/cty/function"
|
"github.com/zclconf/go-cty/cty/function"
|
||||||
"github.com/zclconf/go-cty/cty/function/stdlib"
|
"github.com/zclconf/go-cty/cty/function/stdlib"
|
||||||
@ -52,6 +53,7 @@ var stdlibFunctions = map[string]function.Function{
|
|||||||
"hasindex": stdlib.HasIndexFunc,
|
"hasindex": stdlib.HasIndexFunc,
|
||||||
"indent": stdlib.IndentFunc,
|
"indent": stdlib.IndentFunc,
|
||||||
"index": stdlib.IndexFunc,
|
"index": stdlib.IndexFunc,
|
||||||
|
"indexof": indexOfFunc,
|
||||||
"int": stdlib.IntFunc,
|
"int": stdlib.IntFunc,
|
||||||
"join": stdlib.JoinFunc,
|
"join": stdlib.JoinFunc,
|
||||||
"jsondecode": stdlib.JSONDecodeFunc,
|
"jsondecode": stdlib.JSONDecodeFunc,
|
||||||
@ -115,6 +117,51 @@ var stdlibFunctions = map[string]function.Function{
|
|||||||
"zipmap": stdlib.ZipmapFunc,
|
"zipmap": stdlib.ZipmapFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// indexOfFunc constructs a function that finds the element index for a given
|
||||||
|
// value in a list.
|
||||||
|
var indexOfFunc = function.New(&function.Spec{
|
||||||
|
Params: []function.Parameter{
|
||||||
|
{
|
||||||
|
Name: "list",
|
||||||
|
Type: cty.DynamicPseudoType,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "value",
|
||||||
|
Type: cty.DynamicPseudoType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Type: function.StaticReturnType(cty.Number),
|
||||||
|
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||||
|
if !(args[0].Type().IsListType() || args[0].Type().IsTupleType()) {
|
||||||
|
return cty.NilVal, errors.New("argument must be a list or tuple")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !args[0].IsKnown() {
|
||||||
|
return cty.UnknownVal(cty.Number), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if args[0].LengthInt() == 0 { // Easy path
|
||||||
|
return cty.NilVal, errors.New("cannot search an empty list")
|
||||||
|
}
|
||||||
|
|
||||||
|
for it := args[0].ElementIterator(); it.Next(); {
|
||||||
|
i, v := it.Element()
|
||||||
|
eq, err := stdlib.Equal(v, args[1])
|
||||||
|
if err != nil {
|
||||||
|
return cty.NilVal, err
|
||||||
|
}
|
||||||
|
if !eq.IsKnown() {
|
||||||
|
return cty.UnknownVal(cty.Number), nil
|
||||||
|
}
|
||||||
|
if eq.True() {
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cty.NilVal, errors.New("item not found")
|
||||||
|
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
// timestampFunc constructs a function that returns a string representation of the current date and time.
|
// timestampFunc constructs a function that returns a string representation of the current date and time.
|
||||||
//
|
//
|
||||||
// This function was imported from terraform's datetime utilities.
|
// This function was imported from terraform's datetime utilities.
|
||||||
|
49
bake/hclparser/stdlib_test.go
Normal file
49
bake/hclparser/stdlib_test.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package hclparser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIndexOf(t *testing.T) {
|
||||||
|
type testCase struct {
|
||||||
|
input cty.Value
|
||||||
|
key cty.Value
|
||||||
|
want cty.Value
|
||||||
|
wantErr bool
|
||||||
|
}
|
||||||
|
tests := map[string]testCase{
|
||||||
|
"index 0": {
|
||||||
|
input: cty.TupleVal([]cty.Value{cty.StringVal("one"), cty.NumberIntVal(2.0), cty.NumberIntVal(3), cty.StringVal("four")}),
|
||||||
|
key: cty.StringVal("one"),
|
||||||
|
want: cty.NumberIntVal(0),
|
||||||
|
},
|
||||||
|
"index 3": {
|
||||||
|
input: cty.TupleVal([]cty.Value{cty.StringVal("one"), cty.NumberIntVal(2.0), cty.NumberIntVal(3), cty.StringVal("four")}),
|
||||||
|
key: cty.StringVal("four"),
|
||||||
|
want: cty.NumberIntVal(3),
|
||||||
|
},
|
||||||
|
"index -1": {
|
||||||
|
input: cty.TupleVal([]cty.Value{cty.StringVal("one"), cty.NumberIntVal(2.0), cty.NumberIntVal(3), cty.StringVal("four")}),
|
||||||
|
key: cty.StringVal("3"),
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, test := range tests {
|
||||||
|
name, test := name, test
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
got, err := indexOfFunc.Call([]cty.Value{test.input, test.key})
|
||||||
|
if err != nil {
|
||||||
|
if test.wantErr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Fatalf("unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
if !got.RawEquals(test.want) {
|
||||||
|
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user