From 8f119f1b8162374fd2e694a380ba6f5f606721e5 Mon Sep 17 00:00:00 2001 From: Angus Lees <gus@inodes.org> Date: Wed, 28 Jun 2017 16:57:50 +1000 Subject: [PATCH] Add several regex native functions - `escapeStringRegex` - `regexMatch` - `regexSubst` They do what you expect, as implemented by the golang `regexp` package. --- lib/kubecfg.libsonnet | 18 +++++++++++++++++- lib/kubecfg_test.jsonnet | 8 ++++++++ utils/nativefuncs.go | 15 +++++++++++++++ utils/nativefuncs_test.go | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/lib/kubecfg.libsonnet b/lib/kubecfg.libsonnet index 90111d1e..4744f53b 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 e6aa3f2c..27e66178 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 749eb12a..3a1129d2 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 891e656b..c807b4d0 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") +} -- GitLab