From 320f31667456262b98fafb4377f4336e7dc9d21d Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Mon, 8 Dec 2025 13:04:01 +0000 Subject: [PATCH] nix: update checks This takes inspiration from the `heartwood/flake.nix`[^1] file. It runs checks at the MSRV but uses a rust-toolchain to allow for newer development. To obtain the latest 1.90 toolchain, the NixOS release was update to the latest 25.11. [^1]: https://rosa.radicle.xyz/raw/rad%3Az3gqcJUoA1n9HaHKufZs5FCSGazv5/4a5a51e6e550456c75d1a2182b0eafb9c3033ec0/flake.nix --- flake.lock | 104 ++++++++++++---- flake.nix | 281 +++++++++++++++++++++++++------------------- rust-toolchain.toml | 4 + 3 files changed, 246 insertions(+), 143 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/flake.lock b/flake.lock index d5e70a4..ca3e6ec 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "advisory-db": { "flake": false, "locked": { - "lastModified": 1739168963, - "narHash": "sha256-Pi7XjqacMBPEsCQf2GqPb2JfPB0Qkbi2xYrYtjoy7OE=", + "lastModified": 1765194944, + "narHash": "sha256-/vOedVUVYyZugEqJ9PPOmjjaMX215geoAY3yCsxHtI8=", "owner": "rustsec", "repo": "advisory-db", - "rev": "110cb7a5c98b088f131096c936ca2f540de717d8", + "rev": "3cb5be8c9c1af51e6e27236234c44b3b87b1b125", "type": "github" }, "original": { @@ -18,11 +18,11 @@ }, "crane": { "locked": { - "lastModified": 1739053031, - "narHash": "sha256-LrMDRuwAlRFD2T4MgBSRd1s2VtOE+Vl1oMCNu3RpPE0=", + "lastModified": 1765145449, + "narHash": "sha256-aBVHGWWRzSpfL++LubA0CwOOQ64WNLegrYHwsVuVN7A=", "owner": "ipetkov", "repo": "crane", - "rev": "112e6591b2d6313b1bd05a80a754a8ee42432a7e", + "rev": "69f538cdce5955fcd47abfed4395dc6d5194c1c5", "type": "github" }, "original": { @@ -37,11 +37,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1739169164, - "narHash": "sha256-2+/6/2rHsMjlrulkrjZbwthCQiQpeW2pukRFaaUMLy8=", + "lastModified": 1765003156, + "narHash": "sha256-k4YrPUhRj7Ciq385vREU57RHiDFycY5RaJwdCOmsLhU=", "owner": "nix-community", "repo": "fenix", - "rev": "d7616af878cd0cb7f940b470440347920395be0c", + "rev": "e8361cc010853d17740a63aae00385061ac9de51", "type": "github" }, "original": { @@ -49,6 +49,22 @@ "type": "indirect" } }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -67,13 +83,56 @@ "type": "github" } }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1765016596, + "narHash": "sha256-rhSqPNxDVow7OQKi4qS5H8Au0P4S3AYbawBSmJNUtBQ=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1739020877, - "narHash": "sha256-mIvECo/NNdJJ/bXjNqIh8yeoSjVLAuDuTUzAo7dzs8Y=", + "lastModified": 1764667669, + "narHash": "sha256-7WUCZfmqLAssbDqwg9cUDAXrSoXN79eEEq17qhTNM/Y=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a79cfe0ebd24952b580b1cf08cd906354996d547", + "rev": "418468ac9527e799809c900eda37cbff999199b6", "type": "github" }, "original": { @@ -85,16 +144,16 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1739188370, - "narHash": "sha256-2h/5uQaKwQeRXIgpOJpzgeO3qe93AonbJFk0CxTSygY=", + "lastModified": 1765190540, + "narHash": "sha256-kE8LyaA5TsFILJrnKI9Zb2Vow0eycYuSaB1qmYmXaes=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8ae4ee7978617d3af98721a62f14f25befc0beef", + "rev": "78c294509cf24e3ece22d00c02cca20f377a9c45", "type": "github" }, "original": { "owner": "NixOS", - "ref": "release-24.11", + "ref": "release-25.11", "repo": "nixpkgs", "type": "github" } @@ -105,6 +164,7 @@ "crane": "crane", "fenix": "fenix", "flake-utils": "flake-utils", + "git-hooks": "git-hooks", "nixpkgs": "nixpkgs_2", "rust-overlay": "rust-overlay" } @@ -112,11 +172,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1739099919, - "narHash": "sha256-YUdM2yZzQIbakgc2LdVmkgJMYTqeTu3YdWGgFfiZiTg=", + "lastModified": 1764925941, + "narHash": "sha256-zldc1SrUIhGMdQp+0woSqvBS51Mi8PW6JukONBQXZBY=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "35181e167efb94d5090df588e6af9f93250421f3", + "rev": "2cbf3587d36dfc7b701ebb744d3dd5064355d04f", "type": "github" }, "original": { @@ -133,11 +193,11 @@ ] }, "locked": { - "lastModified": 1739154531, - "narHash": "sha256-QGeN6e0nMJlNLzm3Y2A7P6riXhQXMeCXLZ7yajZYFQM=", + "lastModified": 1765161692, + "narHash": "sha256-XdY9AFzmgRPYIhP4N+WiCHMNxPoifP5/Ld+orMYBD8c=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "035dac86ab7ce5c1e8a4d59dfe85e6911a3526ea", + "rev": "7ed7e8c74be95906275805db68201e74e9904f07", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 55bc268..040277b 100644 --- a/flake.nix +++ b/flake.nix @@ -2,12 +2,17 @@ description = "Improved types and functionality for using Git in Radicle"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/release-24.11"; + nixpkgs.url = "github:NixOS/nixpkgs/release-25.11"; crane = { url = "github:ipetkov/crane"; }; + git-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + rust-overlay = { url = "github:oxalica/rust-overlay"; inputs = { @@ -36,7 +41,7 @@ advisory-db, rust-overlay, ... - }: + } @ inputs: flake-utils.lib.eachDefaultSystem (system: let pname = "radicle-git"; pkgs = import nixpkgs { @@ -46,150 +51,184 @@ inherit (pkgs) lib; - rustToolChain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain; - craneLib = (crane.mkLib pkgs).overrideToolchain rustToolChain; + msrv = let + msrv = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package.rust-version; + in rec { + toolchain = pkgs.rust-bin.stable.${msrv}.default; + craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; + commonArgs = mkCommonArgs craneLib; + }; + + rustup = rec { + toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; + commonArgs = mkCommonArgs craneLib; + }; srcFilters = path: type: # Allow data/git-platinum.tgz (lib.hasSuffix "\.tgz" path) || # Default filter from crane (allow .rs files) - (craneLib.filterCargoSources path type); + (rustup.craneLib.filterCargoSources path type); src = lib.cleanSourceWith { src = ./.; filter = srcFilters; }; - # Common arguments can be set here to avoid repeating them later - commonArgs = { - inherit pname; + basicArgs = { inherit src; + pname = "radicle-git"; + version = "0.1.0"; strictDeps = true; - - buildInputs = - [ - pkgs.git - # Add additional build inputs here - ] - ++ lib.optionals pkgs.stdenv.isDarwin [ - # Additional darwin specific inputs can be set here - pkgs.libiconv - ]; }; - # Build *just* the cargo dependencies, so we can reuse - # all of that work (e.g. via cachix) when running in CI - cargoArtifacts = - craneLib.buildDepsOnly commonArgs; + # Common arguments can be set here to avoid repeating them later + mkCommonArgs = craneLib: + basicArgs + // { + # Build *just* the cargo dependencies, so we can reuse + # all of that work (e.g. via cachix) when running in CI + cargoArtifacts = craneLib.buildDepsOnly basicArgs; - # Build the actual crate itself, reusing the dependency - # artifacts from above. + nativeBuildInputs = with pkgs; [ + git + ]; + buildInputs = lib.optionals pkgs.stdenv.buildPlatform.isDarwin (with pkgs; [ + darwin.apple_sdk.frameworks.Security + libiconv + ]); + }; - radicle-git-ext = craneLib.buildPackage (commonArgs - // { - inherit (craneLib.crateNameFromCargoToml {cargoToml = ./radicle-git-ext/Cargo.toml;}); - doCheck = false; - inherit cargoArtifacts; - }); - radicle-std-ext = craneLib.buildPackage (commonArgs - // { - inherit (craneLib.crateNameFromCargoToml {cargoToml = ./radicle-std-ext/Cargo.toml;}); - doCheck = false; - inherit cargoArtifacts; - }); - radicle-surf = craneLib.buildPackage (commonArgs - // { - inherit (craneLib.crateNameFromCargoToml {cargoToml = ./radicle-surf/Cargo.toml;}); - inherit cargoArtifacts; - doCheck = false; - }); - - # Test crates - radicle-git-ext-test = craneLib.buildPackage (commonArgs - // { - inherit (craneLib.crateNameFromCargoToml {cargoToml = ./radicle-git-ext/t/Cargo.toml;}); - inherit cargoArtifacts; - doCheck = false; - }); - radicle-surf-test = craneLib.buildPackage (commonArgs - // { - inherit (craneLib.crateNameFromCargoToml {cargoToml = ./radicle-surf/t/Cargo.toml;}); - inherit cargoArtifacts; - doCheck = false; - }); + buildCrate = rust: name: let + # Test crates live under `{crate}/t` but are called `{crate}-t`. + # Check if it is a test crate, and safely remove the suffix and build the Cargo.toml path. + isTest = lib.hasSuffix "-test" name; + pname = lib.removeSuffix "-test" name; + cargoToml = src + "/${pname}${lib.optionalString isTest "/t"}/Cargo.toml"; + in + rust.craneLib.buildPackage (rust.commonArgs + // { + inherit (rust.craneLib.crateNameFromCargoToml {inherit cargoToml;}) pname version; + cargoExtraArgs = "-p ${pname}"; + doCheck = false; + }); + buildCrates = { + rust ? rustup, + prefix ? "", + }: + builtins.listToAttrs (map + (name: lib.nameValuePair (prefix + name) (buildCrate rust name)) + [ + "radicle-std-ext" + "radicle-git-ext" + "radicle-git-ext-test" + "radicle-surf" + "radicle-surf-test" + ]); in { # Formatter formatter = pkgs.alejandra; - # Set of checks that are run: `nix flake check` - checks = { - # Build the crate as part of `nix flake check` for convenience - inherit radicle-git-ext; - inherit radicle-surf; - inherit radicle-git-ext-test; - inherit radicle-surf-test; - - # Run clippy (and deny all warnings) on the crate source, - # again, reusing the dependency artifacts from above. - # - # Note that this is done as a separate derivation so that - # we can block the CI if there are issues here, but not - # prevent downstream consumers from building our crate by itself. - clippy = craneLib.cargoClippy (commonArgs - // { - inherit cargoArtifacts; - cargoClippyExtraArgs = "--all-targets -- --deny warnings"; - }); - - doc = craneLib.cargoDoc (commonArgs - // { - inherit cargoArtifacts; - }); - - # Check formatting - fmt = craneLib.cargoFmt { - inherit pname; - inherit src; - }; - - # Audit dependencies - audit = craneLib.cargoAudit { - inherit src advisory-db; - }; - - # Audit licenses - deny = craneLib.cargoDeny { - inherit pname; - inherit src; - }; - - # Run tests with cargo-nextest - nextest = craneLib.cargoNextest (commonArgs - // { - inherit cargoArtifacts; - partitions = 1; - partitionType = "count"; - nativeBuildInputs = [ - # git is required so the sandbox can access it. - pkgs.git + checks = + (buildCrates { + rust = msrv; + prefix = "msrv-"; + }) + // { + pre-commit-check = inputs.git-hooks.lib.${system}.run { + src = ./.; + settings.rust.check.cargoDeps = pkgs.rustPlatform.importCargoLock {lockFile = ./Cargo.lock;}; + default_stages = [ + "pre-commit" + "pre-push" ]; - # Ensure dev is used since we rely on env variables being - # set in tests. - buildPhase = '' - export CARGO_PROFILE=dev; - ''; - }); - }; + hooks = { + alejandra.enable = true; + codespell = { + enable = true; + entry = "${lib.getExe pkgs.codespell} -w"; + types = ["text"]; + }; + rustfmt = { + enable = true; + fail_fast = true; + packageOverrides.rustfmt = rustup.toolchain; + }; + cargo-check = { + enable = true; + name = "cargo check"; + after = ["rustfmt"]; + fail_fast = true; + }; + cargo-doc = let + # We wrap `cargo` in order to set an environment variable that + # gives us a non-zero exit on warning. + command = + pkgs.writeShellScript + "cargo" + "RUSTDOCFLAGS='--deny warnings' ${lib.getExe' rustup.toolchain "cargo"} $@"; + in { + enable = true; + name = "cargo doc"; + after = ["rustfmt"]; + fail_fast = true; + entry = "${command} doc --workspace --all-features --no-deps"; + files = "\\.rs$"; + pass_filenames = false; + }; + clippy = { + enable = true; + name = "cargo clippy"; + stages = ["pre-push"]; # Only pre-push, because it takes a while. + settings = { + allFeatures = true; + denyWarnings = true; + }; + packageOverrides = { + cargo = rustup.toolchain; + clippy = rustup.toolchain; + }; + }; + shellcheck.enable = true; + }; + }; - packages = { - inherit radicle-git-ext; - inherit radicle-surf; - inherit radicle-git-ext-test; - inherit radicle-surf-test; - }; + # Run clippy (and deny all warnings) on the crate source, + # again, reusing the dependency artifacts from above. + # + # Note that this is done as a separate derivation so that + # we can block the CI if there are issues here, but not + # prevent downstream consumers from building our crate by itself. + doc = rustup.craneLib.cargoDoc rustup.commonArgs; + deny = rustup.craneLib.cargoDeny rustup.commonArgs; + fmt = rustup.craneLib.cargoFmt basicArgs; - devShells.default = craneLib.devShell { + audit = rustup.craneLib.cargoAudit { + inherit src advisory-db; + }; + + # Run tests with cargo-nextest + nextest = rustup.craneLib.cargoNextest (rustup.commonArgs + // { + partitions = 1; + partitionType = "count"; + nativeBuildInputs = [ + # git is required so the sandbox can access it. + pkgs.git + ]; + # Ensure dev is used since we rely on env variables being + # set in tests. + buildPhase = '' + export CARGO_PROFILE=dev; + ''; + }); + }; + + packages = buildCrates {}; + + devShells.default = rustup.craneLib.devShell { # Extra inputs can be added here; cargo and rustc are provided by default. packages = [ pkgs.cargo-deny diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..547da22 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.90" +profile = "default" +components = [ "rust-src" ]