Packaging a patterns crate derivation, devShell, flake check
Beat A taught pattern places and refutability. Beat B puts that binary behind a store path, a shell, and a check.
<!-- hal:authoritative:yaml -->
Beat A taught pattern places and refutability. Beat B puts that binary behind a store path, a shell, and a check.
§I - Frame
Duha Beat B, Nix packaging session 05. Beat A (Rust session 22) taught the Place Map, the Refutability Gate, and the Syntax Kit from TRPL Ch.19. This shell packages a small crate that exercises those moves: one derivation that builds the binary, one devShell that holds the toolchain, one checks entry that nix flake check can run.
Session 04 packaged yesterday's trait-objects crate. Same three packaging moves, new crate noun. Asr owns the Pills cursor and the later Rust-roads rows (#16 crate-as-derivation, #19 flake devShell/checks). Those Done cells stay unmarked today. This bundle does not consume a Pill.
Three moves land by the end:
- The Crate Derivation: read
rustPlatform.buildRustPackagefor a patterns demo binary (src, lock hash, what lands in$out). - The Dev Shell: name
devShells.defaultas the editable toolchain, not the release store path. - The Flake Check: say what
nix flake checkbuilds from thechecksattribute set.
Done-criteria: Can sketch a buildRustPackage for a patterns binary, open a Rust devShell, and name one flake checks entry that proves the build.
§II - The Crate Derivation
A derivation is still a build spec: inputs in, store path out. For Rust, nixpkgs wraps that as rustPlatform.buildRustPackage. The rust-tops corpus shows the shape in nix/cargo-tops.nix (read-only teach from the repo; no bot build cadence):
{
lib,
rustPlatform,
}:
rustPlatform.buildRustPackage {
pname = "cargo-tops";
version = "0.1.3";
src = lib.cleanSource ../.;
cargoLock.lockFile = ../Cargo.lock;
buildAndTestSubdir = "crates/cargo-tops";
doCheck = true;
meta = {
description = "init / check / gate for the Rust-TOPS protocol";
mainProgram = "cargo-tops";
};
}
Read it the way NIX-SYLLABUS row #16 asks: src is the crate tree; cargoLock.lockFile (or cargoHash when you vendor differently) pins the crate graph; buildAndTestSubdir selects a workspace member; doCheck runs cargo test in the sandbox; the binary lands under $out (usually $out/bin/<mainProgram>).
For today's Patterns lesson, the same skeleton fits a single-binary crate whose main places patterns in match, if let, while let, and let, prints which arm or binding fired, and exits. Swap pname to something like patterns-demo, point src at that crate, keep a real Cargo.lock in tree. The demo can stay on std alone: an Option, a small enum, one destructuring let, one match guard, one @ binding. No network fetches during nix build. Prefer cargoLock.lockFile when the tree has a lock; use cargoHash only when that is the pin style you keep.
Sandbox honesty still rules. Flake inputs and the lock hash must explain every byte that enters the builder. A print-and-exit binary proves the Place Map without needing external services.
§III - The Dev Shell
A release derivation is not a workspace. While you edit the patterns crate you want rustc, cargo, clippy, and rustfmt on PATH without baking them into the binary's runtime closure. That is devShells:
devShells = forAllSystems (
system:
let
pkgs = pkgsFor system;
in
{
default = pkgs.mkShell {
packages = [
pkgs.rustc
pkgs.cargo
pkgs.clippy
pkgs.rustfmt
];
};
}
);
The rust-tops flake.nix uses that pattern (plus cargo-tops itself on the shell). Enter with nix develop. Build the release path separately with nix build .#patterns-demo (or whatever you named the package). Mixing those two jobs is how people ship a toolchain as a runtime dependency by accident.
Pattern matching lives in the Rust binary at match / if let sites, not in the Nix shell. The shell only gives you a pinned compiler so cargo run and cargo test match what the derivation will see.
§IV - The Flake Check
packages is what you install. checks is what CI (and you) ask Nix to build for proof. From the same corpus flake:
checks = forAllSystems (
system:
let
pkgs = pkgsFor system;
in
{
cargo-tops = self.packages.${system}.cargo-tops;
# ... other proofs ...
}
);
nix flake check builds every attribute under checks for the current system. Putting the patterns package itself in checks proves the derivation evaluates and builds. A tighter check can runCommand the binary and assert it prints the expected arm lines, still without standing up a second lesson store of tests outside the flake.
Three outputs, three jobs: packages ships, devShells edits, checks proves. That is the packaging shell for Beat A's Patterns crate.
§V - Proof and close
- Copy the
buildRustPackageskeleton, rename it for a patterns binary, and say whatcargoLock.lockFilepins. - Open a
mkShellwithrustc/cargoand state why those packages are notbuildInputsof the release derivation. - Add the package to
checksand say whatnix flake checkwill build. - Name which Asr NIX-SYLLABUS rows teach the same moves later (#16, #19) and confirm this Duha bundle did not mark them.
Done-criteria: Can sketch a buildRustPackage for a patterns binary, open a Rust devShell, and name one flake checks entry that proves the build.
Asr keeps the next unmarked Pill / Rust-roads row. Duha Beat B only packages today's T1 crate.