From 3fef2726488a5ff3e4528a23617ed3c4aad51190 Mon Sep 17 00:00:00 2001 From: brhutchins Date: Sun, 14 Jun 2026 11:12:03 +0200 Subject: [PATCH] build(nix): add flake Add flake for building/running/installing via Nix. The flake also provides a development shell with all deveplopment dependencies, as well as a check running `cargo fmt`, `cargo clippy`, and `cargo test`. Update docs to cover Nix path. --- .gitignore | 4 +- README.md | 32 +++++++++++++++ docs/contributing.md | 13 +++++- flake.lock | 98 ++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 94 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.gitignore b/.gitignore index 22c17cb..b46afef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /target +/result /.tinyharness -/todo \ No newline at end of file +/todo + diff --git a/README.md b/README.md index 3513ab2..4831ebb 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,30 @@ Alternatively, install via Cargo: cargo install --path . ``` +### Installation (Nix) + +A Nix flake is provided for reproducible builds and dev environments. + +**Run once without installing:** + +```bash +nix run github:PTFOPlayer/TinyHarness +``` + +**Build the package:** + +```bash +cd TinyHarness +nix build +./result/bin/tinyharness +``` + +**Enter a development shell** (with Rust toolchain, rustfmt, and clippy pre-configured): + +```bash +nix develop +``` + ### Usage **Ollama** (default): @@ -420,6 +444,14 @@ cargo fmt --all -- --check # Format check cargo fmt --all # Auto-format ``` +If you're using the Nix flake, prefer: + +```bash +nix build # Build the package +nix flake check # Run all checks (build + fmt + clippy --deny warnings + test) +nix develop # Enter dev shell with cargo/rustfmt/clippy +``` + ### Verification Steps After making changes, run: diff --git a/docs/contributing.md b/docs/contributing.md index f71d98a..8cd66ce 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -6,7 +6,7 @@ TinyHarness is a Rust workspace with three crates and a focus on minimal depende ### Prerequisites -- Rust latest stable (edition 2024) +- Nix with flakes enabled or Rust latest stable (edition 2024) - An LLM backend for testing (Ollama recommended, but not required for library tests) ### Getting the Code @@ -18,6 +18,9 @@ cd TinyHarness ### First Build +>[!NOTE] +>If you have Nix, run `nix develop` + ```bash cargo build --workspace cargo test --workspace @@ -117,6 +120,14 @@ Before submitting a PR, run these in order: 3. `cargo test --workspace` — all tests pass 4. `cargo build` — clean debug build succeeds +If you have Nix installed, the same checks are available as a single command: + +```bash +nix flake check +``` + +This runs `cargo fmt --all -- --check`, `cargo clippy --workspace -- -D warnings`, `cargo test --workspace` (release), and a release build — i.e. steps 1, 2, 3, and a release variant of step 4. See the [Nix installation section](../../README.md#installation-nix) in the README for setup. + --- ## Code Conventions diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..5d189ae --- /dev/null +++ b/flake.lock @@ -0,0 +1,98 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1780532242, + "narHash": "sha256-D+BsdpxmtUwtqGoY0IXPhHgTlmqgcZKCEo1oMyn7ep0=", + "owner": "ipetkov", + "repo": "crane", + "rev": "59a82a1222dd3b2080b5cc52a1a2e8d5f1b77f37", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1781074563, + "narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1781320681, + "narHash": "sha256-mjJ/VxJaIkgcUvKANgKOaaN5M1X1X+6NjCP0C5hw0WI=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "5b929d8c854149d926d05ea0cd6469bf4e54db27", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..8d49e41 --- /dev/null +++ b/flake.nix @@ -0,0 +1,94 @@ +{ + description = "TinyHarness - AI Coding Harness"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + crane = { + url = "github:ipetkov/crane"; + }; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, flake-utils, crane, rust-overlay, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ (import rust-overlay) ]; + }; + + inherit (pkgs) lib; + + rustToolchain = pkgs.rust-bin.stable.latest.default.override { + extensions = [ "rustfmt" "clippy" ]; + }; + + craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; + + src = lib.cleanSourceWith { + filter = path: type: + (craneLib.filterCargoSources path type) || + (lib.hasSuffix ".md" path); + src = lib.cleanSource ./.; + }; + + commonArgs = { + inherit src; + strictDeps = true; + buildInputs = [ + pkgs.openssl + ] ++ lib.optionals pkgs.stdenv.isDarwin [ + pkgs.apple-sdk + ]; + nativeBuildInputs = [ + pkgs.pkg-config + ]; + }; + + cargoArtifacts = craneLib.buildDepsOnly commonArgs; + + tinyharness = craneLib.buildPackage (commonArgs // { + inherit cargoArtifacts; + doCheck = false; + meta = { + mainProgram = "tinyharness"; + }; + }); + + tests = craneLib.cargoTest (commonArgs // { + inherit cargoArtifacts; + }); + + in { + packages = { + default = tinyharness; + tinyharness = tinyharness; + }; + + checks = { + inherit tinyharness; + inherit tests; + clippy = craneLib.cargoClippy (commonArgs // { + inherit cargoArtifacts; + cargoClippyExtraArgs = "-- --deny warnings"; + }); + fmt = craneLib.cargoFmt { + inherit src; + }; + }; + + devShells.default = craneLib.devShell { + checks = self.checks.${system}; + packages = with pkgs; [ + cargo + clippy + rust-analyzer + rustfmt + ]; + }; + }); +}