From ad56f2ecefe8a3843496a6d76f04300fed3e01f7 Mon Sep 17 00:00:00 2001 From: alexion Date: Sun, 27 Sep 2026 18:48:32 -0400 Subject: [PATCH] refactor(dotfiles): split registry responsibilities --- src/dotfiles/registry.nix | 160 +++----------------------- src/dotfiles/registry/collection.nix | 82 +++++++++++++ src/dotfiles/registry/definitions.nix | 26 +++++ src/dotfiles/registry/options.nix | 22 ++++ src/dotfiles/registry/validation.nix | 44 +++++++ 5 files changed, 188 insertions(+), 146 deletions(-) create mode 100644 src/dotfiles/registry/collection.nix create mode 100644 src/dotfiles/registry/definitions.nix create mode 100644 src/dotfiles/registry/options.nix create mode 100644 src/dotfiles/registry/validation.nix diff --git a/src/dotfiles/registry.nix b/src/dotfiles/registry.nix index d0ce789..477acf7 100644 --- a/src/dotfiles/registry.nix +++ b/src/dotfiles/registry.nix @@ -5,152 +5,20 @@ util, }: let - definitions = lib.genAttrs' (util.collectNixFiles root) ( - path: lib.nameValuePair (util.removeNixSuffix path) (mkRegistry path) - ); - - mkRegistry = - path: - let - evaluated = lib.evalModules { - specialArgs = { inherit util; }; - modules = [ - (import ./registry/schema.nix { inherit lib; }) - path - ]; - }; - in - { - inherit (evaluated.config) type replicate checks; - }; - - registryOption = - registry: - lib.mkOption { - type = lib.types.attrsOf (lib.types.attrsOf registry.type); - default = { }; - description = '' - Lazily collected fleet-visible registry entries, nested by host and entry name. - ''; - }; - withOperations = - registry: - registry - // { - join = host: entry: join registry host entry; - }; - join = - registry: host: entry: - lib.filterAttrs (_name: value: value != null) ( - lib.mapAttrs ( - registryName: _registry: (registry.${registryName}.${host} or { }).${entry} or null - ) definitions - ); - - collectData = - { hosts }: - let - data = lib.mapAttrs ( - registryName: registry: - if registry.replicate or false then - replicatedData registryName hosts raw.${registryName} - else - lib.mapAttrs (hostName: host: host.config.registry.${registryName}.${hostName} or { }) hosts - ) definitions; - raw = lib.mapAttrs (registryName: _registry: rawDeclarations registryName hosts) definitions; - in - assertValid data; - - replicatedData = - registryName: hosts: raw: - let - entries = lib.mapAttrs (_entryName: entry: entry.value) (replicatedEntries registryName raw); - in - lib.mapAttrs (_hostName: _host: entries) hosts; - - replicatedEntries = - registryName: raw: - let - entries = lib.concatLists ( - lib.concatLists ( - lib.mapAttrsToList ( - _evalHost: hostDeclarations: - lib.mapAttrsToList ( - hostName: declarations: - lib.mapAttrsToList (entryName: value: { - path = "registry.${registryName}.${hostName}.${entryName}"; - inherit entryName value; - }) declarations - ) hostDeclarations - ) raw - ) - ); - in - lib.foldl' ( - acc: entry: - if lib.hasAttr entry.entryName acc then - if acc.${entry.entryName}.value == entry.value then - acc - else - throw "conflicting replicated registry entry ${entry.path} does not match ${acc.${entry.entryName}.path}" - else - acc - // { - ${entry.entryName} = entry; - } - ) { } entries; - - rawDeclarations = - registryName: hosts: - lib.mapAttrs (_hostName: host: host.config.registry.${registryName} or { }) hosts; - - assertValid = - data: - let - assertions = validationAssertions data; - failures = lib.filter (assertion: !assertion.assertion) assertions; - in - assert lib.assertMsg (lib.all (assertion: assertion.assertion) assertions) ( - lib.concatMapStringsSep "\n" (assertion: assertion.message) failures - ); - data; - - validationAssertions = - data: - lib.concatLists ( - lib.mapAttrsToList ( - registryName: registry: - let - entries = flattenRegistryEntries registryName data.${registryName}; - in - map (check: { - assertion = check.assertion entries; - inherit (check) message; - }) registry.checks - ) definitions - ); - - flattenRegistryEntries = - registryName: data: - lib.concatLists ( - lib.mapAttrsToList ( - host: entries: - lib.mapAttrsToList (entry: value: { - path = "registry.${registryName}.${host}.${entry}"; - inherit host entry value; - }) entries - ) data - ); - -in -{ - types = lib.mapAttrs (_name: definition: definition.type) definitions; - - module = { - options.registry = lib.mapAttrs (_name: registryOption) definitions; + options = import ./registry/options.nix { + inherit definitions lib; }; - collected = withOperations (collectData { - inherit hosts; - }); + definitions = import ./registry/definitions.nix { + inherit lib root util; + }; + + collected = import ./registry/collection.nix { + inherit definitions hosts lib; + validate = import ./registry/validation.nix { inherit definitions lib; }; + }; +in +{ + inherit (options) types module; + inherit collected; } diff --git a/src/dotfiles/registry/collection.nix b/src/dotfiles/registry/collection.nix new file mode 100644 index 0000000..57897c2 --- /dev/null +++ b/src/dotfiles/registry/collection.nix @@ -0,0 +1,82 @@ +{ + definitions, + hosts, + lib, + validate, +}: +let + withOperations = + registry: + registry + // { + join = host: entry: join registry host entry; + }; + + join = + registry: host: entry: + lib.filterAttrs (_name: value: value != null) ( + lib.mapAttrs ( + registryName: _registry: (registry.${registryName}.${host} or { }).${entry} or null + ) definitions + ); + + collectData = + { hosts }: + let + data = lib.mapAttrs ( + registryName: registry: + if registry.replicate or false then + replicatedData registryName hosts raw.${registryName} + else + lib.mapAttrs (hostName: host: host.config.registry.${registryName}.${hostName} or { }) hosts + ) definitions; + raw = lib.mapAttrs (registryName: _registry: rawDeclarations registryName hosts) definitions; + in + validate data; + + replicatedData = + registryName: hosts: raw: + let + entries = lib.mapAttrs (_entryName: entry: entry.value) (replicatedEntries registryName raw); + in + lib.mapAttrs (_hostName: _host: entries) hosts; + + replicatedEntries = + registryName: raw: + let + entries = lib.concatLists ( + lib.concatLists ( + lib.mapAttrsToList ( + _evalHost: hostDeclarations: + lib.mapAttrsToList ( + hostName: declarations: + lib.mapAttrsToList (entryName: value: { + path = "registry.${registryName}.${hostName}.${entryName}"; + inherit entryName value; + }) declarations + ) hostDeclarations + ) raw + ) + ); + in + lib.foldl' ( + acc: entry: + if lib.hasAttr entry.entryName acc then + if acc.${entry.entryName}.value == entry.value then + acc + else + throw "conflicting replicated registry entry ${entry.path} does not match ${acc.${entry.entryName}.path}" + else + acc + // { + ${entry.entryName} = entry; + } + ) { } entries; + + rawDeclarations = + registryName: hosts: + lib.mapAttrs (_hostName: host: host.config.registry.${registryName} or { }) hosts; +in +withOperations (collectData { + inherit hosts; +}) diff --git a/src/dotfiles/registry/definitions.nix b/src/dotfiles/registry/definitions.nix new file mode 100644 index 0000000..f2b2c40 --- /dev/null +++ b/src/dotfiles/registry/definitions.nix @@ -0,0 +1,26 @@ +{ + lib, + root, + util, +}: +let + definitions = lib.genAttrs' (util.collectNixFiles root) ( + path: lib.nameValuePair (util.removeNixSuffix path) (mkRegistry path) + ); + + mkRegistry = + path: + let + evaluated = lib.evalModules { + specialArgs = { inherit util; }; + modules = [ + (import ./schema.nix { inherit lib; }) + path + ]; + }; + in + { + inherit (evaluated.config) type replicate checks; + }; +in +definitions diff --git a/src/dotfiles/registry/options.nix b/src/dotfiles/registry/options.nix new file mode 100644 index 0000000..021b13f --- /dev/null +++ b/src/dotfiles/registry/options.nix @@ -0,0 +1,22 @@ +{ + definitions, + lib, +}: +let + registryOption = + registry: + lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf registry.type); + default = { }; + description = '' + Lazily collected fleet-visible registry entries, nested by host and entry name. + ''; + }; +in +{ + types = lib.mapAttrs (_name: definition: definition.type) definitions; + + module = { + options.registry = lib.mapAttrs (_name: registryOption) definitions; + }; +} diff --git a/src/dotfiles/registry/validation.nix b/src/dotfiles/registry/validation.nix new file mode 100644 index 0000000..1840ff5 --- /dev/null +++ b/src/dotfiles/registry/validation.nix @@ -0,0 +1,44 @@ +{ + definitions, + lib, +}: +let + assertValid = + data: + let + assertions = validationAssertions data; + failures = lib.filter (assertion: !assertion.assertion) assertions; + in + assert lib.assertMsg (lib.all (assertion: assertion.assertion) assertions) ( + lib.concatMapStringsSep "\n" (assertion: assertion.message) failures + ); + data; + + validationAssertions = + data: + lib.concatLists ( + lib.mapAttrsToList ( + registryName: registry: + let + entries = flattenRegistryEntries registryName data.${registryName}; + in + map (check: { + assertion = check.assertion entries; + inherit (check) message; + }) registry.checks + ) definitions + ); + + flattenRegistryEntries = + registryName: data: + lib.concatLists ( + lib.mapAttrsToList ( + host: entries: + lib.mapAttrsToList (entry: value: { + path = "registry.${registryName}.${host}.${entry}"; + inherit host entry value; + }) entries + ) data + ); +in +assertValid