diff --git a/lib/kubecfg.libsonnet b/lib/kubecfg.libsonnet index 43448e4517689d5b5a16476b44d09e464bc41987..9215a753dbe086917219c93c1761426eb1f07438 100644 --- a/lib/kubecfg.libsonnet +++ b/lib/kubecfg.libsonnet @@ -13,6 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +// NB: libjsonnet native functions can only pass primitive types, so +// some functions json-encode the arg. These "*FromJson" functions +// will be replaced by regular native version when libjsonnet is able +// to support this. This file strives to hide this implementation +// detail. + { // parseJson(data): parses the `data` string as a json document, and // returns the resulting jsonnet object. @@ -24,6 +30,21 @@ // element. parseYaml:: std.native("parseYaml"), + // manifestJson(value, indent): convert the jsonnet object `value` + // to a string encoded as "pretty" (multi-line) JSON, with each + // nesting level indented by `indent` spaces. + manifestJson(value, indent=4):: ( + local f = std.native("manifestJsonFromJson"); + f(std.toString(value), indent) + ), + + // manifestYaml(value): convert the jsonnet object `value` to a + // string encoded as a single YAML document. + manifestYaml(value):: ( + local f = std.native("manifestYamlFromJson"); + f(std.toString(value)) + ), + // escapeStringRegex(s): Quote the regex metacharacters found in s. // The result is a regex that will match the original literal // characters. diff --git a/lib/kubecfg_test.jsonnet b/lib/kubecfg_test.jsonnet index fafd8afeaf38a2d016843f2b8fbbe2eb1e352ed4..1e288153821f3e6a7e5ca57d989f3d4f63b0061b 100644 --- a/lib/kubecfg_test.jsonnet +++ b/lib/kubecfg_test.jsonnet @@ -27,16 +27,43 @@ baz: xyzzy "); assert x == [[3, 4], {foo: "bar", baz: "xyzzy"}] : "got " + x; +local x = kubecfg.manifestJson({foo: "bar", baz: [3, 4]}); +assert x == '{ + "baz": [ + 3, + 4 + ], + "foo": "bar" +} +' : "got " + x; + +local x = kubecfg.manifestJson({foo: "bar", baz: [3, 4]}, indent=2); +assert x == '{ + "baz": [ + 3, + 4 + ], + "foo": "bar" +} +' : "got " + x; + +local x = kubecfg.manifestYaml({foo: "bar", baz: [3, 4]}); +assert x == "baz: +- 3 +- 4 +foo: bar +" : "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 r = kubecfg.escapeStringRegex("f[o"); +assert r == "f\\[o" : "got " + r; -local r2 = kubecfg.regexSubst("e", "tree", "oll"); -assert r2 == "trolloll" : "got " + r2; +local r = kubecfg.regexSubst("e", "tree", "oll"); +assert r == "trolloll" : "got " + r; // Kubecfg wants to see something that looks like a k8s object { diff --git a/utils/nativefuncs.go b/utils/nativefuncs.go index 13569130afd0ff093acd6355f059e2d57f796178..30fe7cc8ab6df2030e318643a2a7156f357ac95b 100644 --- a/utils/nativefuncs.go +++ b/utils/nativefuncs.go @@ -20,6 +20,9 @@ import ( "encoding/json" "io" "regexp" + "strings" + + goyaml "github.com/ghodss/yaml" jsonnet "github.com/strickyak/jsonnet_cgo" "k8s.io/apimachinery/pkg/util/yaml" @@ -40,6 +43,11 @@ func resolveImage(resolver Resolver, image string) (string, error) { // RegisterNativeFuncs adds kubecfg's native jsonnet functions to provided VM func RegisterNativeFuncs(vm *jsonnet.VM, resolver Resolver) { + // NB: libjsonnet native functions can only pass primitive + // types, so some functions json-encode the arg. These + // "*FromJson" functions will be replaced by regular native + // version when libjsonnet is able to support this. + vm.NativeCallback("parseJson", []string{"json"}, func(data []byte) (res interface{}, err error) { err = json.Unmarshal(data, &res) return @@ -61,6 +69,25 @@ func RegisterNativeFuncs(vm *jsonnet.VM, resolver Resolver) { return ret, nil }) + vm.NativeCallback("manifestJsonFromJson", []string{"json", "indent"}, func(data []byte, indent int) (string, error) { + data = bytes.TrimSpace(data) + buf := bytes.Buffer{} + if err := json.Indent(&buf, data, "", strings.Repeat(" ", indent)); err != nil { + return "", err + } + buf.WriteString("\n") + return buf.String(), nil + }) + + vm.NativeCallback("manifestYamlFromJson", []string{"json"}, func(data []byte) (string, error) { + var input interface{} + if err := json.Unmarshal(data, &input); err != nil { + return "", err + } + output, err := goyaml.Marshal(input) + return string(output), err + }) + vm.NativeCallback("resolveImage", []string{"image"}, func(image string) (string, error) { return resolveImage(resolver, image) })