mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Merge pull request #1096 from hashicorp/f-sprintf
config: add "format' function [GH-758]
This commit is contained in:
commit
23609a7af5
@ -17,6 +17,7 @@ var Funcs map[string]ast.Function
|
|||||||
func init() {
|
func init() {
|
||||||
Funcs = map[string]ast.Function{
|
Funcs = map[string]ast.Function{
|
||||||
"file": interpolationFuncFile(),
|
"file": interpolationFuncFile(),
|
||||||
|
"format": interpolationFuncFormat(),
|
||||||
"join": interpolationFuncJoin(),
|
"join": interpolationFuncJoin(),
|
||||||
"element": interpolationFuncElement(),
|
"element": interpolationFuncElement(),
|
||||||
"replace": interpolationFuncReplace(),
|
"replace": interpolationFuncReplace(),
|
||||||
@ -66,6 +67,21 @@ func interpolationFuncFile() ast.Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interpolationFuncFormat implements the "replace" function that does
|
||||||
|
// string replacement.
|
||||||
|
func interpolationFuncFormat() ast.Function {
|
||||||
|
return ast.Function{
|
||||||
|
ArgTypes: []ast.Type{ast.TypeString},
|
||||||
|
Variadic: true,
|
||||||
|
VariadicType: ast.TypeAny,
|
||||||
|
ReturnType: ast.TypeString,
|
||||||
|
Callback: func(args []interface{}) (interface{}, error) {
|
||||||
|
format := args[0].(string)
|
||||||
|
return fmt.Sprintf(format, args[1:]...), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// interpolationFuncJoin implements the "join" function that allows
|
// interpolationFuncJoin implements the "join" function that allows
|
||||||
// multi-variable values to be joined by some character.
|
// multi-variable values to be joined by some character.
|
||||||
func interpolationFuncJoin() ast.Function {
|
func interpolationFuncJoin() ast.Function {
|
||||||
|
@ -70,6 +70,42 @@ func TestInterpolateFuncFile(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInterpolateFuncFormat(t *testing.T) {
|
||||||
|
testFunction(t, testFunctionConfig{
|
||||||
|
Cases: []testFunctionCase{
|
||||||
|
{
|
||||||
|
`${format("hello")}`,
|
||||||
|
"hello",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
`${format("hello %s", "world")}`,
|
||||||
|
"hello world",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
`${format("hello %d", 42)}`,
|
||||||
|
"hello 42",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
`${format("hello %05d", 42)}`,
|
||||||
|
"hello 00042",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
`${format("hello %05d", 12345)}`,
|
||||||
|
"hello 12345",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestInterpolateFuncJoin(t *testing.T) {
|
func TestInterpolateFuncJoin(t *testing.T) {
|
||||||
testFunction(t, testFunctionConfig{
|
testFunction(t, testFunctionConfig{
|
||||||
Cases: []testFunctionCase{
|
Cases: []testFunctionCase{
|
||||||
|
@ -48,7 +48,8 @@ type Type uint32
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
TypeInvalid Type = 0
|
TypeInvalid Type = 0
|
||||||
TypeString Type = 1 << iota
|
TypeAny Type = 1 << iota
|
||||||
|
TypeString
|
||||||
TypeInt
|
TypeInt
|
||||||
TypeFloat
|
TypeFloat
|
||||||
)
|
)
|
||||||
|
@ -6,16 +6,18 @@ import "fmt"
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
_Type_name_0 = "TypeInvalid"
|
_Type_name_0 = "TypeInvalid"
|
||||||
_Type_name_1 = "TypeString"
|
_Type_name_1 = "TypeAny"
|
||||||
_Type_name_2 = "TypeInt"
|
_Type_name_2 = "TypeString"
|
||||||
_Type_name_3 = "TypeFloat"
|
_Type_name_3 = "TypeInt"
|
||||||
|
_Type_name_4 = "TypeFloat"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_Type_index_0 = [...]uint8{0, 11}
|
_Type_index_0 = [...]uint8{0, 11}
|
||||||
_Type_index_1 = [...]uint8{0, 10}
|
_Type_index_1 = [...]uint8{0, 7}
|
||||||
_Type_index_2 = [...]uint8{0, 7}
|
_Type_index_2 = [...]uint8{0, 10}
|
||||||
_Type_index_3 = [...]uint8{0, 9}
|
_Type_index_3 = [...]uint8{0, 7}
|
||||||
|
_Type_index_4 = [...]uint8{0, 9}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (i Type) String() string {
|
func (i Type) String() string {
|
||||||
@ -28,6 +30,8 @@ func (i Type) String() string {
|
|||||||
return _Type_name_2
|
return _Type_name_2
|
||||||
case i == 8:
|
case i == 8:
|
||||||
return _Type_name_3
|
return _Type_name_3
|
||||||
|
case i == 16:
|
||||||
|
return _Type_name_4
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("Type(%d)", i)
|
return fmt.Sprintf("Type(%d)", i)
|
||||||
}
|
}
|
||||||
|
@ -174,6 +174,10 @@ func (tc *typeCheckCall) TypeCheck(v *TypeCheck) (ast.Node, error) {
|
|||||||
|
|
||||||
// Verify the args
|
// Verify the args
|
||||||
for i, expected := range function.ArgTypes {
|
for i, expected := range function.ArgTypes {
|
||||||
|
if expected == ast.TypeAny {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if args[i] != expected {
|
if args[i] != expected {
|
||||||
cn := v.ImplicitConversion(args[i], expected, tc.n.Args[i])
|
cn := v.ImplicitConversion(args[i], expected, tc.n.Args[i])
|
||||||
if cn != nil {
|
if cn != nil {
|
||||||
@ -188,7 +192,7 @@ func (tc *typeCheckCall) TypeCheck(v *TypeCheck) (ast.Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we're variadic, then verify the types there
|
// If we're variadic, then verify the types there
|
||||||
if function.Variadic {
|
if function.Variadic && function.VariadicType != ast.TypeAny {
|
||||||
args = args[len(function.ArgTypes):]
|
args = args[len(function.ArgTypes):]
|
||||||
for i, t := range args {
|
for i, t := range args {
|
||||||
if t != function.VariadicType {
|
if t != function.VariadicType {
|
||||||
|
@ -80,6 +80,12 @@ The supported built-in functions are:
|
|||||||
in this file are _not_ interpolated. The contents of the file are
|
in this file are _not_ interpolated. The contents of the file are
|
||||||
read as-is.
|
read as-is.
|
||||||
|
|
||||||
|
* `format(format, args...)` - Formats a string according to the given
|
||||||
|
format. The syntax for the format is standard `sprintf` syntax.
|
||||||
|
Good documentation for the syntax can be [found here](http://golang.org/pkg/fmt/).
|
||||||
|
Example to zero-prefix a count, used commonly for naming servers:
|
||||||
|
`format("web-%03d", count.index+1)`.
|
||||||
|
|
||||||
* `join(delim, list)` - Joins the list with the delimiter. A list is
|
* `join(delim, list)` - Joins the list with the delimiter. A list is
|
||||||
only possible with splat variables from resources with a count
|
only possible with splat variables from resources with a count
|
||||||
greater than one. Example: `join(",", aws_instance.foo.*.id)`
|
greater than one. Example: `join(",", aws_instance.foo.*.id)`
|
||||||
|
Loading…
Reference in New Issue
Block a user