Unit Files
Unit files end in .want. Each unit file declares a single Target.
A unit file is a Spore body with two exports:
build = (#import "want:build")
paths = (#import "want:build/paths")
.input = [
(paths.unit "./input.txt")
]
.do = \(ctx: build.Ctx) build.FS {
(build.pick ctx.jobs ctx.input "input.txt")
}
.inputis a list of PathSets the target reads; the list is implicitly OR'd together. An empty list means the target reads nothing..dois a proc that is called to produce the build. It is handed abuild.Ctx(its job port onctx.jobs, and its filtered input tree onctx.input) and returns anFS.
The output path
A unit file does not declare its output; it is derived from the file's name.
A file hello.txt.want produces the output path hello.txt, and a file
build/app.want produces build/app.
The FS returned by do is shifted into place under that path. A flat
single-file FS (the result of picking a file) lands exactly at the output
path; a tree becomes the subtree beneath it.
The build fails during planning if the derived output path already exists in the source tree, so a target can never silently overwrite a source file.
Path rules
Paths in .input are module-root-relative, with two exceptions:
- A path beginning with
./is relative to the directory of the unit file. Ina/build_my_output.want, the input./input.txtnamesa/input.txt, whileinput.txtnames the file at the module root. - Paths may not begin with
/(absolute paths are rejected), may not be empty, and may not contain a..segment.
Inputs implicitly exclude the target's own output path.
Example: download a rootfs
fetch.want downloads a pinned Alpine minirootfs and returns it:
build = (#import "want:build")
alpine = (#import "want:linux/dist/alpine")
.input = []
.do = \(ctx: build.Ctx) build.FS {
(alpine.rootfs ctx.jobs)
}
The result lands at fetch/ in the build output. want ls fetch lists it,
and want build computes the whole module.