From 69f4bdb8c0ab8b83216ad27429b0cf71a11ff1be Mon Sep 17 00:00:00 2001 From: Eric Rodrigues Pires Date: Sat, 27 Jun 2026 12:50:07 -0300 Subject: [PATCH] Add top-level module.nix --- .tack/default.nix | 66 +++++++++++++++++++++++++++++++++++++---------- book/src/nixos.md | 64 ++++++++++++++++++++++++++++++++++++++++++--- module.nix | 27 +++++++++++++++++++ 3 files changed, 140 insertions(+), 17 deletions(-) create mode 100644 module.nix diff --git a/.tack/default.nix b/.tack/default.nix index cfc8495..71a5407 100644 --- a/.tack/default.nix +++ b/.tack/default.nix @@ -6,6 +6,7 @@ let attrNames attrValues concatMap + elem elemAt filter foldl' @@ -19,6 +20,7 @@ let match pathExists readFile + substring tail trace ; @@ -55,7 +57,35 @@ let acc ) { } (attrNames all_follow_raw); - fetchPin = name: fetchTree lock.${name}; + knownTypes = [ + "github" + "gitlab" + "git" + "tarball" + "path" + "indirect" + ]; + + # path nodes are convenience pins, so return the live local path directly + # because fetchTree rejects unlocked paths in pure eval + fetchPin = + name: + if !(lock ? ${name}) then + throw "tack: pin '${name}' has no lock entry; run tack update" + else + let + node = lock.${name}; + in + if (node.type or "") == "path" then + { + outPath = if substring 0 1 node.path == "/" then node.path else ./. + ("/" + node.path); + lastModified = node.lastModified or 0; + } + // (if node ? narHash then { inherit (node) narHash; } else { }) + else if !(elem (node.type or "") knownTypes) then + throw "tack: unknown lock type '${node.type or "?"}' for pin '${name}'" + else + fetchTree node; fetchFixed = name: entry: @@ -85,8 +115,17 @@ let upLock: nodeName: path: if path == [ ] then nodeName + else if !(upLock.nodes ? ${nodeName}) then + throw "tack: follows path dead-end: no node '${nodeName}' in flake.lock" else - walkPath upLock (resolveSpec upLock upLock.nodes.${nodeName}.inputs.${head path}) (tail path); + let + key = head path; + inputs = upLock.nodes.${nodeName}.inputs or { }; + in + if !(inputs ? ${key}) then + throw "tack: follows path dead-end: node '${nodeName}' has no input '${key}'" + else + walkPath upLock (resolveSpec upLock inputs.${key}) (tail path); followsFor = pin: @@ -94,7 +133,7 @@ let rules = removeAttrs all_follow (pin.exclude_follow or [ ]); in { - level = (pin.follows or { }) // rules; + level = rules // (pin.follows or { }); deep = rules; }; @@ -102,8 +141,8 @@ let _: target: self.${target} or (throw "tack: follows target '${target}' is not a pin") ); - # a follows key is `flake:name`, `tack:name`, or a bare `name`. - # project a follows set onto one side, rekeyed to bare names. + # follows key is `flake:name`, `tack:name`, or bare `name` + # project onto one side, rekeyed to bare names followsForSide = side: follows: listToAttrs ( @@ -174,8 +213,8 @@ let hasTack = pathExists tackPinsPath; upPins = if hasTack then fromTOML (readFile tackPinsPath) else { }; - # project follows onto each side, then keep only the names that side has. - # note that a bare follow reaches both, a `flake:`/`tack:` follow just the one. + # project follows onto each side, keep only names that side has + # bare follow reaches both; `flake:`/`tack:` reaches just one tackOverrides = resolveFollows ( intersectAttrs (upPins.inputs or { }) (followsForSide "tack" levelFollows) ); @@ -184,8 +223,8 @@ let # deep follows pass down raw, so each descendant re-projects per side callerInputs = mkCallerInputs upLock nodeName (raw.inputs or { }) flakeLevel deepFollows; - # upstream's own claim that its outputs forward tackOverrides. a closed - # `{ self }:` upstream would throw on the extra kwarg, so forward only here. + # upstream declares its outputs forward tackOverrides; a closed `{ self }:` + # would throw on the extra kwarg, so forward only when declared supportsOverrides = (upPins.tack or { }).recomposable or false; extraArgs = if supportsOverrides && tackOverrides != { } then { inherit tackOverrides; } else { }; @@ -231,8 +270,8 @@ let intersectAttrs (upPins.inputs or { }) (followsForSide "tack" f.level) ); in - # a fetch pin is a source tree (a path). only when there are overrides to - # push into the upstream's own .tack do we hand back its resolved inputs + # a fetch pin is a source tree (path); hand back resolved inputs only when + # there are overrides to push into the upstream's .tack if hasTack && tackOverrides != { } then let upstream = import (path + "/.tack"); @@ -261,9 +300,8 @@ let declared = pins.inputs or { }; - # undeclared lock entries are auto-dedup synthetics only when they are - # referenced as [all_follow] targets. stale locks left after hand-editing - # pins.toml are ignored, and can be cleaned with `tack rm `. + # undeclared lock entries are auto-dedup synthetics only when referenced as + # [all_follow] targets; stale locks from hand-edits are ignored (tack rm to clean) autoTargets = listToAttrs ( map (target: { name = target; diff --git a/book/src/nixos.md b/book/src/nixos.md index 00e8e37..757a273 100644 --- a/book/src/nixos.md +++ b/book/src/nixos.md @@ -4,9 +4,16 @@ Sandhole is available as a flake, containing an overlay and a NixOS service. ## Setup -If you're using Nix flakes for your system, you can install the NixOS service like so: +You can install the NixOS module for the following pinning solutions (click to expand): + + + Here's an example `configuration.nix` with Sandhole and Agnos. You can find full options in [the NixOS module options page](./nixos_options.md): ```nix @@ -40,8 +100,6 @@ Here's an example `configuration.nix` with Sandhole and Agnos. You can find full }: let - # ... - # Add admin keys to this link farm adminKeys = pkgs.linkFarm "sandhole-admin-keys" [ { diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..7d47593 --- /dev/null +++ b/module.nix @@ -0,0 +1,27 @@ +{ + system ? builtins.currentSystem, + inputs ? import ./.tack, + pkgs ? import inputs.nixpkgs { + inherit system; + overlays = [ (import inputs.rust-overlay) ]; + }, + craneLib ? (import inputs.crane { inherit pkgs; }).overrideToolchain ( + p: p.rust-bin.stable.latest.default + ), +}: +let + inherit (pkgs) lib; +in +{ + imports = [ ./nix/modules/sandhole.nix ]; + services.sandhole.package = + lib.mkDefault + (import ./nix { + inherit + system + inputs + pkgs + craneLib + ; + }).sandhole; +} -- 2.51.2