Files
sausage/host/src/builder/README.md
T

4.7 KiB

Rust builder

The world cargo calls POST http://host.sausage/cargo with argv and cwd. The request also accepts optional timeout_secs. The response contains newline-delimited JSON events. stdout and stderr events contain byte arrays. The final exit event contains a code and component locations. Each location contains an executable path and working directory.

The CLI forwards human output as Cargo emits complete lines. Displayed source and artifact paths use the world's workspace and target directories. The builder hides Cargo's native capture-runner command line. The builder captures compiler JSON for artifact discovery without forwarding it to stdout. Compiler diagnostics remain on stderr. cargo run reserves stdout for the program. cargo new and cargo init use native Cargo, including --lib, --name, and --edition. They need no existing manifest. Subsequent builds use the world's default WASI target. For test and run, it executes the artifacts through the process interface. Cargo selects run binaries through a capture runner, so --bin and default-run retain their normal behavior. The test runner uses each package's root directory, even when the caller runs Cargo from a subdirectory. For test and run, arguments after -- belong to the executable, not the host build. Other commands retain their -- arguments, such as fmt -- --check and Clippy lint options.

The host finds the Cargo workspace above the requested directory and copies its sources through the shared VFS. It excludes target and .git. The copy preserves source symlinks, including dangling links, without following them.

Each workspace owns a source copy and target directory. It also owns a registry and kache cache. These directories live under <dir>/host/builds/.

Cargo fetches dependencies with network access. By default, the command then runs offline inside bubblewrap namespaces. The host-only sausage run --no-builder-sandbox WORLD switch runs Cargo directly instead. Tests use RuntimeOptions.no_builder_sandbox and select it with SAUSAGE_TEST_NO_BUILDER_SANDBOX=1. The switch is not a world config setting. Direct mode uses no user, mount, network, or PID namespaces. It retains the source copy, working directory, private registry, kache settings, timeout, output, and artifact publication.

In the default sandboxed mode, the source copy and target directory permit writes. The private kache cache also permits writes. The registry and Nix store remain read-only. Host home directories and the host network are absent. The PID namespace removes compiler descendants and the private kache daemon after Cargo exits.

The builder copies changed and new source files back through the VFS. It preserves other source files, including concurrent edits in the world. It leaves source symlinks unchanged rather than publishing them as ordinary files. It publishes WASI executables into the world's workspace target directory. After cargo clean, it removes the published artifacts that Cargo removed from the native target. Every target build uses wasm32-wasip2 and links the shared cwd-init object, including its numeric exit-code interface. The host rejects other build targets and --target-dir overrides.

The command deadline defaults to 30 minutes. The host kills timed-out commands before it sends their timeout message. A closed response cancels the native command and its process group.

The host retains at most 20 GiB of build directories and evicts the oldest workspace first. An incomplete cache entry without a usage marker uses its directory timestamp for eviction.

The Nix wrapper supplies these tools on PATH:

  • Rust and the native compiler
  • The WASI C tools
  • Bubblewrap
  • Nushell
  • wasm-tools
  • Kache
  • Bash and Coreutils

Kache comes from the upstream flake at revision 96052b4842239bb216f6c4812054203c21550788. The development shell supplies the same builder tools. The builder resolves the wrapper and interpreter paths to their canonical Nix store paths. The embedded cwd-init sources produce a startup object and a linker script inside each workspace's tool folder. The linker script uses the canonical Nushell interpreter, so it needs no host /usr/bin/env. The sandbox exposes Bash at /bin/sh for native build scripts. It does not depend on a user-profile path or a host HOME file. Development commands retain the global Cargo configuration and its kache wrapper. The sandbox uses a private Cargo home and selects kache through --config build.rustc-wrapper.

For cargo add, the network phase updates the private source copy and fetches the new dependencies, including transitive dependencies. The command then repeats offline inside the namespaces before source publication. The disk cap applies after each completed command, including compiler failures.