diff --git a/lib/kubecfg.libsonnet b/lib/kubecfg.libsonnet index 90111d1ea6d6b712a74ea4b7670568c72728e586..4744f53b8e525124026be5a7992182a28e2c9100 100644 --- a/lib/kubecfg.libsonnet +++ b/lib/kubecfg.libsonnet @@ -9,8 +9,24 @@ // element. parseYaml:: std.native("parseYaml"), + // escapeStringRegex(s): Quote the regex metacharacters found in s. + // The result is a regex that will match the original literal + // characters. + escapeStringRegex:: std.native("escapeStringRegex"), + // resolveImage(image): convert the docker image string from // image:tag into a more specific image@digest, depending on kubecfg // command line flags. - resolveImage:: std.native("resolveImage") + resolveImage:: std.native("resolveImage"), + + // regexMatch(regex, string): Returns true if regex is found in + // string. Regex is as implemented in golang regexp package + // (python-ish). + regexMatch:: std.native("regexMatch"), + + // regexSubst(regex, src, repl): Return the result of replacing + // regex in src with repl. Replacement string may include $1, etc + // to refer to submatches. Regex is as implemented in golang regexp + // package (python-ish). + regexSubst:: std.native("regexSubst"), } diff --git a/lib/kubecfg_test.jsonnet b/lib/kubecfg_test.jsonnet index e6aa3f2cf4d2ddd16adc27734d42c7d2d3fc4290..27e661788282936632dba597cad72bdbbe9bc370 100644 --- a/lib/kubecfg_test.jsonnet +++ b/lib/kubecfg_test.jsonnet @@ -15,6 +15,14 @@ assert x == [[3, 4], {foo: "bar", baz: "xyzzy"}] : "got " + x; local i = kubecfg.resolveImage("busybox"); assert i == "busybox:latest" : "got " + i; +assert kubecfg.regexMatch("o$", "foo"); + +local r1 = kubecfg.escapeStringRegex("f[o"); +assert r1 == "f\\[o" : "got " + r1; + +local r2 = kubecfg.regexSubst("e", "tree", "oll"); +assert r2 == "trolloll" : "got " + r2; + // Kubecfg wants to see something that looks like a k8s object { apiVersion: "test", diff --git a/utils/nativefuncs.go b/utils/nativefuncs.go index 749eb12a1bfd7a12f03cf3f557b3ef6844a8f0f1..3a1129d21c5f39701aae52c5037eaa9f74d8b7e9 100644 --- a/utils/nativefuncs.go +++ b/utils/nativefuncs.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "io" + "regexp" jsonnet "github.com/strickyak/jsonnet_cgo" "k8s.io/client-go/pkg/util/yaml" @@ -48,4 +49,18 @@ func RegisterNativeFuncs(vm *jsonnet.VM, resolver Resolver) { vm.NativeCallback("resolveImage", []string{"image"}, func(image string) (string, error) { return resolveImage(resolver, image) }) + + vm.NativeCallback("escapeStringRegex", []string{"str"}, func(s string) (string, error) { + return regexp.QuoteMeta(s), nil + }) + + vm.NativeCallback("regexMatch", []string{"regex", "string"}, regexp.MatchString) + + vm.NativeCallback("regexSubst", []string{"regex", "src", "repl"}, func(regex, src, repl string) (string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return "", err + } + return r.ReplaceAllString(src, repl), nil + }) } diff --git a/utils/nativefuncs_test.go b/utils/nativefuncs_test.go index 891e656b9ea732f0532c73396c327a748a652979..c807b4d097e15be61e0c77668660deb9956540aa 100644 --- a/utils/nativefuncs_test.go +++ b/utils/nativefuncs_test.go @@ -57,3 +57,37 @@ func TestParseYaml(t *testing.T) { a[0] + a[1]`) check(t, err, x, "\"helloworld\"\n") } + +func TestRegexMatch(t *testing.T) { + vm := jsonnet.Make() + defer vm.Destroy() + RegisterNativeFuncs(vm, NewIdentityResolver()) + + _, err := vm.EvaluateSnippet("failtest", `std.native("regexMatch")("[f", "foo")`) + if err == nil { + t.Errorf("regexMatch succeeded with invalid regex") + } + + x, err := vm.EvaluateSnippet("test", `std.native("regexMatch")("foo.*", "seafood")`) + check(t, err, x, "true\n") + + x, err = vm.EvaluateSnippet("test", `std.native("regexMatch")("bar.*", "seafood")`) + check(t, err, x, "false\n") +} + +func TestRegexSubst(t *testing.T) { + vm := jsonnet.Make() + defer vm.Destroy() + RegisterNativeFuncs(vm, NewIdentityResolver()) + + _, err := vm.EvaluateSnippet("failtest", `std.native("regexSubst")("[f",s "foo", "bar")`) + if err == nil { + t.Errorf("regexSubst succeeded with invalid regex") + } + + x, err := vm.EvaluateSnippet("test", `std.native("regexSubst")("a(x*)b", "-ab-axxb-", "T")`) + check(t, err, x, "\"-T-T-\"\n") + + x, err = vm.EvaluateSnippet("test", `std.native("regexSubst")("a(x*)b", "-ab-axxb-", "${1}W")`) + check(t, err, x, "\"-W-xxW-\"\n") +}