mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
lang: Factor out the base function table
Whichever function were responsible for instantiating this map would inevitably end up scaling in length based on the number of funtions and thus violate the function length linter. As a compromise, we'll factor out the function table into its own function that is exempt from that linter but focused only on constructing the base function table, and then Scope.Functions can be shorter by dealing only with the scope-specific customizations of the returned table. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
parent
69bf43dd56
commit
972324e5ea
@ -33,153 +33,11 @@ const CoreNamespace = addrs.FunctionNamespaceCore + "::"
|
||||
func (s *Scope) Functions() map[string]function.Function {
|
||||
s.funcsLock.Lock()
|
||||
if s.funcs == nil {
|
||||
// Some of our functions are just directly the cty stdlib functions.
|
||||
// Others are implemented in the subdirectory "funcs" here in this
|
||||
// repository. New functions should generally start out their lives
|
||||
// in the "funcs" directory and potentially graduate to cty stdlib
|
||||
// later if the functionality seems to be something domain-agnostic
|
||||
// that would be useful to all applications using cty functions.
|
||||
|
||||
s.funcs = 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,
|
||||
"base64gunzip": funcs.Base64GunzipFunc,
|
||||
"base64sha256": funcs.Base64Sha256Func,
|
||||
"base64sha512": funcs.Base64Sha512Func,
|
||||
"bcrypt": funcs.BcryptFunc,
|
||||
"can": tryfunc.CanFunc,
|
||||
"ceil": stdlib.CeilFunc,
|
||||
"chomp": stdlib.ChompFunc,
|
||||
"cidrcontains": funcs.CidrContainsFunc,
|
||||
"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,
|
||||
"chunklist": stdlib.ChunklistFunc,
|
||||
"file": funcs.MakeFileFunc(s.BaseDir, false),
|
||||
"fileexists": funcs.MakeFileExistsFunc(s.BaseDir),
|
||||
"fileset": funcs.MakeFileSetFunc(s.BaseDir),
|
||||
"filebase64": funcs.MakeFileFunc(s.BaseDir, true),
|
||||
"filebase64sha256": funcs.MakeFileBase64Sha256Func(s.BaseDir),
|
||||
"filebase64sha512": funcs.MakeFileBase64Sha512Func(s.BaseDir),
|
||||
"filemd5": funcs.MakeFileMd5Func(s.BaseDir),
|
||||
"filesha1": funcs.MakeFileSha1Func(s.BaseDir),
|
||||
"filesha256": funcs.MakeFileSha256Func(s.BaseDir),
|
||||
"filesha512": funcs.MakeFileSha512Func(s.BaseDir),
|
||||
"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,
|
||||
"urldecode": funcs.URLDecodeFunc,
|
||||
"uuid": funcs.UUIDFunc,
|
||||
"uuidv5": funcs.UUIDV5Func,
|
||||
"values": stdlib.ValuesFunc,
|
||||
"yamldecode": ctyyaml.YAMLDecodeFunc,
|
||||
"yamlencode": ctyyaml.YAMLEncodeFunc,
|
||||
"zipmap": stdlib.ZipmapFunc,
|
||||
}
|
||||
|
||||
s.funcs["templatefile"] = funcs.MakeTemplateFileFunc(s.BaseDir, func() map[string]function.Function {
|
||||
// The templatefile function prevents recursive calls to itself
|
||||
// by copying this map and overwriting the "templatefile" entry.
|
||||
return s.funcs
|
||||
})
|
||||
|
||||
// Registers "templatestring" function in function map.
|
||||
s.funcs["templatestring"] = funcs.MakeTemplateStringFunc(s.BaseDir, func() map[string]function.Function {
|
||||
// This anonymous function returns the existing map of functions for initialization.
|
||||
return s.funcs
|
||||
})
|
||||
|
||||
s.funcs = makeBaseFunctionTable(s.BaseDir)
|
||||
if s.ConsoleMode {
|
||||
// The type function is only available in OpenTofu console.
|
||||
s.funcs["type"] = funcs.TypeFunc
|
||||
}
|
||||
|
||||
if !s.ConsoleMode {
|
||||
} else {
|
||||
// The plantimestamp function doesn't make sense in the OpenTofu
|
||||
// console.
|
||||
s.funcs["plantimestamp"] = funcs.MakeStaticTimestampFunc(s.PlanTimestamp)
|
||||
@ -242,3 +100,156 @@ func (s *Scope) experimentalFunction(experiment experiments.Experiment, fn funct
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// makeBaseFunctionTable constructs the initial table of functions that we uses as
|
||||
// the basis for the function table in each scope.
|
||||
//
|
||||
// This function intentionally always returns a fresh map on each call because the
|
||||
// caller is expected to modify it further before storing it as part of a
|
||||
// particular [Scope], based on the unique settings of that scope.
|
||||
//
|
||||
//nolint:funlen // The length of this function naturally scales with the number of functions in the OpenTofu language.
|
||||
func makeBaseFunctionTable(baseDir string) map[string]function.Function {
|
||||
// Some of our functions are just directly the cty stdlib functions.
|
||||
// Others are implemented in the subdirectory "funcs" here in this
|
||||
// repository. New functions should generally start out their lives
|
||||
// in the "funcs" directory and potentially graduate to cty stdlib
|
||||
// later if the functionality seems to be something domain-agnostic
|
||||
// that would be useful to all applications using cty functions.
|
||||
|
||||
ret := 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,
|
||||
"base64gunzip": funcs.Base64GunzipFunc,
|
||||
"base64sha256": funcs.Base64Sha256Func,
|
||||
"base64sha512": funcs.Base64Sha512Func,
|
||||
"bcrypt": funcs.BcryptFunc,
|
||||
"can": tryfunc.CanFunc,
|
||||
"ceil": stdlib.CeilFunc,
|
||||
"chomp": stdlib.ChompFunc,
|
||||
"cidrcontains": funcs.CidrContainsFunc,
|
||||
"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,
|
||||
"chunklist": stdlib.ChunklistFunc,
|
||||
"file": funcs.MakeFileFunc(baseDir, false),
|
||||
"fileexists": funcs.MakeFileExistsFunc(baseDir),
|
||||
"fileset": funcs.MakeFileSetFunc(baseDir),
|
||||
"filebase64": funcs.MakeFileFunc(baseDir, true),
|
||||
"filebase64sha256": funcs.MakeFileBase64Sha256Func(baseDir),
|
||||
"filebase64sha512": funcs.MakeFileBase64Sha512Func(baseDir),
|
||||
"filemd5": funcs.MakeFileMd5Func(baseDir),
|
||||
"filesha1": funcs.MakeFileSha1Func(baseDir),
|
||||
"filesha256": funcs.MakeFileSha256Func(baseDir),
|
||||
"filesha512": funcs.MakeFileSha512Func(baseDir),
|
||||
"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,
|
||||
"urldecode": funcs.URLDecodeFunc,
|
||||
"uuid": funcs.UUIDFunc,
|
||||
"uuidv5": funcs.UUIDV5Func,
|
||||
"values": stdlib.ValuesFunc,
|
||||
"yamldecode": ctyyaml.YAMLDecodeFunc,
|
||||
"yamlencode": ctyyaml.YAMLEncodeFunc,
|
||||
"zipmap": stdlib.ZipmapFunc,
|
||||
}
|
||||
|
||||
ret["templatefile"] = funcs.MakeTemplateFileFunc(baseDir, func() map[string]function.Function {
|
||||
// The templatefile function prevents recursive calls to itself
|
||||
// by copying this map and overwriting the "templatefile" entry.
|
||||
return ret
|
||||
})
|
||||
|
||||
// Registers "templatestring" function in function map.
|
||||
ret["templatestring"] = funcs.MakeTemplateStringFunc(baseDir, func() map[string]function.Function {
|
||||
// This anonymous function returns the existing map of functions for initialization.
|
||||
return ret
|
||||
})
|
||||
|
||||
return ret
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ import (
|
||||
// it really is registered correctly) and possibly a small set of additional
|
||||
// functions showing real-world use-cases that rely on type conversion
|
||||
// behaviors.
|
||||
//
|
||||
//nolint:gocognit // This test intentionally embraces mainloop complexity so that maintenence can primarily focus on the declarative test table rather than the actual test logic.
|
||||
func TestFunctions(t *testing.T) {
|
||||
// used in `pathexpand()` test
|
||||
homePath, err := homedir.Dir()
|
||||
|
Loading…
Reference in New Issue
Block a user