[bldr]docs
Concepts

Pods

The container a build step runs in, and what goes in and comes out.

A pod is a container bldr runs one build step in. Content goes in as mounts, a command runs, and content comes out as a capture.

You will meet pods through the builders in bldr/node-tools and bldr/rust-tools, which make them for you. Reach for one directly when nothing existing fits.

import { ContainerImage } from "bldr";
import debian from "debian";

const out = ContainerImage.fromMember(debian, "amd64")
    .pod()
    .mount(sourceTree, "/src")
    .workdir("/src")
    .run("make && mkdir -p /out && cp build/thing /out/")
    .capture("/out");

What a pod can be given

.mount(tree, dest)a tree, read-only by default
.mount(tree, dest, { mutable: true })a writable overlay whose diff you can capture
.cache(volume, dest)a cache volume, kept between runs
.env(key, value)an environment variable
.workdir(dir)where the command starts

What you can take out

.capture(path)what the run changed under that path
.captureMerged(path)everything visible there, changed or not
.mountDelta(id, subpath)what it wrote into a mutable mount
.logs()the pod's stdout and stderr, as a file
.exitCode()the exit code, as a value you can branch on

The distinction between capture and captureMerged catches people out. capture gives you the overlay diff, which is what the run created or modified. If your build writes to /out that is what you want. If you need a file the run did not touch, you want the merged view.

The rules that will bite you

A pod runs once. Every output of one pod shares that single run, so asking for several outputs does not run it several times. The flip side: declare every mount, command and capture before anything forces the pod. Changing it afterwards throws rather than being quietly ignored.

A non-zero exit fails the build, at that pod's task, with its log. When a non-zero exit is data rather than failure, say so with .allowExit(), and read .exitCode().

Mounts are not the rootfs. capture reads the pod's root filesystem, so capturing a path that is a mount point yields nothing. Read a mount back with .mountDelta().

On this page