Skip to content

Commit 8bcca38

Browse files
committed
feat: enhance flake for build cache performance
1 parent 772b9cf commit 8bcca38

5 files changed

Lines changed: 215 additions & 89 deletions

File tree

.github/workflows/nix.yml

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,26 @@ concurrency:
2727

2828
jobs:
2929
build:
30-
name: Build
31-
runs-on: ubuntu-latest
30+
name: Build (${{ matrix.system }})
31+
strategy:
32+
fail-fast: false
33+
matrix:
34+
include:
35+
- system: x86_64-linux
36+
runner: depot-ubuntu-24.04-8
37+
- system: aarch64-linux
38+
runner: depot-ubuntu-22.04-arm-8
39+
- system: aarch64-darwin
40+
runner: depot-macos-14
41+
runs-on: ${{ matrix.runner }}
3242
steps:
3343
- uses: actions/checkout@v4
3444
- uses: DeterminateSystems/nix-installer-action@v14
45+
- uses: cachix/cachix-action@v17
46+
with:
47+
name: moonrepo
48+
authToken: ${{ github.event_name != 'pull_request' && secrets.CACHIX_AUTH_TOKEN || '' }}
3549
- name: Check flake
36-
run: nix flake check --no-build --no-write-lock-file
50+
run: nix flake check --no-build --no-write-lock-file --accept-flake-config
3751
- name: Build package
38-
run: nix build .#default -L
52+
run: nix build .#packages.${{ matrix.system }}.default -L --accept-flake-config

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,8 @@ dockerManifest.json
5050
# AI / agents
5151
.claude/settings.local.json
5252
.claude/worktrees
53+
54+
# Nix
55+
result
56+
result-*
57+
.direnv/

