From 8b6bd20a6a2c2aa4a5b21a9617da78a0e5c36ec3 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 3 Feb 2026 20:31:02 -0700 Subject: [PATCH] Try to improve nix caching (#48297) Release Notes: - N/A --- .github/workflows/release_nightly.yml | 23 ++++++++ .github/workflows/run_tests.yml | 23 ++++++++ flake.nix | 2 +- .../xtask/src/tasks/workflows/nix_build.rs | 54 +++++++++++++++++-- tooling/xtask/src/tasks/workflows/steps.rs | 11 ++++ 5 files changed, 108 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release_nightly.yml b/.github/workflows/release_nightly.yml index f6f3bf6659fd463805c866094602123e0249c6b5..942f39c45266122e5a8919b3daea9e7e5d82c252 100644 --- a/.github/workflows/release_nightly.yml +++ b/.github/workflows/release_nightly.yml @@ -387,6 +387,10 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: clean: false + - name: steps::cache_nix_dependencies_namespace + uses: namespacelabs/nscloud-cache-action@v1 + with: + cache: nix - name: nix_build::build_nix::install_nix uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f with: @@ -417,10 +421,20 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: clean: false + - name: steps::cache_nix_store_macos + uses: namespacelabs/nscloud-cache-action@v1 + with: + path: ~/nix-cache - name: nix_build::build_nix::install_nix uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f with: github_access_token: ${{ secrets.GITHUB_TOKEN }} + - name: nix_build::build_nix::configure_local_nix_cache + run: | + mkdir -p ~/nix-cache + echo "extra-substituters = file://$HOME/nix-cache?priority=10" | sudo tee -a /etc/nix/nix.conf + echo "require-sigs = false" | sudo tee -a /etc/nix/nix.conf + sudo launchctl kickstart -k system/org.nixos.nix-daemon - name: nix_build::build_nix::cachix_action uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad with: @@ -429,6 +443,15 @@ jobs: cachixArgs: -v - name: nix_build::build_nix::build run: nix build .#default -L --accept-flake-config + - name: nix_build::build_nix::export_to_local_nix_cache + if: always() + run: | + if [ -L result ]; then + echo "Copying build closure to local binary cache..." + nix copy --to "file://$HOME/nix-cache" ./result || echo "Warning: nix copy to local cache failed" + else + echo "No build result found, skipping cache export." + fi timeout-minutes: 60 continue-on-error: true update_nightly_tag: diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 5358f19631a63629d841b29d03c0b162eeb69313..2621831b48bf4b78a786bc86cc4eee024842bf44 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -478,6 +478,10 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: clean: false + - name: steps::cache_nix_dependencies_namespace + uses: namespacelabs/nscloud-cache-action@v1 + with: + cache: nix - name: nix_build::build_nix::install_nix uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f with: @@ -508,10 +512,20 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: clean: false + - name: steps::cache_nix_store_macos + uses: namespacelabs/nscloud-cache-action@v1 + with: + path: ~/nix-cache - name: nix_build::build_nix::install_nix uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f with: github_access_token: ${{ secrets.GITHUB_TOKEN }} + - name: nix_build::build_nix::configure_local_nix_cache + run: | + mkdir -p ~/nix-cache + echo "extra-substituters = file://$HOME/nix-cache?priority=10" | sudo tee -a /etc/nix/nix.conf + echo "require-sigs = false" | sudo tee -a /etc/nix/nix.conf + sudo launchctl kickstart -k system/org.nixos.nix-daemon - name: nix_build::build_nix::cachix_action uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad with: @@ -521,6 +535,15 @@ jobs: pushFilter: -zed-editor-[0-9.]*-nightly - name: nix_build::build_nix::build run: nix build .#debug -L --accept-flake-config + - name: nix_build::build_nix::export_to_local_nix_cache + if: always() + run: | + if [ -L result ]; then + echo "Copying build closure to local binary cache..." + nix copy --to "file://$HOME/nix-cache" ./result || echo "Warning: nix copy to local cache failed" + else + echo "No build result found, skipping cache export." + fi timeout-minutes: 60 continue-on-error: true check_postgres_and_protobuf_migrations: diff --git a/flake.nix b/flake.nix index e671d8ff7eb1b69297eaab6357b78e2d8e360737..3a9744fe1eeb7c4b08b514eb5c31fe407830d7b6 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "High-performance, multiplayer code editor from the creators of Atom and Tree-sitter"; + description = "Zed is a minimal code editor crafted for speed and collaboration with humans and AI."; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; diff --git a/tooling/xtask/src/tasks/workflows/nix_build.rs b/tooling/xtask/src/tasks/workflows/nix_build.rs index 21fb8898bb31adcdacd56487e26c592593dbcfce..9e401ccac08bc6439cbd3aff60a576e2d6933c3b 100644 --- a/tooling/xtask/src/tasks/workflows/nix_build.rs +++ b/tooling/xtask/src/tasks/workflows/nix_build.rs @@ -44,6 +44,32 @@ pub(crate) fn build_nix( )) } + // After install-nix, register ~/nix-cache as a local binary cache + // substituter so nix pulls from it on demand during builds (no bulk + // import). Also restart the daemon so it picks up the new config. + pub fn configure_local_nix_cache() -> Step { + named::bash(indoc::indoc! {r#" + mkdir -p ~/nix-cache + echo "extra-substituters = file://$HOME/nix-cache?priority=10" | sudo tee -a /etc/nix/nix.conf + echo "require-sigs = false" | sudo tee -a /etc/nix/nix.conf + sudo launchctl kickstart -k system/org.nixos.nix-daemon + "#}) + } + + // Incrementally copy only new store paths from the build result's + // closure into the local binary cache for the next run. + pub fn export_to_local_nix_cache() -> Step { + named::bash(indoc::indoc! {r#" + if [ -L result ]; then + echo "Copying build closure to local binary cache..." + nix copy --to "file://$HOME/nix-cache" ./result || echo "Warning: nix copy to local cache failed" + else + echo "No build result found, skipping cache export." + fi + "#}) + .if_condition(Expression::new("always()")) + } + let runner = match platform { Platform::Windows => unimplemented!(), Platform::Linux => runners::LINUX_X86_BUNDLER, @@ -67,10 +93,30 @@ pub(crate) fn build_nix( job = job.needs(deps.iter().map(|d| d.name.clone()).collect::>()); } - job = job - .add_step(install_nix()) - .add_step(cachix_action(cachix_filter)) - .add_step(build(&flake_output)); + // On Linux, `cache: nix` uses bind-mounts so the /nix store is available + // before install-nix-action runs — no extra steps needed. + // + // On macOS, `/nix` lives on a read-only root filesystem and the nscloud + // cache action cannot mount or symlink there. Instead we cache a + // user-writable directory (~/nix-cache) as a local binary cache and + // register it as a nix substituter. Nix then pulls paths from it on + // demand during builds (zero-copy at startup), and after building we + // incrementally copy new paths into the cache for the next run. + job = match platform { + Platform::Linux => job + .add_step(steps::cache_nix_dependencies_namespace()) + .add_step(install_nix()) + .add_step(cachix_action(cachix_filter)) + .add_step(build(&flake_output)), + Platform::Mac => job + .add_step(steps::cache_nix_store_macos()) + .add_step(install_nix()) + .add_step(configure_local_nix_cache()) + .add_step(cachix_action(cachix_filter)) + .add_step(build(&flake_output)) + .add_step(export_to_local_nix_cache()), + Platform::Windows => unimplemented!(), + }; NamedJob { name: format!("build_nix_{platform}_{arch}"), diff --git a/tooling/xtask/src/tasks/workflows/steps.rs b/tooling/xtask/src/tasks/workflows/steps.rs index 6db4f2fa6c6b80c1a2dd1b22a9b9303296e9e4da..26a2f0407188f2599f6bee9e5c5936dfe2ae45eb 100644 --- a/tooling/xtask/src/tasks/workflows/steps.rs +++ b/tooling/xtask/src/tasks/workflows/steps.rs @@ -138,6 +138,17 @@ pub fn cache_rust_dependencies_namespace() -> Step { .add_with(("path", "~/.rustup")) } +pub fn cache_nix_dependencies_namespace() -> Step { + named::uses("namespacelabs", "nscloud-cache-action", "v1").add_with(("cache", "nix")) +} + +pub fn cache_nix_store_macos() -> Step { + // On macOS, `/nix` is on a read-only root filesystem so nscloud's `cache: nix` + // cannot mount or symlink there. Instead we cache a user-writable directory and + // use nix-store --import/--export in separate steps to transfer store paths. + named::uses("namespacelabs", "nscloud-cache-action", "v1").add_with(("path", "~/nix-cache")) +} + pub fn setup_linux() -> Step { named::bash("./script/linux") }