In Jsonnet’s standard libraries, there’s an std.prune function which will recursively go through an object and remove any empty field in the object which is quite handy, usually. In my case I wanted to prune all empty fields in a container object but spare the legit empty emptyDir field so the std.prune may cause some trouble:
// source { containers: { local container = { image: 'nginx:latest', env: [], args: [], volumeMounts: [ { name: 'test', emptyDir: {} } ], }, test: std.prune(container), }, } // output { "containers": { "test": { "image": "nginx:latest", // removed emtpy env and args "volumeMounts": [ { "name": "test" // the emptyDir should not be removed here } ] } } }
So I wrote my own prune function which only clean up empty field matching a list of names, here’s what it looks like:
// source { containers: { local prune(obj) = local field_list = ['args', 'env']; { [if std.member(field_list, f) && std.length(obj[f]) == 0 then null else f]: obj[f] for f in std.objectFields(obj) }, local container = { image: 'nginx:latest', env: [], args: [], volumeMounts: [ { name: 'test', emptyDir: {} } ], }, test: prune(container), }, } // output { "containers": { "test": { "image": "nginx:latest", "volumeMounts": [ { "emptyDir": {}, "name": "test" } ] } } }
This works for the sample but obviously it only goes through the first-level fields. Let’s get recursive!
// source { containers: { local pruneExcept(a, ex=[]) = if std.isObject(a) then{ [if std.member(ex, f) || std.length(a[f]) > 0 then f else null]: $.prune(a[f],ex) for f in std.objectFields(a) } else if std.isArray(a) then [ $.prune(nf, ex) for nf in a ] else a, local container = { image: 'nginx:latest', env: [], args: [], volumeMounts: [ { name: 'test', emptyDir: {}, rubbish: {} } ], resources: { requests: { cpu: '0.5', rubbish: [] }, rubbish: [], } }, test: pruneExcept(container, 'emptyDir'), }, } // output { "containers": { "test": { "image": "nginx:latest", "resources": { "requests": { "cpu": "0.5" } }, "volumeMounts": [ { "emptyDir": {}, "name": "test" } ] } }
It works but why should I stop here? I had a look at the source code of std.prune
and proposed a PR here. 🙂