ursula
Zeus is on the loose, an unstoppable frenzy of creative force! Come
June I'll have an entire nursery to celebrate me and chastise my
absence in July. ytree
needed a witchy aunt, ursula. I could produce
tarchives by authoring YAML directly or tapping into the python APIs,
both covered in the last post. "Authoring" could also mean templating,
which I'd rather not do. Or promote! So ursula
implements a
lua-driven CLI for dynamic generation. Here's the same example from
before, a static set of resource definitions.
--- !ytree/tar/dir/v1 name: ./foo --- !ytree/tar/file/v1 name: ./foo/bar contents: !ytree/res/file/v1 path: files/ytree/example.yaml --- !ytree/tar/file/v1 name: ./hello/world contents: !ytree/res/buffer/v1 contents: !!binary aGVsbG8sIHdvcmxk --- !ytree/tar/file/v1 name: ./hello/world contents: !ytree/res/string/v1 value: hello, world
Here's a lua script that produces the same document stream. The
ytree
package being required is implemented in python and exposed
to the runtime. I wrapped the ytree.tar
resource constructors
behind the ursula.fs
endpoints so that each time one is declared
in lua I simply serialize the object.
local ursula = require("ursula") local ytree = require("ytree") return function (values) ursula.fs.dir { name = "./foo", } ursula.fs.file { name = "./foo/bar", contents = ytree.res.file "files/ytree/example.yaml" } ursula.fs.file { name = "./hello/world", contents = ytree.res.buffer "aGVsbG8sIHdvcmxk" } ursula.fs.file { name = "./hello/world", contents = ytree.res.string "hello, world" } end
If you had that in a file named files/ursula/example.lua
then you
could run it like this. I truncated the output here to remove the
default members like uid
for brevity.
$ python -m dynastyf.ursula files.ursula.example --- !ytree/tar/dir/v1 name: ./foo --- !ytree/tar/file/v1 name: ./foo/bar contents: !ytree/res/file/v1 path: files/ytree/example.yaml --- !ytree/tar/file/v1 name: ./hello/world contents: !ytree/res/buffer/v1 contents: !!binary | aGVsbG8sIHdvcmxk --- !ytree/tar/file/v1 name: ./hello/world contents: !ytree/res/string/v1 value: hello, world
At this point you could save the output or pipe it through
ytree.tar
to produce an actual tarchive, which was true for the
static file to begin with, but this stream is produced on the fly.
$ python -m dynastyf.ursula files.ursula.example \ | python -m ytree.tar -c \ | tar -tvf - drwxr-x--- 0/0 0 1969-12-31 19:00 ./foo/ -rw-r----- 0/0 346 1969-12-31 19:00 ./foo/bar -rw-r----- 0/0 12 1969-12-31 19:00 ./hello/world -rw-r----- 0/0 12 1969-12-31 19:00 ./hello/world
I don't leverage it in that example but you can see that the function
returned by the module takes one argument, values
, which
ursula
constructs by merging dictionaries loaded from yet more
YAML documents. Here's an example of a script that looks up a name
from that table (and does a little templating, as a treat).
local ursula = require("ursula") local ytree = require("ytree") return function (values) ursula.fs.file { name = "foo", contents = ytree.res.string( string.format("%s, %s", values.greeting, values.name) ) } end
$ python -m dynastyf.ursula \ --values files/ursula/foo.yaml \ files.ursula.hello --- !ytree/tar/file/v1 name: foo contents: !ytree/res/string/v1 value: hello, foo
Values are merged top down (if there are multiple documents in one
file) and left to right (if there are multiple files). Here's a second
file to finish the example. I only override the name, so the greeting
from foo.yaml
will simply pass through.