Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Buck2 Integration

Turnkey provides first-class Buck2 integration with automatic toolchain and dependency cell generation.

Enabling Buck2

In your flake.nix:

turnkey.toolchains = {
  enable = true;
  declarationFiles.default = ./toolchain.toml;
  buck2.enable = true;
};

By default only the default shell gets the Buck2 integration: the pinned buck2 on its PATH, the prelude, and the generated cells. List other shells in buck2.shells to give them the integration too:

turnkey.toolchains = {
  declarationFiles = {
    default = ./toolchain.toml;
    ci = ./toolchain.ci.toml;
    docs = ./docs/toolchain.toml;   # no Buck2 here
  };
  buck2 = {
    enable = true;
    shells = [ "default" "ci" ];
  };
};

Naming a shell that declarationFiles doesn't define is an error.

The buck2 version

Each turnkey revision ships exactly one buck2 release, together with the prelude built with it. You don't choose buck2 in toolchain.toml: you get a newer buck2 by updating your turnkey input (nix flake update turnkey). Turnkey's test runner speaks buck2's internal test protocol and its prelude is patched for one prelude revision, so each only works against the release it was built for (ADR 0002).

To see which release you have, read turnkey.toolchains.buck2.version, or look at the shell's welcome message, which ends with (buck2 <version>) when a welcomeMessage is set.

Migrating from a declared buck2

Earlier turnkey revisions took buck2 from toolchain.toml. Declaring it now fails evaluation:

error: turnkey: /nix/store/…-source/toolchain.toml declares buck2-toolchain, but turnkey now ships buck2 itself.

To migrate:

  1. Remove the buck2 or buck2-toolchain entry from every toolchain.toml.
  2. Keep buck2.enable = true; in flake.nix. If a shell other than default used to declare buck2, add its name to buck2.shells. Before, declaring buck2 is what gave a shell the Buck2 integration.
  3. buck2-toolchain also carried reindeer. If you use it, declare reindeer = {} in toolchain.toml.

To run a different buck2 anyway, override turnkey's toolbox input with follows. This is unsupported: test result caching or the prelude may break against another release.

Generated Cells

When Buck2 integration is enabled, Turnkey generates:

Toolchains Cell

Located at .turnkey/toolchains/, contains toolchain rules for each declared language:

  • toolchains//:go - Go toolchain
  • toolchains//:rust - Rust toolchain
  • toolchains//:python - Python toolchain
  • etc.

It also holds toolchains//conditions:<os>-<cpu>, one config_setting per platform in buck2.platforms (the flake's systems by default), combining its OS and CPU constraints. Rules sync keys a select() on one when deps differ by CPU within one OS (Platform-Conditional Deps). With buck2.go.allowedBuildTags, which also sets .buckconfig's go.allowed_build_tags, it holds the settings combining the platform's OS and CPU with each allowed tag, set (linux-x86_64-integration) or unset (linux-no_integration), for a Go library whose imports depend on a tag.

Prelude Cell

The Buck2 prelude is provided via Nix at .turnkey/prelude/: the prelude built with turnkey's pinned buck2 release, with turnkey's patches and extensions applied.

The prelude and toolchains cells are symlinks into the Nix store. After either changes, a plain buck2 call needs a tk call or a buck2 kill first: see Symlinked Cells and Plain buck2.

A Prelude of Your Own

prelude.path replaces turnkey's prelude with a derivation or a path. It is off the supported path, and it turns test result caching off:

turnkey.toolchains.buck2.prelude.path = ./my-prelude;

Directories Buck2 Doesn't See

The generated .buckconfig's project.ignore lists directories, relative to the project root, that buck2 skips: //... doesn't load their rules.star files, and buck2's file watcher drops their events, so they never show up as File changed: lines. turnkey always ignores two kinds of directory that no build reads but something writes to all the time:

  • the VCS's metadata: .git, .jj, .hg, .sl;
  • the devenv and direnv state: .devenv, .direnv.

ignore adds to them. Use it for trees that are projects of their own, such as test fixtures whose targets only build in their own checkout:

turnkey.toolchains.buck2.ignore = [ "e2e/fixtures" ];

Buck2 reads project.ignore when its daemon starts, so a change takes effect once the daemon restarts. .buckconfig is a store symlink, so tk restarts it on its next command; plain buck2 needs a buck2 kill first (Symlinked Cells and Plain buck2).

Dependency Cells

Language-specific dependency cells are generated when configured:

  • godeps// - Go dependencies from go-deps.toml
  • rustdeps// - Rust dependencies from rust-deps.toml
  • pydeps// - Python dependencies from python-deps.toml
  • jsdeps// - JavaScript dependencies from js-deps.toml
  • soldeps// - Solidity dependencies from solidity-deps.toml

They are write-once directories, which plain buck2 reads without a daemon restart.

See Managing Dependencies for configuration details.