minimal working state

This commit is contained in:
do butterflies cry? 2026-03-17 20:37:59 +10:00
parent 855430ef16
commit 6c1a0a5d33
Signed by: cry
GPG key ID: F68745A836CA0412
26 changed files with 331 additions and 326 deletions

32
flake.lock generated
View file

@ -9,11 +9,11 @@
"utils": "utils" "utils": "utils"
}, },
"locked": { "locked": {
"lastModified": 1766051518, "lastModified": 1770019181,
"narHash": "sha256-znKOwPXQnt3o7lDb3hdf19oDo0BLP4MfBOYiWkEHoik=", "narHash": "sha256-hwsYgDnby50JNVpTRYlF3UR/Rrpt01OrxVuryF40CFY=",
"owner": "serokell", "owner": "serokell",
"repo": "deploy-rs", "repo": "deploy-rs",
"rev": "d5eff7f948535b9c723d60cd8239f8f11ddc90fa", "rev": "77c906c0ba56aabdbc72041bf9111b565cdd6171",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -68,11 +68,11 @@
"spectrum": "spectrum" "spectrum": "spectrum"
}, },
"locked": { "locked": {
"lastModified": 1771365290, "lastModified": 1773018425,
"narHash": "sha256-1XJOslVyF7yzf6yd/yl1VjGLywsbtwmQh3X1LuJcLI4=", "narHash": "sha256-fpgZBmZpKoEXEowBK/6m8g9FcOLWQ4UxhXHqCw2CpSM=",
"owner": "microvm-nix", "owner": "microvm-nix",
"repo": "microvm.nix", "repo": "microvm.nix",
"rev": "789c90b164b55b4379e7a94af8b9c01489024c18", "rev": "25ebda3c558e923720c965832dc9a04f559a055c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -129,11 +129,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1768323494, "lastModified": 1773375660,
"narHash": "sha256-yBXJLE6WCtrGo7LKiB6NOt6nisBEEkguC/lq/rP3zRQ=", "narHash": "sha256-SEzUWw2Rf5Ki3bcM26nSKgbeoqi2uYy8IHVBqOKjX3w=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "2c3e5ec5df46d3aeee2a1da0bfedd74e21f4bf3a", "rev": "3e20095fe3c6cbb1ddcef89b26969a69a1570776",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -166,11 +166,11 @@
"systems": "systems_2" "systems": "systems_2"
}, },
"locked": { "locked": {
"lastModified": 1770975056, "lastModified": 1773738366,
"narHash": "sha256-ZXTz/P3zUbbM6lNXzt91u8EwfNqhXpYMu8+wvFZqQHE=", "narHash": "sha256-oH22HyNHEdCoCQo734sQCHUr6C0jmGQJMZ13dsgEHkk=",
"owner": "cry128", "owner": "cry128",
"repo": "nt", "repo": "nt",
"rev": "f42dcdd49a7921a7f433512e83d5f93696632412", "rev": "f32c3a726a3d608d30aaaa1df2301c1eaf5ef8f4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -212,11 +212,11 @@
"spectrum": { "spectrum": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1759482047, "lastModified": 1772189877,
"narHash": "sha256-H1wiXRQHxxPyMMlP39ce3ROKCwI5/tUn36P8x6dFiiQ=", "narHash": "sha256-i1p90Rgssb//aNiTDFq46ZG/fk3LmyRLChtp/9lddyA=",
"ref": "refs/heads/main", "ref": "refs/heads/main",
"rev": "c5d5786d3dc938af0b279c542d1e43bce381b4b9", "rev": "fe39e122d898f66e89ffa17d4f4209989ccb5358",
"revCount": 996, "revCount": 1255,
"type": "git", "type": "git",
"url": "https://spectrum-os.org/git/spectrum" "url": "https://spectrum-os.org/git/spectrum"
}, },

View file

@ -15,22 +15,28 @@
mix, mix,
inputs, inputs,
... ...
} @ args: } @ args: let
mix.newMixture args (mixture: { mixArgs =
submods.public = [ args
./snow // {
]; inherit (inputs.nixpkgs) lib;
};
in
mix.newMixture mixArgs (mixture: {
submods.public = [
./snow
];
version = "0.2.6-alpha"; version = "0.2.6-alpha";
overlays = [ overlays = [
# build deploy-rs as a package not from the flake input, # build deploy-rs as a package not from the flake input,
# hence we can rely on a nixpkg binary cache. # hence we can rely on a nixpkg binary cache.
inputs.deploy-rs.overlays.default inputs.deploy-rs.overlays.default
]; ];
nixosModules = rec { nixosModules = rec {
default = cerulean; default = cerulean;
cerulean = ./nixos; cerulean = ./nixos;
}; };
}) })

