enable use of the convert function

We add `convert` to our set of functions, and we clean up the duplicate
function assignments in this package. The multiple assignments have
meant that any function changes are inevitably forgotten from the testing
framework, and we shouldn't need to declare the mapping multiple times.
pull/38160/head
James Bardin 3 months ago
parent 9ce50aa8a6
commit 4f97ef67ee

@ -65,131 +65,22 @@ func (s *Scope) Functions() map[string]function.Function {
s.funcsLock.Lock()
if s.funcs == nil {
s.funcs = baseFunctions(s.BaseDir)
coreFuncs := baseFunctions(s.BaseDir)
// If you're adding something here, please consider whether it meets
// the criteria for either or both of the sets [filesystemFunctions]
// and [templateFunctions] and add it there if so, to ensure that
// functions relying on those classifications will behave correctly.
coreFuncs := map[string]function.Function{
"abs": stdlib.AbsoluteFunc,
"abspath": funcs.AbsPathFunc,
"alltrue": funcs.AllTrueFunc,
"anytrue": funcs.AnyTrueFunc,
"basename": funcs.BasenameFunc,
"base64decode": funcs.Base64DecodeFunc,
"base64encode": funcs.Base64EncodeFunc,
"base64gzip": funcs.Base64GzipFunc,
"base64sha256": funcs.Base64Sha256Func,
"base64sha512": funcs.Base64Sha512Func,
"bcrypt": funcs.BcryptFunc,
"can": tryfunc.CanFunc,
"ceil": stdlib.CeilFunc,
"chomp": stdlib.ChompFunc,
"cidrhost": funcs.CidrHostFunc,
"cidrnetmask": funcs.CidrNetmaskFunc,
"cidrsubnet": funcs.CidrSubnetFunc,
"cidrsubnets": funcs.CidrSubnetsFunc,
"coalesce": funcs.CoalesceFunc,
"coalescelist": stdlib.CoalesceListFunc,
"compact": stdlib.CompactFunc,
"concat": stdlib.ConcatFunc,
"contains": stdlib.ContainsFunc,
"csvdecode": stdlib.CSVDecodeFunc,
"dirname": funcs.DirnameFunc,
"distinct": stdlib.DistinctFunc,
"element": stdlib.ElementFunc,
"endswith": funcs.EndsWithFunc,
"ephemeralasnull": funcs.EphemeralAsNullFunc,
"chunklist": stdlib.ChunklistFunc,
"file": funcs.MakeFileFunc(s.BaseDir, false, immutableResults("file", s.FunctionResults)),
"fileexists": funcs.MakeFileExistsFunc(s.BaseDir, immutableResults("fileexists", s.FunctionResults)),
"fileset": funcs.MakeFileSetFunc(s.BaseDir, immutableResults("fileset", s.FunctionResults)),
"filebase64": funcs.MakeFileFunc(s.BaseDir, true, immutableResults("filebase64", s.FunctionResults)),
"filebase64sha256": funcs.MakeFileBase64Sha256Func(s.BaseDir, immutableResults("filebase64sha256", s.FunctionResults)),
"filebase64sha512": funcs.MakeFileBase64Sha512Func(s.BaseDir, immutableResults("filebase64sha512", s.FunctionResults)),
"filemd5": funcs.MakeFileMd5Func(s.BaseDir, immutableResults("filemd5", s.FunctionResults)),
"filesha1": funcs.MakeFileSha1Func(s.BaseDir, immutableResults("filesha1", s.FunctionResults)),
"filesha256": funcs.MakeFileSha256Func(s.BaseDir, immutableResults("filesha256", s.FunctionResults)),
"filesha512": funcs.MakeFileSha512Func(s.BaseDir, immutableResults("filesha512", s.FunctionResults)),
"flatten": stdlib.FlattenFunc,
"floor": stdlib.FloorFunc,
"format": stdlib.FormatFunc,
"formatdate": stdlib.FormatDateFunc,
"formatlist": stdlib.FormatListFunc,
"indent": stdlib.IndentFunc,
"index": funcs.IndexFunc, // stdlib.IndexFunc is not compatible
"join": stdlib.JoinFunc,
"jsondecode": stdlib.JSONDecodeFunc,
"jsonencode": stdlib.JSONEncodeFunc,
"keys": stdlib.KeysFunc,
"length": funcs.LengthFunc,
"list": funcs.ListFunc,
"log": stdlib.LogFunc,
"lookup": funcs.LookupFunc,
"lower": stdlib.LowerFunc,
"map": funcs.MapFunc,
"matchkeys": funcs.MatchkeysFunc,
"max": stdlib.MaxFunc,
"md5": funcs.Md5Func,
"merge": stdlib.MergeFunc,
"min": stdlib.MinFunc,
"one": funcs.OneFunc,
"parseint": stdlib.ParseIntFunc,
"pathexpand": funcs.PathExpandFunc,
"pow": stdlib.PowFunc,
"range": stdlib.RangeFunc,
"regex": stdlib.RegexFunc,
"regexall": stdlib.RegexAllFunc,
"replace": funcs.ReplaceFunc,
"reverse": stdlib.ReverseListFunc,
"rsadecrypt": funcs.RsaDecryptFunc,
"sensitive": funcs.SensitiveFunc,
"nonsensitive": funcs.NonsensitiveFunc,
"issensitive": funcs.IssensitiveFunc,
"setintersection": stdlib.SetIntersectionFunc,
"setproduct": stdlib.SetProductFunc,
"setsubtract": stdlib.SetSubtractFunc,
"setunion": stdlib.SetUnionFunc,
"sha1": funcs.Sha1Func,
"sha256": funcs.Sha256Func,
"sha512": funcs.Sha512Func,
"signum": stdlib.SignumFunc,
"slice": stdlib.SliceFunc,
"sort": stdlib.SortFunc,
"split": stdlib.SplitFunc,
"startswith": funcs.StartsWithFunc,
"strcontains": funcs.StrContainsFunc,
"strrev": stdlib.ReverseFunc,
"substr": stdlib.SubstrFunc,
"sum": funcs.SumFunc,
"textdecodebase64": funcs.TextDecodeBase64Func,
"textencodebase64": funcs.TextEncodeBase64Func,
"timestamp": funcs.TimestampFunc,
"timeadd": stdlib.TimeAddFunc,
"timecmp": funcs.TimeCmpFunc,
"title": stdlib.TitleFunc,
"tostring": funcs.MakeToFunc(cty.String),
"tonumber": funcs.MakeToFunc(cty.Number),
"tobool": funcs.MakeToFunc(cty.Bool),
"toset": funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)),
"tolist": funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)),
"tomap": funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)),
"transpose": funcs.TransposeFunc,
"trim": stdlib.TrimFunc,
"trimprefix": stdlib.TrimPrefixFunc,
"trimspace": stdlib.TrimSpaceFunc,
"trimsuffix": stdlib.TrimSuffixFunc,
"try": tryfunc.TryFunc,
"upper": stdlib.UpperFunc,
"urlencode": funcs.URLEncodeFunc,
"uuid": funcs.UUIDFunc,
"uuidv5": funcs.UUIDV5Func,
"values": stdlib.ValuesFunc,
"yamldecode": ctyyaml.YAMLDecodeFunc,
"yamlencode": ctyyaml.YAMLEncodeFunc,
"zipmap": stdlib.ZipmapFunc,
}
// Modify the functions which behave slightly differently in core.
// Filesystem functions will check for consistent results, and the
// template functions need to be updated to close over the correct
// versions of the filesystem functions.
coreFuncs["file"] = funcs.MakeFileFunc(s.BaseDir, false, immutableResults("file", s.FunctionResults))
coreFuncs["fileexists"] = funcs.MakeFileExistsFunc(s.BaseDir, immutableResults("fileexists", s.FunctionResults))
coreFuncs["fileset"] = funcs.MakeFileSetFunc(s.BaseDir, immutableResults("fileset", s.FunctionResults))
coreFuncs["filebase64"] = funcs.MakeFileFunc(s.BaseDir, true, immutableResults("filebase64", s.FunctionResults))
coreFuncs["filebase64sha256"] = funcs.MakeFileBase64Sha256Func(s.BaseDir, immutableResults("filebase64sha256", s.FunctionResults))
coreFuncs["filebase64sha512"] = funcs.MakeFileBase64Sha512Func(s.BaseDir, immutableResults("filebase64sha512", s.FunctionResults))
coreFuncs["filemd5"] = funcs.MakeFileMd5Func(s.BaseDir, immutableResults("filemd5", s.FunctionResults))
coreFuncs["filesha1"] = funcs.MakeFileSha1Func(s.BaseDir, immutableResults("filesha1", s.FunctionResults))
coreFuncs["filesha256"] = funcs.MakeFileSha256Func(s.BaseDir, immutableResults("filesha256", s.FunctionResults))
coreFuncs["filesha512"] = funcs.MakeFileSha512Func(s.BaseDir, immutableResults("filesha512", s.FunctionResults))
// Our two template-rendering functions want to be able to call
// all of the other functions themselves, but we pass them indirectly
@ -226,7 +117,7 @@ func (s *Scope) Functions() map[string]function.Function {
// All of the built-in functions are also available under the "core::"
// namespace, to distinguish from the "provider::" and "module::"
// namespaces that can serve as external extension points.
s.funcs = make(map[string]function.Function, len(coreFuncs)*2)
s.funcs = make(map[string]function.Function)
for name, fn := range coreFuncs {
fn = funcs.WithDescription(name, fn)
s.funcs[name] = fn
@ -306,11 +197,13 @@ func baseFunctions(baseDir string) map[string]function.Function {
"compact": stdlib.CompactFunc,
"concat": stdlib.ConcatFunc,
"contains": stdlib.ContainsFunc,
"convert": funcs.ConvertFunc,
"csvdecode": stdlib.CSVDecodeFunc,
"dirname": funcs.DirnameFunc,
"distinct": stdlib.DistinctFunc,
"element": stdlib.ElementFunc,
"endswith": funcs.EndsWithFunc,
"ephemeralasnull": funcs.EphemeralAsNullFunc,
"chunklist": stdlib.ChunklistFunc,
"file": funcs.MakeFileFunc(baseDir, false, noopWrapper),
"fileexists": funcs.MakeFileExistsFunc(baseDir, noopWrapper),
@ -401,11 +294,19 @@ func baseFunctions(baseDir string) map[string]function.Function {
"zipmap": stdlib.ZipmapFunc,
}
fs["templatefile"] = funcs.MakeTemplateFileFunc(baseDir, func() (map[string]function.Function, collections.Set[string], collections.Set[string]) {
// The templatefile function prevents recursive calls to itself
// by copying this map and overwriting the "templatefile" entry.
// Our two template-rendering functions want to be able to call
// all of the other functions themselves, but we pass them indirectly
// via a callback to avoid chicken/egg problems while initializing
// the functions table.
funcsFunc := func() (funcs map[string]function.Function, fsFuncs collections.Set[string], templateFuncs collections.Set[string]) {
// The templatefile and templatestring functions prevent recursive
// calls to themselves and each other by copying this map and
// overwriting the relevant entries.
return fs, filesystemFunctions, templateFunctions
}, noopWrapper)
}
fs["templatefile"] = funcs.MakeTemplateFileFunc(baseDir, funcsFunc, noopWrapper)
fs["templatestring"] = funcs.MakeTemplateStringFunc(funcsFunc)
return fs
}

@ -281,6 +281,19 @@ func TestFunctions(t *testing.T) {
},
},
"convert": {
{
`convert({}, object({attr=optional(string, "default")}))`,
cty.ObjectVal(map[string]cty.Value{
"attr": cty.StringVal("default"),
}),
},
{
`convert({}, map(list(map(set(string)))))`,
cty.MapValEmpty(cty.List(cty.Map(cty.Set(cty.String)))),
},
},
"csvdecode": {
{
`csvdecode("a,b,c\n1,2,3\n4,5,6")`,

Loading…
Cancel
Save