Runnables
A runnable is a directory artifact that can be used with brioche run
. A runnable is just an ordinary directory artifact that contains a file or symlink called brioche-run
at the root— this is the executable that gets invoked when calling brioche run
:
import * as std from "std";import { cargoBuild } from "rust";
export default function () { // Build a cargo project // // app // └── bin // └── hello const app = cargoBuild({ source: Brioche.glob("src", "Cargo.*"), });
// Add a symlink for use with `brioche run` // // app // ├── bin // │ └── hello // └── brioche-run -> bin/hello return app.insert("brioche-run", std.symlink({ target: "bin/hello" }));}
If you were to call the above project with brioche run
, then the project would build, then Brioche would execute the brioche-run
symlink from the artifact, which in turn would call bin/hello
.
You could also simplify the above code using the std.withRunnableLink
utility, but the result is the same:
import * as std from "std";import { cargoBuild } from "rust";
export default function () { const app = cargoBuild({ source: Brioche.glob("src", "Cargo.*"), });
return std.withRunnableLink(app, "bin/hello");}
rust.cargoBuild()
also provides a runnable
option to simplify it even more:
import * as std from "std";import { cargoBuild } from "rust";
export default function () { return cargoBuild({ source: Brioche.glob("src", "Cargo.*"), runnable: "bin/hello", });}
Making a runnable from a Bash script
Sometimes, you may want to use brioche run
, but you may not be able to link to a single binary to do what you want to do:
- Calling an interpreter like
node
with a specific script path - Passing default arguments or environment variables to a binary
- Transforming the result of a binary
The utility std.bashRunnable
is meant for these sorts of use cases: it takes a Bash script and some optional extra context, and returns a runnable that executes the script when brioche run
is called. There’s nothing special about it: just like every other runnable, it returns a directory with a brioche-run
executable in it.
import * as std from "std";import nodejs from "nodejs";
export default function () { const nodeProject = Brioche.glob("src/**.js");
return std.bashRunnable` node "$root"/src/script.js ` .root(nodeProject) .dependencies(nodejs());}
.root()
is used to include extra stuff in the root of the artifact, which can be referenced in the script using the $root
environment variable. Dependencies and extra env vars can be bundled in the script using the .dependencies()
and .env()
methods, respectively.
Turning a runnable into a container image
You can use std.ociContainerImage()
to build an OCI container image, e.g. for Docker or Podman. If you don’t set an entrypoint, then /brioche-run
will be used by default. This means you can easily turn any runnable artifact into an OCI container image!
import * as std from "std";import nodejs from "nodejs";
export default function build() { const nodeProject = Brioche.glob("src/**.js");
return std.bashRunnable` node "$root"/src/script.js ` .root(nodeProject) .dependencies(nodejs());}
export function container() { return std.ociContainerImage({ recipe: build(), });}
In this example, you can run brioche run
to run the project natively on your machine, or you can run brioche build -e container -o container.tar
to build an easily-deployable container image.