View file

@ -18,13 +18,13 @@
node, node,
pkgs, pkgs,
lib, lib,
_cerulean, _snow,
... ...
} @ args: { } @ args: {
imports = imports =
[ [
_cerulean.inputs.sops-nix.nixosModules.sops _snow.inputs.sops-nix.nixosModules.sops
# _cerulean.inputs.microvm.nixosModules.microvm # _snow.inputs.microvm.nixosModules.microvm
# add support for `options.legacyImports` # add support for `options.legacyImports`
# ./legacy-imports.nix # ./legacy-imports.nix
@ -36,7 +36,7 @@
(import /${root}/nixpkgs.nix) (import /${root}/nixpkgs.nix)
] ]
# homemanager options declarations # homemanager options declarations
++ (lib.optional (_cerulean.homeManager != null) ./home.nix) ++ (lib.optional (_snow.homeManager != null) ./home.nix)
# remote deployment configuration # remote deployment configuration
++ (lib.optional (node.deploy.ssh.host != null) ./remote-deploy); ++ (lib.optional (node.deploy.ssh.host != null) ./remote-deploy);
@ -46,7 +46,7 @@
(with pkgs; [ (with pkgs; [
sops sops
]) ])
++ (with _cerulean.inputs; [ ++ (with _snow.inputs; [
deploy-rs.packages.${system}.default deploy-rs.packages.${system}.default
]); ]);
} }

