Jsonnet で YAML を生成
Jsonnet は JSON を拡張したような DSL で、変数や関数を定義できたり内包表記が使えたりと、それなりに便利になっています。
JSON 以外にも YAML や INI ファイルなども生成できるようになっているようなので、YAML の生成を試してみました。
なお、Jsonnet の事は Kubernetes の ksonnet で知ったのですが、Kubernetes の YAML に関しては JavaScript や Python 等のプログラミング言語を使う Pulumi の方が(現時点では)良さそうな気がしています。
はじめに
今回は Jsonnet ファイルの処理に Go 言語で実装された下記ツールを使います。
インストールは go get するだけです。
インストール
> go get github.com/google/go-jsonnet/cmd/jsonnet
これで jsonnet コマンドが使えるようになります。
> jsonnet --version Jsonnet commandline interpreter v0.13.0
JSON 生成
まずは JSON を生成してみます。 以下のような機能を使った jsonnet ファイルを用意してみました。
local
で変数・関数を定義self
でカレントのオブジェクトを参照$
でルートのオブジェクトを参照std.関数名
で標準ライブラリの関数を呼び出す[]
と{}
の内包表記
sample.jsonnet
local items = [ { id: i, name: 'item-' + i } for i in std.range(1, 3) ]; local last(xs) = xs[std.length(xs) - 1]; { base_items: items, products: [ { name: it.name, qty: 1 } for it in items ], first: self.products[0], last: last(self.products), ref: { local ps = $['products'], products_md5: { [p.name]: std.md5(p.name) for p in ps } }, }
jsonnet コマンドで JSON 変換すると以下のようになります。 要素の並びは名前順にソートされるようです。
JSON 生成結果
> jsonnet sample.jsonnet { "base_items": [ { "id": 1, "name": "item-1" }, { "id": 2, "name": "item-2" }, { "id": 3, "name": "item-3" } ], "first": { "name": "item-1", "qty": 1 }, "last": { "name": "item-3", "qty": 1 }, "products": [ { "name": "item-1", "qty": 1 }, { "name": "item-2", "qty": 1 }, { "name": "item-3", "qty": 1 } ], "ref": { "products_md5": { "item-1": "761ff52b8e6dd373fdf291a1a70df20c", "item-2": "38d3f385ea8d8bb2dcfc759ac85af6ef", "item-3": "65910a0fd76f69a08e6faa142384f327" } } }
YAML 生成
YAML で出力したい場合は std.manifestYamlDoc()
を使うだけです。
sample_yaml.jsonnet
local items = [ { id: i, name: 'item-' + i } for i in std.range(1, 3) ]; local last(xs) = xs[std.length(xs) - 1]; std.manifestYamlDoc({ base_items: items, products: [ { name: it.name, qty: 1 } for it in items ], first: self.products[0], last: last(self.products), ref: { local ps = $['products'], products_md5: { [p.name]: std.md5(p.name) for p in ps } }, })
YAML を出力する場合は、-S
オプションを指定して jsonnet コマンドを実行します。
YAML 生成結果
> jsonnet -S sample_yaml.jsonnet "base_items": - "id": 1 "name": "item-1" - "id": 2 "name": "item-2" - "id": 3 "name": "item-3" "first": "name": "item-1" "qty": 1 "last": "name": "item-3" "qty": 1 "products": - "name": "item-1" "qty": 1 - "name": "item-2" "qty": 1 - "name": "item-3" "qty": 1 "ref": "products_md5": "item-1": "761ff52b8e6dd373fdf291a1a70df20c" "item-2": "38d3f385ea8d8bb2dcfc759ac85af6ef" "item-3": "65910a0fd76f69a08e6faa142384f327"
-S
オプションを指定しないとエスケープされた文字列として出力されてしまいます。
YAML 生成結果(-S を指定しなかった場合)
> jsonnet sample_yaml.jsonnet "\"base_items\":\n- \"id\": 1\n \"name\": \"item-1\"\n- \"id\": 2\n \"name\": \"item-2\"\n- \"id\": 3\n \"name\": \"item-3\"\n\"first\":\n \"name\": \"item-1\"\n \"qty\": 1\n\"last\":\n \"name\": \"item-3\"\n \"qty\": 1\n\"products\":\n- \"name\": \"item-1\"\n \"qty\": 1\n- \"name\": \"item-2\"\n \"qty\": 1\n- \"name\": \"item-3\"\n \"qty\": 1\n\"ref\":\n \"products_md5\":\n \"item-1\": \"761ff52b8e6dd373fdf291a1a70df20c\"\n \"item-2\": \"38d3f385ea8d8bb2dcfc759ac85af6ef\"\n \"item-3\": \"65910a0fd76f69a08e6faa142384f327\""