execvm
There was some overlap between ursula and ytree so I pulled the common bits into a separate project, metrologyf. He standardizes my YAML serialization and lua parsing and supplies libraries for assorted bits like merging dictionaries and loading environment variables.
I also revived execvm,
which in some ways is where I started from. He emerged in winter a few
years ago and evolved a bit before budding like ytree
this
month. The current CLI execvm.ysh
is like ytree.tar
but for a
stream of command descriptions, executing them in sequence rather than
producing tarchive output.
$ echo '!execvm/posix/command/v1 {argv: [echo, hello, world]}' \ | python -m execvm.ysh hello, world
Commands can be defined statically in YAML or through a python API a
la ytree
, which is also exposed through ursula.compile
. I
started this example in the ytree post. In
that case I had a shell script that defined a version monitoring
pipeline. This is a lua script that generates a sequence of commands
(an execvm
script) equivalent to the original shell script.
local execvm = require("execvm") local ursula = require("ursula") return function (values) domain = ursula.env("DOMAIN", values.domain) url = domain .. "/status.yaml" ursula.execv { argv = {"curl", "-s", url}, stdout = execvm.posix.command { argv = {"python", "-m", "ytree.tar", "-c"}, stdout = execvm.posix.command { argv = {"tar", "-Oxf", "-", "version.yaml"}, stdout = execvm.posix.command { argv = {"python", "-m", "ytree.tar", "-c"}, stdout = execvm.posix.command { argv = {"tar", "-Oxf", "-", "version"} } } } } } end
The determination of that URL happens at ursula.compile
runtime
and gets baked into the generated script.
$ DOMAIN=http://localhost:8000 \ python -m ursula.compile --values values.yaml monitor --- !execvm/posix/command/v1 argv: [curl, -s, 'http://localhost:8000/status.yaml'] cwd: null env: {} stderr: !execvm/posix/stream/v1 stderr stdout: !execvm/posix/command/v1 argv: [python, -m, ytree.tar, -c] cwd: null env: {} stderr: !execvm/posix/stream/v1 stderr stdout: !execvm/posix/command/v1 argv: [tar, -Oxf, '-', version.yaml] cwd: null env: {} stderr: !execvm/posix/stream/v1 stderr stdout: !execvm/posix/command/v1 argv: [python, -m, ytree.tar, -c] cwd: null env: {} stderr: !execvm/posix/stream/v1 stderr stdout: !execvm/posix/command/v1 argv: [tar, -Oxf, '-', version] cwd: null env: {} stderr: !execvm/posix/stream/v1 stderr stdout: !execvm/posix/stream/v1 stdout
That's a little verbose but it's just a stream of commands so it can
pipe right into execvm.ysh
. The pipeline itself can also be
captured as an execvm
command.
--- !execvm/posix/command/v1 argv: [python, -m, dynastyf.ursula, --values, values.yaml, monitor] stdout: !execvm/posix/command/v1 argv: [python, -m, execvm.ysh]
All the referenced files are in the blog source and included directly
into this page for these snippets. The files/
directory at the
root of the repository contains these entries.
I can point DOMAIN
at localhost to run against the nikola
serve
instance that's running while I write or run without the
override, which defaults to polling from the website. That's
functional but it's still assuming there's a shell for running
everything so I still need one more layer of abstraction to glue it
all together. And there's a weird hidden hardcoded URL in there still,
but don't look too much at that. Or do, you made it this far!