View file

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
{ {
_cerulean, _snow,
config, config,
root, root,
lib, lib,
@ -30,7 +30,7 @@
; ;
in { in {
imports = [ imports = [
_cerulean.homeManager.nixosModules.default _snow.homeManager.nixosModules.default
]; ];
options = { options = {
@ -69,7 +69,7 @@ in {
_module.args.username = name; _module.args.username = name;
}); });
extraSpecialArgs = _cerulean.specialArgs; extraSpecialArgs = _snow.specialArgs;
sharedModules = [ sharedModules = [
../home ../home

View file

@ -11,12 +11,17 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
{mix, ...} @ args: {
mix.newMixture args (mixture: { nt,
includes = { mix,
public = [ ...
./flake } @ args:
./lib mix.newMixture (removeAttrs args ["this"]) (mixture: {
]; submods.public = [
}; ./lib
];
includes.public = [
./flake
];
}) })

View file

@ -1,4 +1,5 @@
{ {
self,
this, this,
inputs, inputs,
systems, systems,
@ -16,14 +17,20 @@
inherit (inputs.nixpkgs) lib; inherit (inputs.nixpkgs) lib;
in { in {
# snow.flake # snow.flake
# XXX: TODO: stop taking in root as parameter (maybe take self instead?)
flake = flakeInputs: root: let flake = flakeInputs: root: let
snowflake = lib.evalModules { snowflake = lib.evalModules {
class = "snowflake"; class = "snowflake";
specialArgs = let specialArgs = let
reservedSpecialArgs = { reservedSpecialArgs = {
inherit (this) snow; # inherit (this) snow;
snow = this;
inherit systems root; inherit systems root;
inputs = flakeInputs; inputs = flakeInputs;
_snowFlake = {
inherit self inputs;
};
}; };
warnIfReserved = let warnIfReserved = let
@ -50,7 +57,10 @@ in {
flakeInputs // reservedSpecialArgs; flakeInputs // reservedSpecialArgs;
modules = [ modules = [
./module.nix ./nodes
./modules
./outputs
(this.lib.findImport /${root}/snow)
]; ];
}; };
in in

View file

@ -1,24 +0,0 @@
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
{
root,
snow,
...
}: {
imports = [
./nodes
./modules
(snow.findImport /${root}/snow)
];
}

View file

@ -10,7 +10,7 @@
; ;
inherit inherit
(snow) (snow.lib)
mkPerSystemFlakeOutput mkPerSystemFlakeOutput
; ;

View file

@ -9,7 +9,7 @@
types types
; ;
inherit inherit
(snow) (snow.lib)
mkPerSystemFlakeOutput mkPerSystemFlakeOutput
; ;
in in

View file

@ -10,7 +10,7 @@
literalExpression literalExpression
; ;
inherit inherit
(snow) (snow.lib)
mkPerSystemFlakeOutput mkPerSystemFlakeOutput
; ;
in in

View file

@ -9,7 +9,7 @@
types types
; ;
inherit inherit
(snow) (snow.lib)
mkPerSystemFlakeOutput mkPerSystemFlakeOutput
; ;
in in

View file

@ -9,7 +9,7 @@
types types
; ;
inherit inherit
(snow) (snow.lib)
mkPerSystemFlakeOutput mkPerSystemFlakeOutput
; ;
in in

View file

@ -8,38 +8,39 @@
mkOption mkOption
types types
; ;
outputs = mkOption {
type = types.submoduleWith {
modules = [
{
freeformType =
types.lazyAttrsOf
(types.unique
{
message = ''
No option has been declared for this flake output attribute, so its definitions can't be merged automatically.
Possible solutions:
- Load a module that defines this flake output attribute
- Declare an option for this flake output attribute
- Make sure the output attribute is spelled correctly
- Define the value only once, with a single definition in a single module
'';
}
types.raw);
}
];
};
description = ''
Raw flake output attributes. Any attribute can be set here, but some
attributes are represented by options, to provide appropriate
configuration merging.
'';
};
in { in {
options = { options = {
inherit outputs; outputs = mkOption {
type = types.submoduleWith {
modules = [
{
freeformType =
types.lazyAttrsOf
(types.unique
{
message = ''
No option has been declared for this flake output attribute, so its definitions can't be merged automatically.
Possible solutions:
- Load a module that defines this flake output attribute
- Declare an option for this flake output attribute
- Make sure the output attribute is spelled correctly
- Define the value only once, with a single definition in a single module
'';
}
types.raw);
}
];
};
description = ''
Raw flake output attributes. Any attribute can be set here, but some
attributes are represented by options, to provide appropriate
configuration merging.
'';
};
}; };
config = {inherit (config) flake;}; config = {
# ensure a minimal version is set
outputs = {};
};
} }

View file

@ -10,7 +10,7 @@
; ;
inherit inherit
(snow) (snow.lib)
mkPerSystemFlakeOutput mkPerSystemFlakeOutput
; ;
in in

View file

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
{ {
_snow, _snowFlake,
lib, lib,
specialArgs, specialArgs,
... ...
@ -39,7 +39,7 @@
config = { config = {
nodes = { nodes = {
base = _snow.inputs.nixpkgs; base = _snowFlake.inputs.nixpkgs;
}; };
}; };
} }

View file

@ -1,73 +0,0 @@
# # Copyright 2025-2026 _cry64 (Emile Clark-Boman)
# #
# # Licensed under the Apache License, Version 2.0 (the "License");
# # you may not use this file except in compliance with the License.
# # You may obtain a copy of the License at
# #
# # http://www.apache.org/licenses/LICENSE-2.0
# #
# # Unless required by applicable law or agreed to in writing, software
# # distributed under the License is distributed on an "AS IS" BASIS,
# # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# # See the License for the specific language governing permissions and
# # limitations under the License.
{nt, ...}: let
inherit
(builtins)
concatLists
elem
filter
isAttrs
mapAttrs
pathExists
typeOf
;
rootGroupName = "all";
in {
parseGroupsDecl = groups: let
validGroup = g:
isAttrs g
|| throw ''
Snow node groups must be provided as attribute sets, got "${typeOf g}" instead!
Ensure all the group definitions are attribute sets under your call to `snow.flake`.
NOTE: Groups can be accessed via `self.groups.PATH.TO.YOUR.GROUP`
'';
delegate = parent: gName: g: let
result =
(g
// {
_name = gName;
_parent = parent;
})
|> mapAttrs (name: value:
if elem name ["_name" "_parent"]
# ignore metadata fields
then value
else assert validGroup value; (delegate result name value));
in
result;
in
assert validGroup groups;
delegate null rootGroupName groups;
getGroupModules = root: groups:
# ensure root group is always added
groups
# add all inherited groups via _parent
|> map (let
delegate = g:
if g._parent == null
then [g]
else [g] ++ delegate (g._parent);
in
delegate)
# flatten recursion result
|> concatLists
# find import location
|> map (group: nt.findImport /${root}/groups/${group._name})
# filter by uniqueness
|> nt.prim.unique
# ignore missing groups
|> filter pathExists;
}

View file

@ -14,8 +14,9 @@
{ {
lib, lib,
systems, systems,
config,
nodesConfig, nodesConfig,
groups,
groupLibs,
... ...
}: { }: {
options = let options = let
@ -25,6 +26,11 @@
types types
; ;
inherit
(groupLibs)
resolveGroupsInheritance
;
flakeRef = types.either types.str types.path; flakeRef = types.either types.str types.path;
in { in {
enabled = lib.mkOption { enabled = lib.mkOption {
@ -113,8 +119,8 @@
A function from the `groups` hierarchy to a list of groups this node inherits from. A function from the `groups` hierarchy to a list of groups this node inherits from.
''; '';
apply = groupsFn: # apply = groupsFn:
groupsFn nodesConfig.groups; # groupsFn nodesConfig.groups |> resolveGroupsInheritance;
}; };
deploy = { deploy = {
@ -266,32 +272,32 @@
}; };
}; };
config = let # config = let
throwGotNull = name: # throwGotNull = name:
throw '' # throw ''
[snow] `nodes.<name>.${name}` must be set for all nodes! (got: <null>) # [snow] `nodes.<name>.${name}` must be set for all nodes! (got: <null>)
''; # '';
givenSystem = # givenSystem =
(config.system != null) # (config.system != null)
|| throwGotNull "system"; # || throwGotNull "system";
givenBase = # givenBase =
(config.base != null) # (config.base != null)
|| throwGotNull "base"; # || throwGotNull "base";
givenHomeManager = # givenHomeManager =
(config.homeManager != null) # (config.homeManager != null)
|| throwGotNull "homeManager"; # || throwGotNull "homeManager";
givenDeployHost = # givenDeployHost =
(config.deploy.ssh.host != null) # (config.deploy.ssh.host != null)
|| throwGotNull "deploy.ssh.host"; # || throwGotNull "deploy.ssh.host";
in # in
assert givenSystem # assert givenSystem
&& givenBase # && givenBase
&& givenHomeManager # && givenHomeManager
&& givenDeployHost; { # && givenDeployHost; {
# extend these from the nodes configuration # # extend these from the nodes configuration
inherit (nodesConfig) modules args; # inherit (nodesConfig) modules args;
}; # };
} }

View file

@ -12,7 +12,9 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
{ {
_snow, _snowFlake,
snow,
root,
lib, lib,
config, config,
specialArgs, specialArgs,
@ -26,7 +28,10 @@
flakeRef = types.either types.str types.path; flakeRef = types.either types.str types.path;
groupLibs = import ./groups.nix {inherit (_snow.inputs) nt;}; groupLibs = import ./groups.nix {
inherit snow root;
inherit (_snowFlake.inputs) nt;
};
in { in {
options = { options = {
base = lib.mkOption { base = lib.mkOption {
@ -94,8 +99,6 @@ in {
description = '' description = ''
Hierarchical groups that nodes can be a member of. Hierarchical groups that nodes can be a member of.
''; '';
apply = groupLibs.parseGroupsDecl;
}; };
nodes = mkOption { nodes = mkOption {
@ -103,7 +106,8 @@ in {
specialArgs = specialArgs =
specialArgs specialArgs
// { // {
nodeConfig = config; nodesConfig = config;
inherit groupLibs;
}; };
modules = [./node.nix]; modules = [./node.nix];
}); });

View file

@ -1,10 +1,10 @@
{ {
config, config,
_snow, _snowFlake,
... ...
}: { }: {
outputs.checks = outputs.checks =
_snow.inputs.deploy-rs.lib _snowFlake.inputs.deploy-rs.lib
|> builtins.mapAttrs (system: deployLib: |> builtins.mapAttrs (system: deployLib:
deployLib.deployChecks config.outputs.deploy); deployLib.deployChecks config.outputs.deploy);
} }

View file

@ -0,0 +1,7 @@
{...}: {
imports = [
./checks.nix
./deploy.nix
./nixosConfigurations.nix
];
}

View file

@ -1,37 +1,10 @@
{ {
_snow, _snowFlake,
snow,
config, config,
... ...
}: let }: {
inherit outputs.deploy.nodes = snow.lib.mapNodes config.nodes ({
(builtins)
mapAttrs
;
mapNodes = nodes: f:
nodes.nodes
|> mapAttrs (name: node: let
# use per-node base or default to nodes' base
base =
if node.base != null
then node.base
else if nodes.base != null
then nodes.base
else
abort ''
snow cannot construct nodes node "${name}" without a base package source.
Ensure `nodes.nodes.*.base` or `nodes.base` is a flake reference to the github:NixOS/nixpkgs repository.
'';
in
f rec {
inherit name node base;
inherit (base) lib;
groups = node.groups (parseGroupsDecl nodes.groups);
groupModules = root: getGroupModules root groups;
});
in {
outputs.deploy.nodes = mapNodes config.nodes ({
name, name,
node, node,
... ...
@ -49,7 +22,7 @@ in {
confirmTimeout confirmTimeout
; ;
nixosFor = system: _snow.inputs.deploy-rs.lib.${system}.activate.nixos; nixosFor = system: _snowFlake.inputs.deploy-rs.lib.${system}.activate.nixos;
in { in {
hostname = hostname =
if ssh.host != null if ssh.host != null

View file

@ -1,14 +1,5 @@
# {
# _module = { ... };
# _type = "configuration";
# class = null;
# config = { ... };
# extendModules = «lambda extendModules @ /nix/store/9hfp0agnm43kz72l5lpfn9var5p0x2fa-source/lib/modules.nix:340:9»;
# graph = [ ... ];
# options = { ... };
# type = { ... };
# }
{ {
_snowFlake,
snow, snow,
config, config,
systems, systems,
@ -27,59 +18,67 @@
nodes nodes
; ;
in { in {
outputs.nixosConfigurations = mapNodes nodes ( outputs.nixosConfigurations = let
{ groups = snow.lib.parseGroupDecls root config.nodes.groups;
base, in
lib, snow.lib.mapNodes nodes (
name, {
node, base,
groupModules, lib,
... name,
}: let node,
homeManager = ...
if node.homeManager != null }: let
then node.homeManager nodeGroups =
else if nodes.homeManager != null (node.groups groups)
then nodes.homeManager |> snow.lib.resolveGroupsInheritance
else |> snow.lib.groupModules;
warn ''
[snowflake] Neither `nodes.homeManager` nor `nodes.nodes.${name}.homeManager` were specified!
[snowflake] home-manager will NOT be used! User configuration will be ignored!
''
null;
userArgs = nodes.args // node.args; homeManager =
snowArgs = { if node.homeManager != null
inherit systems snow root base nodes node; then node.homeManager
inherit (node) system; else if nodes.homeManager != null
hostname = name; then nodes.homeManager
else
warn ''
[snowflake] Neither `nodes.homeManager` nor `nodes.nodes.${name}.homeManager` were specified!
[snowflake] home-manager will NOT be used! User configuration will be ignored!
''
null;
_snow = { userArgs = nodes.args // node.args;
inherit inputs userArgs snowArgs homeManager; snowArgs = {
specialArgs = userArgs // snowArgs; inherit systems snow root base nodes node;
inherit (node) system;
hostname = name;
_snow = {
inherit (_snowFlake) inputs;
inherit userArgs snowArgs homeManager;
specialArgs = userArgs // snowArgs;
};
}; };
}; specialArgs = assert (userArgs
specialArgs = assert (userArgs |> attrNames
|> attrNames |> all (argName:
|> all (argName: ! snowArgs ? argName
! snowArgs ? argName || abort ''
|| abort '' `specialArgs` are like super important to Snow my love... </3
`specialArgs` are like super important to Snow my love... </3 But `args.${argName}` is a reserved argument name :(
But `args.${argName}` is a reserved argument name :( ''));
'')); snowArgs._snow.specialArgs;
snowArgs._snow.specialArgs; in
in lib.nixosSystem {
lib.nixosSystem { inherit (node) system;
inherit (node) system; inherit specialArgs;
inherit specialArgs; modules =
modules = [
[ _snowFlake.self.nixosModules.default
snow.nixosModules.default (snow.lib.findImport /${root}/hosts/${name})
(snow.findImport /${root}/hosts/${name}) ]
] ++ nodeGroups
++ (groupModules root) ++ node.modules
++ node.modules ++ nodes.modules;
++ nodes.modules; }
} );
);
} }

View file

@ -15,13 +15,11 @@
nt, nt,
mix, mix,
... ...
} @ args: let } @ args:
inherit (nt) findImport; mix.newMixture args (mixture: {
in includes.public = [
mix.newMixture args (mixture: { ./util.nix
includes.public = [ ./nixpkgs.nix
./nixpkgs.nix ./nodes.nix
]; ];
})
inherit findImport;
})

View file

@ -14,9 +14,12 @@
minVersion = "23.05pre-git"; minVersion = "23.05pre-git";
isNixpkgsValidVersion = let isNixpkgsValidVersion = let
revInfo = lib.optional (inputs.nixpkgs?rev) " (nixpkgs-lib.rev: ${inputs.nixpkgs.rev})"; revInfo =
if inputs.nixpkgs?rev
then " (nixpkgs-lib.rev: ${inputs.nixpkgs.rev})"
else "";
in in
(builtins.compareVersions lib.version minVersion < 0) (builtins.compareVersions lib.version minVersion >= 0)
|| abort '' || abort ''
The nixpkgs dependency of snow was overridden but is too old. The nixpkgs dependency of snow was overridden but is too old.
The minimum supported version of nixpkgs-lib is ${minVersion}, The minimum supported version of nixpkgs-lib is ${minVersion},

87
nix/snow/lib/nodes.nix Normal file
View file

@ -0,0 +1,87 @@
{
this,
nt,
...
}: let
inherit
(builtins)
concatLists
elem
filter
isAttrs
mapAttrs
pathExists
typeOf
;
inherit (nt.prim) uniq;
rootGroupName = "all";
in {
mapNodes = nodes: f:
nodes.nodes
|> mapAttrs (name: node: let
# use per-node base or default to nodes' base
base =
if node.base != null
then node.base
else if nodes.base != null
then nodes.base
else
abort ''
snow cannot construct nodes node "${name}" without a base package source.
Ensure `nodes.nodes.*.base` or `nodes.base` is a flake reference to the github:NixOS/nixpkgs repository.
'';
in
f rec {
inherit name node base;
inherit (base) lib;
inherit (node) groups;
});
groupModules = map (group: group._module);
parseGroupDecls = root: groupDecls: let
validGroup = g:
isAttrs g
|| throw ''
Snow node groups must be provided as attribute sets, got "${typeOf g}" instead!
Ensure all the group definitions are attribute sets under your call to `snow.flake`.
'';
delegate = parent: gName: g: let
result =
(g
// {
_name = gName;
_parent = parent;
_module = this.lib.findImport /${root}/groups/${gName};
})
|> mapAttrs (name: value:
if elem name ["_name" "_parent" "_module"]
# ignore metadata fields
then value
else assert validGroup value; (delegate result name value));
in
result;
in
assert validGroup groupDecls;
delegate null rootGroupName groupDecls;
resolveGroupsInheritance = groups:
groups
# add all inherited groups via _parent
|> map (let
delegate = g:
if g._parent == null
then [g]
else [g] ++ delegate (g._parent);
in
delegate)
# flatten recursion result
|> concatLists
# ignore missing groups
|> filter (group: pathExists group._module)
# filter by uniqueness
|> uniq;
}

3
nix/snow/lib/util.nix Normal file
View file

@ -0,0 +1,3 @@
{nt, ...}: {
inherit (nt) findImport;
}