diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 73edf03..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: builder -on: [push, pull_request] -jobs: - build: - name: Build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v31 - - name: Cache Rust Artifacts - uses: actions/cache@v4 - env: - cache-name: cache-rust-artifacts - with: - path: | - /home/runner/.cargo - target - key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml', '**/Cargo.lock', '**/.cargo/config.toml', '**/rust-toolchain.toml', '**/flake.nix', '**/flake.lock') }} - - - name: Build - run: | - eval "$(nix print-dev-env)" - - set -x - cargo fmt --check - cargo clippy - cargo test - - nix-build: - name: Nix Build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v31 - - - name: Build with Nix - run: nix build -Lv diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b2b3788 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + types: [ opened, reopened, labeled, synchronize ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: DeterminateSystems/nix-installer-action@v19 + - uses: DeterminateSystems/magic-nix-cache-action@v13 + - name: Cache Rust Artifacts + uses: actions/cache@v4 + env: + cache-name: cache-rust-artifacts + with: + path: | + /home/runner/.cargo + target + key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml', '**/Cargo.lock', '**/.cargo/config.toml', '**/rust-toolchain.toml', '**/flake.nix', '**/flake.lock') }} + - name: Build + run: | + eval "$(nix print-dev-env)" + + set -x + cargo fmt --check + cargo clippy + cargo test + + integration-test: + runs-on: ubuntu-latest + strategy: + matrix: + test: + - nix-build-hello + - nix-build-header + - nix-build-incremental + steps: + - uses: actions/checkout@v4 + - uses: DeterminateSystems/nix-installer-action@v19 + with: + extra-conf: |- + extra-experimental-features = dynamic-derivations ca-derivations recursive-nix + - uses: DeterminateSystems/magic-nix-cache-action@v13 + - name: Build NixOS test driver + run: nix build .#driver-${{ matrix.test }} + - name: Run integration tests + run: nix run -L .#test-${{ matrix.test }} diff --git a/crates/deps-infer/Cargo.toml b/crates/deps-infer/Cargo.toml index 94105b3..645cc81 100644 --- a/crates/deps-infer/Cargo.toml +++ b/crates/deps-infer/Cargo.toml @@ -3,6 +3,7 @@ name = "deps-infer" version.workspace = true edition.workspace = true description = "Dependency inference for C/C++" +license = "MIT" [dependencies] anyhow = "1.0" @@ -10,12 +11,12 @@ clap = { version = "4.5", features = ["derive"] } include-graph = { git = "https://github.com/hinshun/igraph", branch = "performance-improvements" } n2 = { git = "https://github.com/hinshun/n2", branch = "feature/minimal-pub", default-features = false } shell-words = "1.1.0" -tracing = { version = "0.1"} +tracing = { version = "0.1" } tracing-subscriber = { version = "0.3.18", features = [ - "json", - "matchers", - "time", - "tracing", - "env-filter", - "regex", -]} + "json", + "matchers", + "time", + "tracing", + "env-filter", + "regex", +] } diff --git a/crates/nix-libstore/Cargo.toml b/crates/nix-libstore/Cargo.toml index cdf6a6d..76699df 100644 --- a/crates/nix-libstore/Cargo.toml +++ b/crates/nix-libstore/Cargo.toml @@ -3,6 +3,7 @@ name = "nix-libstore" version.workspace = true edition.workspace = true description = "Core Nix datastructures" +license = "MIT" [dependencies] anyhow = "1.0" diff --git a/crates/nix-ninja-task/Cargo.toml b/crates/nix-ninja-task/Cargo.toml index 2f29ce8..311db53 100644 --- a/crates/nix-ninja-task/Cargo.toml +++ b/crates/nix-ninja-task/Cargo.toml @@ -3,6 +3,7 @@ name = "nix-ninja-task" version.workspace = true edition.workspace = true description = "Nix derivation builder for nix-ninja" +license = "MIT" [dependencies] anyhow = "1.0" diff --git a/crates/nix-ninja/Cargo.toml b/crates/nix-ninja/Cargo.toml index a4d7f8a..83aff6a 100644 --- a/crates/nix-ninja/Cargo.toml +++ b/crates/nix-ninja/Cargo.toml @@ -3,9 +3,10 @@ name = "nix-ninja" version.workspace = true edition.workspace = true description = "Ninja compatible build system using Nix backend" +license = "MIT" [dependencies] -anyhow = { version = "1.0", features = [ "backtrace" ] } +anyhow = { version = "1.0", features = ["backtrace"] } clap = { version = "4.4", features = ["derive", "env"] } deps-infer = { path = "../deps-infer" } include-graph = { git = "https://github.com/hinshun/igraph", branch = "performance-improvements" } diff --git a/crates/nix-tool/Cargo.toml b/crates/nix-tool/Cargo.toml index c72bb8c..83d32b6 100644 --- a/crates/nix-tool/Cargo.toml +++ b/crates/nix-tool/Cargo.toml @@ -3,6 +3,7 @@ name = "nix-tool" version.workspace = true edition.workspace = true description = "Helper to spawn Nix commands" +license = "MIT" [dependencies] anyhow = "1.0" diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..7ea2189 --- /dev/null +++ b/deny.toml @@ -0,0 +1,2 @@ +[licenses] +allow = ["MIT", "Apache-2.0", "BSD-3-Clause", "MPL-2.0", "Unicode-3.0"] diff --git a/examples/hello/main.cpp b/examples/hello/main.cpp deleted file mode 100644 index 421abb3..0000000 --- a/examples/hello/main.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - std::cout << "Hello Nix dynamic derivations!" << std::endl; - return 0; -} diff --git a/examples/incremental/util.c b/examples/incremental/util.c deleted file mode 100644 index 9b9867f..0000000 --- a/examples/incremental/util.c +++ /dev/null @@ -1,5 +0,0 @@ -#include "util.h" - -int add(int a, int b) { - return a + b; -} diff --git a/flake.lock b/flake.lock index 46a95b9..ba88a45 100644 --- a/flake.lock +++ b/flake.lock @@ -85,6 +85,26 @@ } }, "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1754487366, + "narHash": "sha256-pHYj8gUBapuUzKV/kN/tR3Zvqc7o6gdFB9XKXIp1SQ8=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "af66ad14b28a127c5c0f3bbb298218fc63528a18", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { "inputs": { "nixpkgs-lib": [ "nix", @@ -143,11 +163,11 @@ ] }, "locked": { - "lastModified": 1738008127, - "narHash": "sha256-HcN58roxuzfGm/MlcTqUD/wCH9bPdhZmK1xI/t8tSUc=", + "lastModified": 1755473597, + "narHash": "sha256-SlKOuI5nFhKeY+6YO+QTEJO0RCfWbzWSjj9wW368jvI=", "owner": "pdtpartners", "repo": "globset", - "rev": "9b586e135be867683f212d6e363816c24424084c", + "rev": "0cc20aa3180679c1857afa197c813f0cabfe606c", "type": "github" }, "original": { @@ -159,7 +179,7 @@ "nix": { "inputs": { "flake-compat": "flake-compat_2", - "flake-parts": "flake-parts", + "flake-parts": "flake-parts_2", "git-hooks-nix": "git-hooks-nix", "nixpkgs": "nixpkgs", "nixpkgs-23-11": "nixpkgs-23-11", @@ -230,11 +250,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1741310760, - "narHash": "sha256-aizILFrPgq/W53Jw8i0a1h1GZAAKtlYOrG/A5r46gVM=", + "lastModified": 1755829505, + "narHash": "sha256-4/Jd+LkQ2ssw8luQVkqVs9spDBVE6h/u/hC/tzngsPo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "de0fe301211c267807afd11b12613f5511ff7433", + "rev": "f937f8ecd1c70efd7e9f90ba13dfb400cf559de4", "type": "github" }, "original": { @@ -250,6 +270,7 @@ "crane": "crane", "fenix": "fenix", "flake-compat": "flake-compat", + "flake-parts": "flake-parts", "globset": "globset", "nix": "nix", "nixpkgs": "nixpkgs_2" diff --git a/flake.nix b/flake.nix index 26eca40..a05bba1 100644 --- a/flake.nix +++ b/flake.nix @@ -3,222 +3,35 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - nix.url = "github:hinshun/nix/2.27.1-fix-nix-missing-includes"; - globset = { url = "github:pdtpartners/globset"; inputs.nixpkgs-lib.follows = "nixpkgs"; }; - crane.url = "github:ipetkov/crane"; - fenix = { url = "github:nix-community/fenix"; inputs.nixpkgs.follows = "nixpkgs"; inputs.rust-analyzer-src.follows = ""; }; - advisory-db = { url = "github:rustsec/advisory-db"; flake = false; }; - + flake-parts = { + url = "github:hercules-ci/flake-parts"; + inputs.nixpkgs-lib.follows = "nixpkgs"; + }; flake-compat = { url = "github:edolstra/flake-compat"; flake = false; }; }; - outputs = inputs: - let - system = "x86_64-linux"; - - pkgs = import inputs.nixpkgs { - inherit system; - }; - - inherit (pkgs) lib; - - craneLib = inputs.crane.mkLib pkgs; - - src = lib.fileset.toSource { - root = ./.; - fileset = inputs.globset.lib.globs ./. [ - "Cargo.lock" - "**/Cargo.toml" - "**/*.rs" - ]; - }; - - # Common arguments can be set here to avoid repeating them later - commonArgs = { - inherit src; - inherit (craneLib.crateNameFromCargoToml { inherit src; }) version; - strictDeps = true; - nativeBuildInputs = with pkgs; [ - pkg-config - ]; - }; - - craneLibLLvmTools = craneLib.overrideToolchain - (inputs.fenix.packages.${system}.complete.withComponents [ - "cargo" - "llvm-tools" - "rustc" - ]); - - # 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; - - # Build the actual crate itself, reusing the dependency - # artifacts from above. - nix-ninja = craneLib.buildPackage (commonArgs // { - inherit cargoArtifacts; - pname = "nix-ninja"; - cargoExtraArgs = "-p nix-ninja"; - }); - - nix-ninja-task = craneLib.buildPackage (commonArgs // { - inherit cargoArtifacts; - pname = "nix-ninja-task"; - cargoExtraArgs = "-p nix-ninja-task"; - src = lib.fileset.toSource { - root = ./.; - fileset = inputs.globset.lib.globs ./. [ - "Cargo.toml" - "Cargo.lock" - "crates/nix-libstore/Cargo.toml" - "crates/nix-libstore/**/*.rs" - "crates/nix-ninja-task/Cargo.toml" - "crates/nix-ninja-task/**/*.rs" - ]; - }; - }); - - default = pkgs.buildEnv { - name = "nix-ninja"; - paths = [ - nix-ninja - nix-ninja-task - ]; - }; - - mkMesonPackage = pkgs.callPackage ./mkMesonPackage.nix { - inherit nix-ninja nix-ninja-task; - }; - - example-hello = mkMesonPackage { - name = "example-hello"; - src = ./examples/hello; - target = "hello"; - }; - - example-header = mkMesonPackage { - name = "example-header"; - src = ./examples/header; - target = "hello"; - }; - - example-incremental = mkMesonPackage { - name = "example-header"; - src = ./examples/incremental; - target = "main"; - }; - - example-nix = pkgs.callPackage ./examples/nix { - inherit inputs mkMesonPackage; - }; - - in - { - inherit pkgs; - - checks.${system} = { - # Build the crate as part of `nix flake check` for convenience - inherit nix-ninja; - - # 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. - nix-ninja-clippy = craneLib.cargoClippy (commonArgs // { - inherit cargoArtifacts; - cargoClippyExtraArgs = "--all-targets -- --deny warnings"; - }); - - nix-ninja-doc = craneLib.cargoDoc (commonArgs // { - inherit cargoArtifacts; - }); - - # Check formatting - nix-ninja-fmt = craneLib.cargoFmt { - inherit src; - }; - - nix-ninja-toml-fmt = craneLib.taploFmt { - src = lib.fileset.toSource { - root = ./.; - fileset = inputs.globset.lib.globs ./. [ - "**/*.toml" - ]; - }; - - # taplo arguments can be further customized below as needed - # taploExtraArgs = "--config ./taplo.toml"; - }; - - # Audit dependencies - nix-ninja-audit = craneLib.cargoAudit { - inherit src; - inherit (inputs) advisory-db; - }; - - # Audit licenses - nix-ninja-deny = craneLib.cargoDeny { - inherit src; - }; - - # Run tests with cargo-nextest - # Consider setting `doCheck = false` on `nix-ninja` if you do not want - # the tests to run twice - nix-ninja-nextest = craneLib.cargoNextest (commonArgs // { - inherit cargoArtifacts; - partitions = 1; - partitionType = "count"; - cargoNextestPartitionsExtraArgs = "--no-tests=pass"; - }); - }; - - packages.${system} = { - inherit default nix-ninja nix-ninja-task; - - inherit (pkgs) nix; - - nix-ninja-llvm-coverage = craneLibLLvmTools.cargoLlvmCov (commonArgs // { - inherit cargoArtifacts; - }); - - inherit - example-hello - example-header - example-incremental - example-nix - ; - }; - - devShells.${system}.default = craneLib.devShell { - checks = inputs.self.checks.${system}; - - packages = with pkgs; [ - gnumake - just - meson - agg - ]; - }; + outputs = inputs@{ flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ "x86_64-linux" ]; + imports = [ ./modules ]; + flake = { inherit (inputs.nixpkgs) lib; }; }; } diff --git a/modules/default.nix b/modules/default.nix new file mode 100644 index 0000000..4d4a9ee --- /dev/null +++ b/modules/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./flake + ./nixos + ]; +} diff --git a/modules/flake/checks.nix b/modules/flake/checks.nix new file mode 100644 index 0000000..37e8b50 --- /dev/null +++ b/modules/flake/checks.nix @@ -0,0 +1,72 @@ +{ lib, inputs, ... }: +{ + perSystem = { pkgs, ... }: + let + inherit (pkgs) craneLib; + inherit (pkgs._nix-ninja) cargoArtifacts commonArgs src; + + in { + checks = { + # 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. + nix-ninja-clippy = craneLib.cargoClippy (commonArgs // { + inherit cargoArtifacts; + cargoClippyExtraArgs = "--all-targets -- --deny warnings"; + }); + + nix-ninja-doc = craneLib.cargoDoc (commonArgs // { + inherit cargoArtifacts; + }); + + # Check formatting + nix-ninja-fmt = craneLib.cargoFmt { + inherit src; + }; + + nix-ninja-toml-fmt = craneLib.taploFmt { + src = lib.fileset.toSource { + root = ../../.; + fileset = inputs.globset.lib.globs ../../. [ + "**/*.toml" + ]; + }; + + # taplo arguments can be further customized below as needed + # taploExtraArgs = "--config ./taplo.toml"; + }; + + # Audit dependencies + nix-ninja-audit = craneLib.cargoAudit { + inherit src; + inherit (inputs) advisory-db; + }; + + # Audit licenses + nix-ninja-deny = craneLib.cargoDeny { + src = lib.fileset.toSource { + root = ../../.; + fileset = inputs.globset.lib.globs ../../. [ + "deny.toml" + "Cargo.lock" + "**/Cargo.toml" + "**/*.rs" + ]; + }; + }; + + # Run tests with cargo-nextest + # Consider setting `doCheck = false` on `nix-ninja` if you do not want + # the tests to run twice + nix-ninja-nextest = craneLib.cargoNextest (commonArgs // { + inherit cargoArtifacts; + partitions = 1; + partitionType = "count"; + cargoNextestPartitionsExtraArgs = "--no-tests=pass"; + }); + }; + }; +} diff --git a/modules/flake/default.nix b/modules/flake/default.nix new file mode 100644 index 0000000..424ff17 --- /dev/null +++ b/modules/flake/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./checks.nix + ./nixosTests.nix + ./overlays.nix + ./packages.nix + ]; +} diff --git a/examples/header/header.h b/modules/flake/examples/header/header.h similarity index 62% rename from examples/header/header.h rename to modules/flake/examples/header/header.h index c8c5125..b42035f 100644 --- a/examples/header/header.h +++ b/modules/flake/examples/header/header.h @@ -3,5 +3,5 @@ #include inline std::string getMessage() { - return "Hello from header.h!"; + return "Hello dynamic derivations!"; } diff --git a/examples/header/main.cpp b/modules/flake/examples/header/main.cpp similarity index 100% rename from examples/header/main.cpp rename to modules/flake/examples/header/main.cpp diff --git a/examples/header/meson.build b/modules/flake/examples/header/meson.build similarity index 100% rename from examples/header/meson.build rename to modules/flake/examples/header/meson.build diff --git a/modules/flake/examples/hello/main.cpp b/modules/flake/examples/hello/main.cpp new file mode 100644 index 0000000..a34a6b7 --- /dev/null +++ b/modules/flake/examples/hello/main.cpp @@ -0,0 +1,6 @@ +#include + +int main() { + std::cout << "Hello dynamic derivations!" << std::endl; + return 0; +} diff --git a/examples/hello/meson.build b/modules/flake/examples/hello/meson.build similarity index 100% rename from examples/hello/meson.build rename to modules/flake/examples/hello/meson.build diff --git a/examples/incremental/main.c b/modules/flake/examples/incremental/main.c similarity index 50% rename from examples/incremental/main.c rename to modules/flake/examples/incremental/main.c index 8b5040f..1f9e678 100644 --- a/examples/incremental/main.c +++ b/modules/flake/examples/incremental/main.c @@ -2,7 +2,7 @@ #include "util.h" int main() { - int sum = add(5, 3); - printf("Hello! The sum is %d\n", sum); + const char* message = msg(); + printf("Hello %s!\n", message); return 0; } diff --git a/examples/incremental/meson.build b/modules/flake/examples/incremental/meson.build similarity index 100% rename from examples/incremental/meson.build rename to modules/flake/examples/incremental/meson.build diff --git a/modules/flake/examples/incremental/util.c b/modules/flake/examples/incremental/util.c new file mode 100644 index 0000000..07338d7 --- /dev/null +++ b/modules/flake/examples/incremental/util.c @@ -0,0 +1,5 @@ +#include "util.h" + +const char* msg() { + return "dynamic derivations"; +} diff --git a/examples/incremental/util.h b/modules/flake/examples/incremental/util.h similarity index 62% rename from examples/incremental/util.h rename to modules/flake/examples/incremental/util.h index 4212de4..4b1c61d 100644 --- a/examples/incremental/util.h +++ b/modules/flake/examples/incremental/util.h @@ -1,6 +1,6 @@ #ifndef UTIL_H #define UTIL_H -int add(int a, int b); +const char* msg(); #endif diff --git a/modules/flake/examples/nix/default.nix b/modules/flake/examples/nix/default.nix new file mode 100644 index 0000000..e73014a --- /dev/null +++ b/modules/flake/examples/nix/default.nix @@ -0,0 +1,98 @@ +{ src +, aws-sdk-cpp +, bison +, boehmgc +, boost +, brotli +, busybox-sandbox-shell +, bzip2 +, cmake +, curl +, doxygen +, editline +, flex +, gtest +, lib +, libarchive +, libblake3 +, libcpuid +, libgit2 +, libseccomp +, libsodium +, lowdown +, mkMesonPackage +, nlohmann_json +, openssl +, perl +, perlPackages +, pkg-config +, rapidcheck +, readline +, sqlite +, toml11 +}: + +mkMesonPackage { + name = "example-nix"; + inherit src; + target = "src/nix/nix"; + + nixNinjaExtraInputs = [ + "src/libexpr/libnixexpr.so.p/meson-generated_.._parser-tab.cc.o:../src/libexpr/parser.y" + "src/libexpr/libnixexpr.so.p/meson-generated_.._lexer-tab.cc.o:../src/libexpr/parser.y" + "src/libexpr/libnixexpr.so.p/meson-generated_.._lexer-tab.cc.o:../src/libexpr/lexer.l" + "src/libexpr/libnixexpr.so.p/eval.cc.o:../src/libexpr/parser.y" + "src/libexpr/libnixexpr.so.p/lexer-helpers.cc.o:../src/libexpr/parser.y" + ]; + + nativeBuildInputs = [ + aws-sdk-cpp + bison + boehmgc + boost + brotli + busybox-sandbox-shell + bzip2 + cmake + curl + doxygen + editline + flex + libarchive + libblake3 + libcpuid + libgit2 + libseccomp + libsodium + lowdown + nlohmann_json + openssl + perl + pkg-config + readline + sqlite + toml11 + ]; + + buildInputs = [ + rapidcheck + gtest + ]; + + # dontAddPrefix = true; + + mesonFlags = [ + "--prefix=/build/tmp" + "--bindir=/build/tmp/bin" + "--mandir=/build/tmp/man" + (lib.mesonOption "perl:dbi_path" "${perlPackages.DBI}/${perl.libPrefix}") + (lib.mesonOption "perl:dbd_sqlite_path" "${perlPackages.DBDSQLite}/${perl.libPrefix}") + ]; + + env = { + # Needed for Meson to find Boost. + # https://github.com/NixOS/nixpkgs/issues/86131. + BOOST_INCLUDEDIR = "${lib.getDev boost}/include"; + BOOST_LIBRARYDIR = "${lib.getLib boost}/lib"; + }; +} diff --git a/modules/flake/nixosTests.nix b/modules/flake/nixosTests.nix new file mode 100644 index 0000000..faa71ba --- /dev/null +++ b/modules/flake/nixosTests.nix @@ -0,0 +1,65 @@ +{ self, lib, flake-parts-lib, ... }: +let + inherit (lib) + mkOption + types + ; + + inherit (flake-parts-lib) + mkPerSystemOption + ; + +in { + options.perSystem = mkPerSystemOption { + _file = ./nixosTests.nix; + + options.nixosTests = mkOption { + type = types.attrsOf types.deferredModule; + default = { }; + }; + }; + + config.perSystem = { config, pkgs, ... }: + let + evalTest = name: module: + (lib.nixos.evalTest { + imports = [ + { + inherit name; + _module.args = { inherit self; }; + } + module + ]; + hostPkgs = pkgs; + node = { inherit pkgs; }; + }).config.result; + + testRigs = lib.mapAttrs (name: module: evalTest name module) config.nixosTests; + + in { + /* For each nixosTest, add an `apps` target that allows the use of + `machine.shell_interact()` for developing tests. + + ```sh + nix run .#test- -L + ``` + */ + apps = + lib.mapAttrs' + (name: testRig: + lib.nameValuePair + ("test-" + name) + { + type = "app"; + program = "${testRig.driver}/bin/nixos-test-driver"; + } + ) + testRigs; + + + packages = + lib.mapAttrs' + (name: testRig: lib.nameValuePair ("driver-" + name) testRig.driver) + testRigs; + }; +} diff --git a/modules/flake/overlays.nix b/modules/flake/overlays.nix new file mode 100644 index 0000000..e8c9bcb --- /dev/null +++ b/modules/flake/overlays.nix @@ -0,0 +1,102 @@ +{ self, inputs, lib, ... }: +{ + flake.overlays.internal = self: super: + let + craneLib = inputs.crane.mkLib self; + + src = lib.fileset.toSource { + root = ../../.; + fileset = inputs.globset.lib.globs ../../. [ + "Cargo.lock" + "**/Cargo.toml" + "**/*.rs" + ]; + }; + + # Common arguments can be set here to avoid repeating them later + commonArgs = { + inherit src; + inherit (craneLib.crateNameFromCargoToml { inherit src; }) version; + strictDeps = true; + nativeBuildInputs = [ + self.pkg-config + ]; + }; + + # 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; + + craneLibLLvmTools = craneLib.overrideToolchain + (inputs.fenix.packages.${self.system}.complete.withComponents [ + "cargo" + "llvm-tools" + "rustc" + ]); + + in { + inherit craneLib; + + # Internal attr for code-reuse across flake modules. + _nix-ninja = { + inherit cargoArtifacts commonArgs src; + }; + + mkMesonPackage = self.callPackage ./pkgs/mkMesonPackage { + inherit (self) nix-ninja nix-ninja-task; + }; + + nix-ninja-llvm-coverage = craneLibLLvmTools.cargoLlvmCov (commonArgs // { + inherit cargoArtifacts; + }); + + # Build the actual crate itself, reusing the dependency + # artifacts from above. + nix-ninja = craneLib.buildPackage (commonArgs // { + inherit cargoArtifacts; + pname = "nix-ninja"; + cargoExtraArgs = "-p nix-ninja"; + }); + + nix-ninja-task = craneLib.buildPackage (commonArgs // { + inherit cargoArtifacts; + pname = "nix-ninja-task"; + cargoExtraArgs = "-p nix-ninja-task"; + src = lib.fileset.toSource { + root = ../../.; + fileset = inputs.globset.lib.globs ../../. [ + "Cargo.{toml,lock}" + "crates/nix-{libstore,ninja-task}/Cargo.toml" + "crates/nix-{libstore,ninja-task}/**/*.rs" + ]; + }; + }); + + example-hello = self.mkMesonPackage { + name = "example-hello"; + src = ./examples/hello; + target = "hello"; + }; + + example-header = self.mkMesonPackage { + name = "example-header"; + src = ./examples/header; + target = "hello"; + }; + + example-incremental = self.mkMesonPackage { + name = "example-header"; + src = ./examples/incremental; + target = "main"; + }; + + example-nix = self.callPackage ./examples/nix { src = inputs.nix; }; + }; + + perSystem = { system, ... }: { + _module.args.pkgs = import inputs.nixpkgs { + inherit system; + overlays = [ self.overlays.internal ]; + }; + }; +} diff --git a/modules/flake/packages.nix b/modules/flake/packages.nix new file mode 100644 index 0000000..1052ac2 --- /dev/null +++ b/modules/flake/packages.nix @@ -0,0 +1,31 @@ +{ self, ... }: +{ + perSystem = { pkgs, system, ... }: { + packages = { + inherit (pkgs) + nix-ninja + nix-ninja-task + nix-ninja-llvm-coverage + ; + + default = pkgs.nix-ninja; + + example-hello = pkgs.example-hello.target; + example-header = pkgs.example-header.target; + example-incremental = pkgs.example-incremental.target; + example-nix = pkgs.example-nix.target; + }; + + devShells.default = pkgs.craneLib.devShell { + checks = self.checks.${system}; + + packages = with pkgs; [ + agg + gnumake + just + meson + taplo + ]; + }; + }; +} diff --git a/mkMesonPackage.nix b/modules/flake/pkgs/mkMesonPackage/default.nix similarity index 92% rename from mkMesonPackage.nix rename to modules/flake/pkgs/mkMesonPackage/default.nix index 5af2519..75be5eb 100644 --- a/mkMesonPackage.nix +++ b/modules/flake/pkgs/mkMesonPackage/default.nix @@ -57,6 +57,10 @@ let __contentAddressed = true; outputHashMode = "text"; outputHashAlgo = "sha256"; + + passthru = { + target = builtins.outputOf ninjaDrv.outPath normalizedTarget; + }; }); -in builtins.outputOf ninjaDrv.outPath normalizedTarget +in ninjaDrv diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix new file mode 100644 index 0000000..df62447 --- /dev/null +++ b/modules/nixos/default.nix @@ -0,0 +1,7 @@ +{ + perSystem = { + nixosTests.nix-build-hello = import ./tests/nix-build-hello.nix; + nixosTests.nix-build-header = import ./tests/nix-build-header.nix; + nixosTests.nix-build-incremental = import ./tests/nix-build-incremental.nix; + }; +} diff --git a/modules/nixos/tests/nix-build-header.nix b/modules/nixos/tests/nix-build-header.nix new file mode 100644 index 0000000..76f80d6 --- /dev/null +++ b/modules/nixos/tests/nix-build-header.nix @@ -0,0 +1,7 @@ +{ self, pkgs, lib, ... }@args: + +import ./nix-build.nix { + flakeOutput = "example-header"; + inputsFrom = [ pkgs.example-header ]; + expectedStdout = "Hello dynamic derivations!"; +} args diff --git a/modules/nixos/tests/nix-build-hello.nix b/modules/nixos/tests/nix-build-hello.nix new file mode 100644 index 0000000..7921227 --- /dev/null +++ b/modules/nixos/tests/nix-build-hello.nix @@ -0,0 +1,7 @@ +{ self, pkgs, lib, ... }@args: + +import ./nix-build.nix { + flakeOutput = "example-hello"; + inputsFrom = [ pkgs.example-hello ]; + expectedStdout = "Hello dynamic derivations!"; +} args diff --git a/modules/nixos/tests/nix-build-incremental.nix b/modules/nixos/tests/nix-build-incremental.nix new file mode 100644 index 0000000..c888786 --- /dev/null +++ b/modules/nixos/tests/nix-build-incremental.nix @@ -0,0 +1,7 @@ +{ self, pkgs, lib, ... }@args: + +import ./nix-build.nix { + flakeOutput = "example-incremental"; + inputsFrom = [ pkgs.example-incremental ]; + expectedStdout = "Hello dynamic derivations!"; +} args diff --git a/modules/nixos/tests/nix-build.nix b/modules/nixos/tests/nix-build.nix new file mode 100644 index 0000000..e8a49fe --- /dev/null +++ b/modules/nixos/tests/nix-build.nix @@ -0,0 +1,73 @@ +# Returns a NixOS test module that strictly exercises the Nix build of an +# output of nix-ninja flake. +# +# It starts the VM with the flake inputs and inputs to the output derivation +# cached, so the Nix build can run offline and only builds the derivation and +# nothing more. + +# Output name it should `nix build ${self}#${flakeOutput}`. +{ flakeOutput +# Inputs of packages it should cache in the VM /nix/store. +, inputsFrom +# Expected stdout from the binary it builds. +, expectedStdout +}: + +{ self, pkgs, lib, ... }: +let + mergeInputs = name: + lib.subtractLists inputsFrom (lib.flatten (lib.catAttrs name inputsFrom)); + + # Extracted from `pkgs.mkShell` to capture the closure of inputs of a + # derivation. I'd like to use `.inputDerivation` but getting an error + # from Nix@2.30 atm: + # + # ```sh + # error: derivation names are allowed to end in '.drv' only if they produce a + # single derivation file + # ``` + inputsClosure = pkgs.stdenv.mkDerivation { + name = "inputs-for-${flakeOutput}"; + buildInputs = mergeInputs "buildInputs"; + nativeBuildInputs = mergeInputs "nativeBuildInputs"; + propagatedBuildInputs = mergeInputs "propagatedBuildInputs"; + propagatedNativeBuildInputs = mergeInputs "propagatedNativeBuildInputs"; + + phases = [ "buildPhase" ]; + + buildPhase = '' + export >> "$out" + ''; + }; + +in { + nodes.machine = { + virtualisation = { + # Closures that are made available to VM, these cache all inputs & flake + # inputs so that during the NixOS test it only needs to build the dynamic + # derivation. + additionalPaths = [ + inputsClosure + ] ++ (builtins.attrValues self.inputs); + }; + + environment.systemPackages = with pkgs; [ + git + nix-ninja + nix-ninja-task + nixVersions.nix_2_30 + ]; + + nix.extraOptions = '' + experimental-features = nix-command flakes dynamic-derivations ca-derivations recursive-nix + ''; + }; + + testScript = '' + start_all() + + result = machine.succeed("nix build --print-out-paths ${self}#${flakeOutput}") + out = machine.succeed(result) + assert "${expectedStdout}" in out + ''; +}