diff --git a/.github/workflows/nix-verify.yml b/.github/workflows/nix-verify.yml new file mode 100644 index 00000000..b0a4bb8c --- /dev/null +++ b/.github/workflows/nix-verify.yml @@ -0,0 +1,42 @@ +name: Nix Verification + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + nix-verify: + name: Verify nix build and develop + runs-on: ubuntu-latest + defaults: + run: + working-directory: zebra-crosslink + steps: + - uses: actions/checkout@v4 + - name: Install Nix + uses: nixbuild/nix-quick-install-action@v30 + - uses: nix-community/cache-nix-action@v6 + with: + primary-key: nix-${{ runner.os }}-${{ hashFiles('flake.lock', 'zebra-crosslink/flake.lock', 'flake.nix', 'zebra-crosslink/flake.nix', 'zebra-crosslink/flake/**/*.nix') }} # yamllint disable-line rule:line-length + restore-prefixes-first-match: nix-${{ runner.os }}- + purge: true + purge-prefixes: nix-${{ runner.os }}- + purge-created: 0 + purge-primary-key: never + - name: Verify root nix build + working-directory: ${{ github.workspace }} + run: nix build --print-build-logs + - name: Verify nix build + run: nix build --print-build-logs + - name: Verify nix develop cargo build + run: nix develop --command cargo build diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..9bca2d11 --- /dev/null +++ b/flake.nix @@ -0,0 +1,41 @@ +{ + description = "crosslink_monolith flake delegating to zebra-crosslink"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + + crane.url = "github:ipetkov/crane"; + + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + flake-utils.url = "github:numtide/flake-utils"; + + advisory-db = { + url = "github:rustsec/advisory-db"; + flake = false; + }; + }; + + outputs = + inputs: + import ./zebra-crosslink/flake/outputs.nix { + project-name = "zebra-crosslink"; + src-root = ./zebra-crosslink; + rust-toolchain-toml = ./zebra-crosslink/rust-toolchain.toml; + flake-lib-path = ./zebra-crosslink/flake; + nixfmt-check-paths = [ + ./flake.nix + ./zebra-crosslink + ]; + inherit (inputs) + flake-utils + nixpkgs + crane + rust-overlay + advisory-db + ; + }; +} diff --git a/zebra-crosslink/flake.nix b/zebra-crosslink/flake.nix index d3de1cf4..5a82ee38 100644 --- a/zebra-crosslink/flake.nix +++ b/zebra-crosslink/flake.nix @@ -57,199 +57,18 @@ outputs = inputs: - inputs.flake-utils.lib.eachDefaultSystem ( - system: - let - project-name = "zebra-crosslink"; - - # Local utility library: - flakelib = import ./flake inputs { - pname = "${project-name}-workspace"; - src-root = ./.; - rust-toolchain-toml = ./rust-toolchain.toml; - inherit system; - }; - - inherit (flakelib) - build-rust-workspace - links-table - nixpkgs - run-command - select-source - ; - - # We use this style of nix formatting in checks and the dev shell: - nixfmt = nixpkgs.nixfmt-rfc-style; - - # We use the latest nixpkgs `libclang`: - inherit (nixpkgs.llvmPackages) libclang; - - src-book = select-source { - name-suffix = "book"; - paths = [ - ./book - ./README.md - ]; - }; - - src-rust = select-source { - name-suffix = "rust"; - paths = [ - ./.cargo - ./.config - ./Cargo.lock - ./Cargo.toml - ./clippy.toml - ./crosslink-test-data - ./release.toml - ./rust-toolchain.toml - ./tower-batch-control - ./tower-fallback - ./zebra-chain - ./zebra-consensus - ./zebra-crosslink - ./zebra-grpc - ./zebra-network - ./zebra-node-services - ./zebra-rpc - ./zebra-scan - ./zebra-script - ./zebra-state - ./zebra-test - ./zebra-utils - ./zebrad - ]; - }; - - zebrad-outputs = build-rust-workspace ./zebrad { - src = src-rust; - - strictDeps = true; - - # Note: we disable tests since we'll run them all via cargo-nextest - doCheck = false; - - # Use the clang stdenv, overriding any downstream attempt to alter it: - stdenv = _: nixpkgs.llvmPackages.stdenv; - - nativeBuildInputs = with nixpkgs; [ - pkg-config - protobuf - ]; - - buildInputs = with nixpkgs; [ - libclang - rocksdb - ]; - - # Additional environment variables can be set directly - LIBCLANG_PATH = "${libclang.lib}/lib"; - }; - - zebrad = zebrad-outputs.pkg; - - zebra-book = nixpkgs.stdenv.mkDerivation rec { - name = "zebra-book"; - src = src-book; - buildInputs = with nixpkgs; [ - mdbook - mdbook-mermaid - ]; - builder = nixpkgs.writeShellScript "${name}-builder.sh" '' - if mdbook build --dest-dir "$out/book/book" "$src/book" 2>&1 | grep -E 'ERROR|WARN' - then - echo 'Failing due to mdbook errors/warnings.' - exit 1 - fi - ''; - }; - in - { - packages = ( - let - base-pkgs = { - inherit - zebrad - zebra-book - src-book - src-rust - ; - }; - - all = links-table "all" { - "./bin" = "${zebrad}/bin"; - "./book" = "${zebra-book}/book"; - "./src/${project-name}/book" = "${src-book}/book"; - "./src/${project-name}/rust" = src-rust; - }; - in - - base-pkgs - // { - inherit all; - default = all; - } - ); - - checks = ( - zebrad-outputs.checks - // { - # Build the crates as part of `nix flake check` for convenience - inherit zebrad; - - # Check formatting - nixfmt-check = run-command "nixfmt" [ nixfmt ] '' - set -efuo pipefail - exitcode=0 - for f in $(find '${./.}' -type f -name '*.nix') - do - cmd="nixfmt --check --strict \"$f\"" - echo "+ $cmd" - eval "$cmd" || exitcode=1 - done - [ "$exitcode" -eq 0 ] && touch "$out" # signal success to nix - exit "$exitcode" - ''; - } - ); - - apps = { - zebrad = inputs.flake-utils.lib.mkApp { drv = zebrad; }; - }; - - # TODO: BEWARE: This dev shell may have buggy deviations from the build. - devShells.default = ( - let - mkClangShell = nixpkgs.mkShell.override { inherit (nixpkgs.llvmPackages) stdenv; }; - - devShellInputs = with nixpkgs; [ - rustup - mdbook - mdbook-mermaid - nixfmt - yamllint - ]; - - dynlibs = with nixpkgs; [ - libGL - libxkbcommon - xorg.libX11 - xorg.libxcb - xorg.libXi - ]; - - crate-args = zebrad-outputs.args.crate; - in - mkClangShell ( - crate-args - // { - # Include devShell inputs: - nativeBuildInputs = crate-args.nativeBuildInputs ++ devShellInputs; - - LD_LIBRARY_PATH = nixpkgs.lib.makeLibraryPath dynlibs; - } - ) - ); - } - ); + import ./flake/outputs.nix { + project-name = "zebra-crosslink"; + src-root = ./.; + rust-toolchain-toml = ./rust-toolchain.toml; + flake-lib-path = ./flake; + nixfmt-check-paths = [ ./. ]; + inherit (inputs) + flake-utils + nixpkgs + crane + rust-overlay + advisory-db + ; + }; } diff --git a/zebra-crosslink/flake/default.nix b/zebra-crosslink/flake/default.nix index cc0e3b27..f69ff7a6 100644 --- a/zebra-crosslink/flake/default.nix +++ b/zebra-crosslink/flake/default.nix @@ -36,7 +36,7 @@ let in (crane.mkLib pkgs).overrideToolchain fromToolchainFile; - flakelib = { + flakelib = rec { nixpkgs = pkgs; # select-source :: { @@ -54,7 +54,7 @@ let inherit (pkgs.lib.fileset) toSource unions; inherit (pkgs.lib.trivial) flip; inherit (pkgs) symlinkJoin; - inherit (flakelib) run-command; + inherit run-command; base-name = "${pname}-src-${name-suffix}"; diff --git a/zebra-crosslink/flake/outputs.nix b/zebra-crosslink/flake/outputs.nix new file mode 100644 index 00000000..50335016 --- /dev/null +++ b/zebra-crosslink/flake/outputs.nix @@ -0,0 +1,226 @@ +# Shared flake outputs for zebra-crosslink and monorepo wrappers. +{ + project-name, + src-root, + rust-toolchain-toml, + flake-lib-path, + flake-utils, + nixpkgs, + crane, + rust-overlay, + advisory-db, + nixfmt-check-paths, +}: flake-utils.lib.eachDefaultSystem ( + system: + let + # Local utility library: + flakelib = import flake-lib-path { + inherit + nixpkgs + crane + rust-overlay + flake-utils + advisory-db + ; + self = null; + } { + pname = "${project-name}-workspace"; + inherit + src-root + rust-toolchain-toml + system + ; + }; + + inherit (flakelib) + build-rust-workspace + links-table + nixpkgs + run-command + select-source + ; + + # We use this style of nix formatting in checks and the dev shell: + nixfmt = nixpkgs.nixfmt-rfc-style; + + # We use the latest nixpkgs `libclang`: + inherit (nixpkgs.llvmPackages) libclang; + + src-book = select-source { + name-suffix = "book"; + paths = [ + (src-root + "/book") + (src-root + "/README.md") + ]; + }; + + src-rust = select-source { + name-suffix = "rust"; + paths = [ + (src-root + "/.cargo") + (src-root + "/.config") + (src-root + "/Cargo.lock") + (src-root + "/Cargo.toml") + (src-root + "/clippy.toml") + (src-root + "/crosslink-test-data") + (src-root + "/release.toml") + (src-root + "/rust-toolchain.toml") + (src-root + "/tower-batch-control") + (src-root + "/tower-fallback") + (src-root + "/zebra-chain") + (src-root + "/zebra-consensus") + (src-root + "/zebra-crosslink") + (src-root + "/zebra-grpc") + (src-root + "/zebra-network") + (src-root + "/zebra-node-services") + (src-root + "/zebra-rpc") + (src-root + "/zebra-scan") + (src-root + "/zebra-script") + (src-root + "/zebra-state") + (src-root + "/zebra-test") + (src-root + "/zebra-utils") + (src-root + "/zebrad") + ]; + }; + + zebrad-outputs = build-rust-workspace (src-root + "/zebrad") { + src = src-rust; + + strictDeps = true; + + # Note: we disable tests since we'll run them all via cargo-nextest + doCheck = false; + + # Use the clang stdenv, overriding any downstream attempt to alter it: + stdenv = _: nixpkgs.llvmPackages.stdenv; + + nativeBuildInputs = with nixpkgs; [ + pkg-config + protobuf + ]; + + buildInputs = with nixpkgs; [ + libclang + rocksdb + ]; + + # Additional environment variables can be set directly + LIBCLANG_PATH = "${libclang.lib}/lib"; + }; + + zebrad = zebrad-outputs.pkg; + + zebra-book = nixpkgs.stdenv.mkDerivation rec { + name = "zebra-book"; + src = src-book; + buildInputs = with nixpkgs; [ + mdbook + mdbook-mermaid + ]; + builder = nixpkgs.writeShellScript "${name}-builder.sh" '' + if mdbook build --dest-dir "$out/book/book" "$src/book" 2>&1 | grep -E 'ERROR|WARN' + then + echo 'Failing due to mdbook errors/warnings.' + exit 1 + fi + ''; + }; + + # Invoke `check_path` for each configured nixfmt check path. + render-path = p: "check_path '${p}'"; + + nixfmt-check-script = builtins.concatStringsSep "\n" (map render-path nixfmt-check-paths); + in + { + packages = ( + let + base-pkgs = { + inherit + zebrad + zebra-book + src-book + src-rust + ; + }; + + all = links-table "all" { + "./bin" = "${zebrad}/bin"; + "./book" = "${zebra-book}/book"; + "./src/${project-name}/book" = "${src-book}/book"; + "./src/${project-name}/rust" = src-rust; + }; + in + + base-pkgs + // { + inherit all; + default = all; + } + ); + + checks = ( + zebrad-outputs.checks + // { + # Build the crates as part of `nix flake check` for convenience + inherit zebrad; + + # Check formatting + nixfmt-check = run-command "nixfmt" [ nixfmt ] '' + set -efuo pipefail + check_path() { + local path="$1" + if [ -d "$path" ] + then + find "$path" -type f -name '*.nix' -exec nixfmt --check --strict {} + || exitcode=1 + elif [ -f "$path" ] + then + nixfmt --check --strict "$path" || exitcode=1 + fi + } + exitcode=0 + ${nixfmt-check-script} + [ "$exitcode" -eq 0 ] && touch "$out" # signal success to nix + exit "$exitcode" + ''; + } + ); + + apps = { + zebrad = flake-utils.lib.mkApp { drv = zebrad; }; + }; + + # TODO: BEWARE: This dev shell may have buggy deviations from the build. + devShells.default = ( + let + mkClangShell = nixpkgs.mkShell.override { inherit (nixpkgs.llvmPackages) stdenv; }; + + devShellInputs = with nixpkgs; [ + rustup + mdbook + mdbook-mermaid + nixfmt + yamllint + ]; + + dynlibs = with nixpkgs; [ + libGL + libxkbcommon + xorg.libX11 + xorg.libxcb + xorg.libXi + ]; + + crate-args = zebrad-outputs.args.crate; + in + mkClangShell ( + crate-args + // { + # Include devShell inputs: + nativeBuildInputs = crate-args.nativeBuildInputs ++ devShellInputs; + + LD_LIBRARY_PATH = nixpkgs.lib.makeLibraryPath dynlibs; + } + ) + ); + } +)