docs/NIX.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ gives contributors on NixOS a dev shell with the right toolchain. It is independ
55
[nixpkgs `moon` package](https://search.nixos.org/packages?query=moon), which is maintained by
66
nixpkgs contributors on their own schedule.
77

8-
Outputs, for `x86_64-linux` and `aarch64-linux`:
8+
Outputs, for `x86_64-linux`, `aarch64-linux`, and `aarch64-darwin`:
99

10-
- `packages.default` builds the `moon` and `moonx` binaries with shell completions.
10+
- `packages.default` and `packages.moon` build the `moon` and `moonx` binaries with shell
11+
completions.
12+
- `packages.moon-deps` exposes the compiled Cargo dependencies for cache warming.
13+
- `apps.default` runs the `moon` binary.
1114
- `devShells.default` provides the Rust toolchain, `just`, and `cargo-nextest`.
1215

1316
## Releases
@@ -17,7 +20,7 @@ package and the `meta.changelog` link without touching `flake.nix`.
1720

1821
## Updating inputs
1922

20-
The flake pins nixpkgs, flake-utils, and rust-overlay in `flake.lock`. To move them forward:
23+
The flake pins nixpkgs, flake-utils, rust-overlay, and Crane in `flake.lock`. To move them forward:
2124

2225
```shell
2326
nix flake update
@@ -42,21 +45,30 @@ gigabytes to the closure.
4245
time. `openssl` plus `OPENSSL_NO_VENDOR` make reqwest link against the system library rather than
4346
compiling a vendored copy, which the `native-tls-vendored` feature would otherwise do.
4447

45-
Cargo dependencies are vendored from `Cargo.lock` through `cargoLock.lockFile`. If moon ever takes a
46-
dependency from a git source, that will need a `cargoLock.outputHashes` entry for it.
48+
Crane vendors Cargo dependencies from `Cargo.lock`. If moon ever takes a dependency from a git
49+
source, Crane will vendor it from the locked revision.
50+
51+
Crane compiles dependencies separately from the final package so application changes can reuse them.
52+
The package source is restricted to Cargo sources and compile-time assets, preventing unrelated files
53+
and version control metadata from invalidating the build.
4754

4855
Tests run with `doCheck = false`. They download Node.js, Bun, Deno, and other toolchains at runtime,
4956
which the Nix sandbox blocks.
5057

5158
## CI
5259

53-
`.github/workflows/nix.yml` runs `nix flake check` and `nix build .#default` when `flake.nix`,
54-
`flake.lock`, `Cargo.toml`, `Cargo.lock`, `rust-toolchain.toml`, or anything under `crates/`
55-
changes. There is no binary cache wired up, so the job compiles moon from source every time.
60+
`.github/workflows/nix.yml` runs `nix flake check` and builds the package for every supported Linux
61+
and macOS system when `flake.nix`, `flake.lock`, `Cargo.toml`, `Cargo.lock`, `rust-toolchain.toml`, or
62+
anything under `crates/` changes. All jobs pull from the public `moonrepo` Cachix cache. Trusted push
63+
and manual runs publish new paths when the repository has a `CACHIX_AUTH_TOKEN` secret; pull requests
64+
remain read-only.
65+
66+
The flake advertises the cache through `nixConfig`. Pass `--accept-flake-config` when running Nix
67+
non-interactively, or configure the cache with `cachix use moonrepo`.
5668

5769
Before pushing a change to the flake, run the same two commands locally:
5870

5971
```shell
60-
nix flake check
61-
nix build .#default
72+
nix flake check --accept-flake-config
73+
nix build .#default --accept-flake-config
6274
```

flake.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 154 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,174 @@
11
{
22
description = "A monorepo build system and task runner for the web ecosystem";
33

4+
nixConfig = {
5+
extra-substituters = [ "https://moonrepo.cachix.org" ];
6+
extra-trusted-public-keys = [
7+
"moonrepo.cachix.org-1:n4zm4mkV1Eoqck4mQvAhJM28EQwFLU7kW4dEbtAXbD8="
8+
];
9+
};
10+
411
inputs = {
512
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
613
flake-utils.url = "github:numtide/flake-utils";
14+
crane.url = "github:ipetkov/crane";
715
rust-overlay = {
816
url = "github:oxalica/rust-overlay";
917
inputs.nixpkgs.follows = "nixpkgs";
1018
};
1119
};
1220

13-
outputs = { self, nixpkgs, flake-utils, rust-overlay }:
14-
flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system:
15-
let
16-
pkgs = import nixpkgs {
17-
inherit system;
18-
overlays = [ rust-overlay.overlays.default ];
19-
};
20-
21-
rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
22-
23-
devRustToolchain = rustToolchain.override {
24-
extensions = [ "rust-src" ];
25-
};
26-
27-
moonVersion = (builtins.fromTOML
28-
(builtins.readFile ./crates/cli/Cargo.toml)).package.version;
29-
30-
nativeDeps = with pkgs; [ pkg-config protobuf ];
31-
buildDeps = with pkgs; [ openssl ];
32-
in
33-
{
34-
packages.default = (pkgs.makeRustPlatform {
35-
cargo = rustToolchain;
36-
rustc = rustToolchain;
37-
}).buildRustPackage {
38-
pname = "moon";
39-
version = moonVersion;
40-
src = ./.;
41-
42-
cargoLock.lockFile = ./Cargo.lock;
43-
44-
nativeBuildInputs = nativeDeps ++ (with pkgs; [
45-
installShellFiles
46-
writableTmpDirAsHomeHook
47-
]);
48-
buildInputs = buildDeps;
49-
50-
env = {
51-
RUSTFLAGS = "-C strip=symbols";
52-
OPENSSL_NO_VENDOR = "1";
21+
outputs =
22+
{
23+
self,
24+
nixpkgs,
25+
flake-utils,
26+
crane,
27+
rust-overlay,
28+
}:
29+
flake-utils.lib.eachSystem
30+
[
31+
"x86_64-linux"
32+
"aarch64-linux"
33+
"aarch64-darwin"
34+
]
35+
(
36+
system:
37+
let
38+
pkgs = import nixpkgs {
39+
inherit system;
40+
overlays = [ rust-overlay.overlays.default ];
5341
};
5442

55-
postInstall = pkgs.lib.optionalString
56-
(pkgs.stdenv.hostPlatform.emulatorAvailable pkgs.buildPackages)
57-
(
58-
let emulator = pkgs.stdenv.hostPlatform.emulator pkgs.buildPackages;
59-
in ''
60-
installShellCompletion --cmd moon \
61-
--bash <(${emulator} $out/bin/moon completions --shell bash) \
62-
--fish <(${emulator} $out/bin/moon completions --shell fish) \
63-
--zsh <(${emulator} $out/bin/moon completions --shell zsh)
64-
''
65-
);
66-
67-
doCheck = false;
68-
69-
meta = with pkgs.lib; {
70-
description = "A monorepo build system and task runner for the web ecosystem";
71-
mainProgram = "moon";
72-
homepage = "https://github.com/moonrepo/moon";
73-
changelog = "https://github.com/moonrepo/moon/releases/tag/v${moonVersion}";
74-
license = licenses.mit;
75-
maintainers = [ ];
76-
platforms = platforms.linux;
43+
rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
44+
45+
devRustToolchain = rustToolchain.override {
46+
extensions = [ "rust-src" ];
7747
};
78-
};
7948

80-
devShells.default = pkgs.mkShell {
81-
nativeBuildInputs = nativeDeps ++ [
82-
devRustToolchain
83-
pkgs.just
84-
pkgs.cargo-nextest
49+
craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;
50+
51+
moonVersion = (builtins.fromTOML (builtins.readFile ./crates/cli/Cargo.toml)).package.version;
52+
53+
nativeDeps = with pkgs; [
54+
pkg-config
55+
protobuf
56+
];
57+
buildDeps = with pkgs; [ openssl ] ++ lib.optionals stdenv.hostPlatform.isDarwin [ libiconv ];
58+
59+
cargoFiles = pkgs.lib.fileset.unions [
60+
./Cargo.toml
61+
./Cargo.lock
62+
./.cargo/config.toml
63+
(craneLib.fileset.commonCargoSources ./crates)
8564
];
86-
buildInputs = buildDeps;
8765

88-
env = {
89-
OPENSSL_NO_VENDOR = "1";
90-
RUST_SRC_PATH = "${devRustToolchain}/lib/rustlib/src/rust/library";
66+
cargoSource = pkgs.lib.fileset.toSource {
67+
root = ./.;
68+
fileset = cargoFiles;
69+
};
70+
71+
source = pkgs.lib.fileset.toSource {
72+
root = ./.;
73+
fileset = pkgs.lib.fileset.unions [
74+
cargoFiles
75+
./crates/daemon-proto/proto
76+
./crates/config-loader/res
77+
./crates/docker/templates/Dockerfile.tera
78+
./crates/app/src/commands/graph/html.tera
79+
./crates/query/src/mql.pest
80+
];
81+
};
82+
83+
commonArgs = {
84+
pname = "moon";
85+
version = moonVersion;
86+
src = source;
87+
88+
cargoExtraArgs = "--locked --package moon_cli --bins";
89+
strictDeps = true;
90+
doCheck = false;
91+
92+
nativeBuildInputs = nativeDeps;
93+
buildInputs = buildDeps;
94+
95+
env = {
96+
RUSTFLAGS = "-C strip=symbols";
97+
OPENSSL_NO_VENDOR = "1";
98+
};
99+
};
100+
101+
cargoArtifacts = craneLib.buildDepsOnly (
102+
commonArgs
103+
// {
104+
src = cargoSource;
105+
buildPhaseCargoCommand = "cargo build --release --locked --package moon_cli --bins";
106+
}
107+
);
108+
109+
moon = craneLib.buildPackage (
110+
commonArgs
111+
// {
112+
inherit cargoArtifacts;
113+
114+
nativeBuildInputs =
115+
nativeDeps
116+
++ (with pkgs; [
117+
installShellFiles
118+
writableTmpDirAsHomeHook
119+
]);
120+
121+
postInstall =
122+
pkgs.lib.optionalString (pkgs.stdenv.hostPlatform.emulatorAvailable pkgs.buildPackages)
123+
(
124+
let
125+
emulator = pkgs.stdenv.hostPlatform.emulator pkgs.buildPackages;
126+
in
127+
''
128+
installShellCompletion --cmd moon \
129+
--bash <(${emulator} $out/bin/moon completions --shell bash) \
130+
--fish <(${emulator} $out/bin/moon completions --shell fish) \
131+
--zsh <(${emulator} $out/bin/moon completions --shell zsh)
132+
''
133+
);
134+
135+
meta = with pkgs.lib; {
136+
description = "A monorepo build system and task runner for the web ecosystem";
137+
mainProgram = "moon";
138+
homepage = "https://github.com/moonrepo/moon";
139+
changelog = "https://github.com/moonrepo/moon/releases/tag/v${moonVersion}";
140+
license = licenses.mit;
141+
maintainers = [ ];
142+
platforms = platforms.linux ++ [ "aarch64-darwin" ];
143+
};
144+
}
145+
);
146+
in
147+
{
148+
packages = {
149+
inherit moon;
150+
moon-deps = cargoArtifacts;
151+
default = moon;
152+
};
153+
154+
apps.default = {
155+
type = "app";
156+
program = "${moon}/bin/moon";
157+
};
158+
159+
devShells.default = pkgs.mkShell {
160+
nativeBuildInputs = nativeDeps ++ [
161+
devRustToolchain
162+
pkgs.just
163+
pkgs.cargo-nextest
164+
];
165+
buildInputs = buildDeps;
166+
167+
env = {
168+
OPENSSL_NO_VENDOR = "1";
169+
RUST_SRC_PATH = "${devRustToolchain}/lib/rustlib/src/rust/library";
170+
};
91171
};
92-
};
93-
}
94-
);
172+
}
173+
);
95174
}

0 commit comments

Comments
 (0)