lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit bd83c4d0d87e16df949ae929d5ed68b13a9f6b07
parent f22d9a92590bc4302b207c0217cf1274a2944b3d
Author: triesap <tyson@radroots.org>
Date:   Thu, 20 Aug 2026 18:27:44 +0000

build: add service flake helpers

- centralize supported systems and injected toolchain construction
- compose generic service packages, checks, apps, and shells
- validate helper boundaries with a fail-closed fixture service
- preserve service-domain and later packaging ownership boundaries

Diffstat:
Abuild/nix/service/compose.nix | 40++++++++++++++++++++++++++++++++++++++++
Abuild/nix/service/default.nix | 7+++++++
Abuild/nix/service/fixture.nix | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/nix/service/native-inputs.nix | 14++++++++++++++
Abuild/nix/service/systems.nix | 6++++++
Abuild/nix/service/toolchain.nix | 4++++
Dbuild/nix/toolchains.nix | 6------
Mflake.nix | 27+++++++++++++++++++--------
8 files changed, 198 insertions(+), 14 deletions(-)

diff --git a/build/nix/service/compose.nix b/build/nix/service/compose.nix @@ -0,0 +1,40 @@ +{ lib }: +{ + serviceName, + package, + nativeInputs, + extraPackages ? { }, + checks ? { }, + apps ? { }, + devShells ? { }, +}: +assert lib.assertMsg ( + builtins.isString serviceName && builtins.match "^[a-z][a-z0-9_]*$" serviceName != null +) "serviceName must be a lowercase snake-case identifier"; +assert lib.assertMsg (lib.isDerivation package) "package must be a derivation"; +assert lib.assertMsg ( + builtins.isAttrs nativeInputs + && builtins.isList (nativeInputs.nativeBuildInputs or null) + && builtins.isList (nativeInputs.buildInputs or null) + && builtins.isAttrs (nativeInputs.environment or null) +) "nativeInputs must come from mkNativeInputs"; +assert lib.assertMsg (builtins.isAttrs extraPackages) "extraPackages must be an attribute set"; +assert lib.assertMsg ( + !(builtins.hasAttr "default" extraPackages) +) "extraPackages must not replace packages.default"; +assert lib.assertMsg (builtins.isAttrs checks) "checks must be an attribute set"; +assert lib.assertMsg (builtins.isAttrs apps) "apps must be an attribute set"; +assert lib.assertMsg (builtins.isAttrs devShells) "devShells must be an attribute set"; +{ + inherit + apps + checks + devShells + nativeInputs + serviceName + ; + packages = { + default = package; + } + // extraPackages; +} diff --git a/build/nix/service/default.nix b/build/nix/service/default.nix @@ -0,0 +1,7 @@ +{ lib, pkgs }: +{ + supportedSystems = import ./systems.nix; + mkToolchain = import ./toolchain.nix { inherit pkgs; }; + mkNativeInputs = import ./native-inputs.nix { inherit lib; }; + mkServiceOutputs = import ./compose.nix { inherit lib; }; +} diff --git a/build/nix/service/fixture.nix b/build/nix/service/fixture.nix @@ -0,0 +1,108 @@ +{ + lib, + pkgs, + service, +}: +let + nativeInputs = service.mkNativeInputs { + nativeBuildInputs = [ pkgs.coreutils ]; + environment = { + RADROOTS_SERVICE_FIXTURE = "1"; + }; + }; + package = pkgs.writeShellApplication { + name = "fixture-service"; + runtimeInputs = nativeInputs.nativeBuildInputs; + text = '' + case "''${1:-}" in + --help) + echo "fixture-service" + ;; + *) + echo "usage: fixture-service --help" >&2 + exit 2 + ;; + esac + ''; + }; + smoke = + pkgs.runCommand "radroots-service-helper-fixture-smoke" + { + nativeBuildInputs = [ + package + pkgs.gnugrep + ]; + } + '' + fixture-service --help > output + grep -Fx "fixture-service" output + touch "$out" + ''; + outputs = service.mkServiceOutputs { + serviceName = "fixture_service"; + inherit nativeInputs package; + checks = { + inherit smoke; + }; + apps.default = { + type = "app"; + program = "${package}/bin/fixture-service"; + }; + devShells.default = pkgs.mkShell { + packages = nativeInputs.nativeBuildInputs; + shellHook = '' + export RADROOTS_SERVICE_FIXTURE=${lib.escapeShellArg nativeInputs.environment.RADROOTS_SERVICE_FIXTURE} + ''; + }; + }; + invalidName = builtins.tryEval ( + (service.mkServiceOutputs { + serviceName = "../fixture"; + inherit nativeInputs package; + }).packages.default.outPath + ); + defaultOverride = builtins.tryEval ( + (service.mkServiceOutputs { + serviceName = "fixture_service"; + inherit nativeInputs package; + extraPackages.default = package; + }).packages.default.outPath + ); + invalidPackage = builtins.tryEval ( + (service.mkServiceOutputs { + serviceName = "fixture_service"; + inherit nativeInputs; + package = "not-a-derivation"; + }).packages.default + ); + invalidNativeInputs = builtins.tryEval ( + (service.mkServiceOutputs { + serviceName = "fixture_service"; + inherit package; + nativeInputs = { }; + }).nativeInputs + ); +in +assert + service.supportedSystems == [ + "aarch64-darwin" + "aarch64-linux" + "x86_64-darwin" + "x86_64-linux" + ]; +assert nativeInputs.nativeBuildInputs == [ pkgs.coreutils ]; +assert nativeInputs.buildInputs == [ ]; +assert nativeInputs.environment.RADROOTS_SERVICE_FIXTURE == "1"; +assert outputs.serviceName == "fixture_service"; +assert outputs.packages.default == package; +assert outputs.checks.smoke == smoke; +assert outputs.apps.default.program == "${package}/bin/fixture-service"; +assert outputs.devShells.default != null; +assert invalidName.success == false; +assert defaultOverride.success == false; +assert invalidPackage.success == false; +assert invalidNativeInputs.success == false; +{ + inherit outputs; + check = smoke; +} diff --git a/build/nix/service/native-inputs.nix b/build/nix/service/native-inputs.nix @@ -0,0 +1,14 @@ +{ lib }: +{ + nativeBuildInputs ? [ ], + buildInputs ? [ ], + environment ? { }, +}: +assert lib.assertMsg (builtins.isList nativeBuildInputs) "nativeBuildInputs must be a list"; +assert lib.assertMsg (builtins.isList buildInputs) "buildInputs must be a list"; +assert lib.assertMsg (builtins.isAttrs environment) "environment must be an attribute set"; +{ + nativeBuildInputs = lib.unique nativeBuildInputs; + buildInputs = lib.unique buildInputs; + inherit environment; +} diff --git a/build/nix/service/systems.nix b/build/nix/service/systems.nix @@ -0,0 +1,6 @@ +[ + "aarch64-darwin" + "aarch64-linux" + "x86_64-darwin" + "x86_64-linux" +] diff --git a/build/nix/service/toolchain.nix b/build/nix/service/toolchain.nix @@ -0,0 +1,4 @@ +{ pkgs }: +{ rustToolchainFile }: +assert builtins.pathExists rustToolchainFile; +pkgs.rust-bin.fromRustupToolchainFile rustToolchainFile diff --git a/build/nix/toolchains.nix b/build/nix/toolchains.nix @@ -1,6 +0,0 @@ -{ pkgs }: -{ - stable = pkgs.rust-bin.fromRustupToolchainFile ../../rust-toolchain.toml; - - coverage = pkgs.rust-bin.fromRustupToolchainFile ../../rust-toolchain-coverage.toml; -} diff --git a/flake.nix b/flake.nix @@ -19,12 +19,7 @@ inputs@{ flake-parts, ... }: flake-parts.lib.mkFlake { inherit inputs; } { imports = [ inputs.treefmt-nix.flakeModule ]; - systems = [ - "aarch64-darwin" - "aarch64-linux" - "x86_64-darwin" - "x86_64-linux" - ]; + systems = import ./build/nix/service/systems.nix; perSystem = { @@ -38,11 +33,24 @@ inherit system; overlays = [ inputs.rust-overlay.overlays.default ]; }; - toolchains = import ./build/nix/toolchains.nix { inherit pkgs; }; + service = import ./build/nix/service { + inherit lib pkgs; + }; + toolchains = { + stable = service.mkToolchain { + rustToolchainFile = ./rust-toolchain.toml; + }; + coverage = service.mkToolchain { + rustToolchainFile = ./rust-toolchain-coverage.toml; + }; + }; common = import ./build/nix/common.nix { crane = inputs.crane; inherit lib pkgs toolchains; }; + serviceFixture = import ./build/nix/service/fixture.nix { + inherit lib pkgs service; + }; in { treefmt = import ./treefmt.nix; @@ -58,8 +66,11 @@ }; checks = lib.filterAttrs (_: value: value != null) ( - import ./build/nix/checks.nix { + (import ./build/nix/checks.nix { inherit common pkgs; + }) + // { + service-helper-fixture = serviceFixture.check; } );