Compare commits
No commits in common. "f4dca25c28135abd9284cfce5ecfdeda8f0018ae" and "3e29615db9ac072029557b031ee814f820e49791" have entirely different histories.
f4dca25c28
...
3e29615db9
34 changed files with 1219 additions and 718 deletions
21
flake.lock
generated
21
flake.lock
generated
|
|
@ -185,30 +185,9 @@
|
|||
"microvm": "microvm",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nt": "nt",
|
||||
"sops-nix": "sops-nix",
|
||||
"systems": "systems_3"
|
||||
}
|
||||
},
|
||||
"sops-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1773096132,
|
||||
"narHash": "sha256-M3zEnq9OElB7zqc+mjgPlByPm1O5t2fbUrH3t/Hm5Ag=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "d1ff3b1034d5bab5d7d8086a7803c5a5968cd784",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"spectrum": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
nt,
|
||||
...
|
||||
} @ inputs:
|
||||
import ./nix
|
||||
import ./cerulean
|
||||
{
|
||||
inherit inputs self nt;
|
||||
inherit (nt) mix;
|
||||
|
|
|
|||
|
|
@ -18,14 +18,15 @@
|
|||
} @ args: let
|
||||
inherit (nt) findImport;
|
||||
in
|
||||
mix.newMixture args (mixture: {
|
||||
mix.newMixture args (mixture: let
|
||||
inherit (mixture) mapNodes;
|
||||
in {
|
||||
includes = {
|
||||
private = [
|
||||
./lib/nodes.nix
|
||||
];
|
||||
public = [
|
||||
./flake
|
||||
./lib.nix
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,53 +4,33 @@
|
|||
systems,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(builtins)
|
||||
attrNames
|
||||
concatStringsSep
|
||||
filter
|
||||
length
|
||||
warn
|
||||
;
|
||||
|
||||
inherit (inputs.nixpkgs) lib;
|
||||
in {
|
||||
# snow.flake
|
||||
flake = flakeInputs: root: let
|
||||
snowflake = lib.evalModules {
|
||||
class = "snowflake";
|
||||
specialArgs = let
|
||||
reservedSpecialArgs = {
|
||||
inherit (this) snow;
|
||||
inherit systems root;
|
||||
inputs = flakeInputs;
|
||||
};
|
||||
|
||||
warnIfReserved = let
|
||||
getReservedNames = names:
|
||||
reservedSpecialArgs
|
||||
|> attrNames
|
||||
|> filter (name: names?${name});
|
||||
|
||||
reservedNames =
|
||||
flakeInputs
|
||||
|> attrNames
|
||||
|> getReservedNames;
|
||||
in
|
||||
(length reservedNames == 0)
|
||||
|| warn ''
|
||||
[snow] Your `flake.nix` declares inputs with reserved names!
|
||||
[snow] These will be accessible only via `inputs.''${NAME}`
|
||||
[snow] Please rename the following:
|
||||
[snow] ${concatStringsSep reservedNames ", "}
|
||||
''
|
||||
true;
|
||||
in
|
||||
assert warnIfReserved;
|
||||
flakeInputs // reservedSpecialArgs;
|
||||
# XXX: TODO: abort if inputs contains reserved names
|
||||
specialArgs =
|
||||
(flakeInputs
|
||||
// {
|
||||
inherit (this) snow;
|
||||
inherit systems root;
|
||||
inputs = flakeInputs;
|
||||
})
|
||||
# XXX: TODO:
|
||||
# |> (x: builtins.removeAttrs x ["self" "nodes"]);
|
||||
|> (x: builtins.removeAttrs x ["self"]);
|
||||
|
||||
modules = [
|
||||
./module.nix
|
||||
({config, ...}: {
|
||||
_module.args = {
|
||||
self = config;
|
||||
# XXX: TODO:
|
||||
# nodes = config.nodes.nodes;
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
in
|
||||
|
|
|
|||
318
nix/snow/flake/lib.nix.bak
Normal file
318
nix/snow/flake/lib.nix.bak
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
{ lib
|
||||
# Optionally a string with extra version info to be included in the error message
|
||||
# in case is lib is out of date. Empty or starts with space.
|
||||
, revInfo ? ""
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
mkOptionType
|
||||
defaultFunctor
|
||||
isAttrs
|
||||
isFunction
|
||||
showOption
|
||||
throwIf
|
||||
types
|
||||
warnIf
|
||||
getAttrFromPath
|
||||
setAttrByPath
|
||||
attrByPath
|
||||
optionalAttrs
|
||||
;
|
||||
inherit (lib.modules)
|
||||
mkAliasAndWrapDefsWithPriority;
|
||||
inherit (lib.types)
|
||||
path
|
||||
submoduleWith
|
||||
;
|
||||
|
||||
# Polyfill isFlake until Nix with https://github.com/NixOS/nix/pull/7207 is common
|
||||
isFlake = maybeFlake:
|
||||
if maybeFlake ? _type
|
||||
then maybeFlake._type == "flake"
|
||||
else maybeFlake ? inputs && maybeFlake ? outputs && maybeFlake ? sourceInfo;
|
||||
|
||||
/**
|
||||
Deprecated for any use except type-merging into `perSystem`.
|
||||
Use `lib.types.deferredModuleWith` instead, and add `apply = m: [ m ];` if needed.
|
||||
|
||||
The deferredModule type was pioneered in flake-parts for the `perSystem` option.
|
||||
The Nixpkgs version has an improved merge function that returns a single module,
|
||||
whereas this version returns a list. The flake-parts version was not updated to
|
||||
match this improvement in Nixpkgs.
|
||||
|
||||
# History
|
||||
|
||||
This predates `lib.types.deferredModuleWith`, added in Nixpkgs 22.11
|
||||
(https://github.com/NixOS/nixpkgs/pull/163617).
|
||||
Documented as deprecated in flake-parts in January 2026.
|
||||
*/
|
||||
deferredModuleWith =
|
||||
attrs@{ staticModules ? [ ] }: mkOptionType {
|
||||
name = "deferredModule";
|
||||
description = "module";
|
||||
check = x: isAttrs x || isFunction x || path.check x;
|
||||
merge = loc: defs: staticModules ++ map (def: lib.setDefaultModuleLocation "${def.file}, via option ${showOption loc}" def.value) defs;
|
||||
inherit (submoduleWith { modules = staticModules; })
|
||||
getSubOptions
|
||||
getSubModules;
|
||||
substSubModules = m: deferredModuleWith (attrs // {
|
||||
staticModules = m;
|
||||
});
|
||||
functor = defaultFunctor "deferredModuleWith" // {
|
||||
type = deferredModuleWith;
|
||||
payload = {
|
||||
inherit staticModules;
|
||||
};
|
||||
binOp = lhs: rhs: {
|
||||
staticModules = lhs.staticModules ++ rhs.staticModules;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Internal: preserves legacy list-merge behavior for perSystem type-merging.
|
||||
mkLegacyDeferredModuleType =
|
||||
module:
|
||||
deferredModuleWith {
|
||||
staticModules = [ module ];
|
||||
};
|
||||
|
||||
errorExample = ''
|
||||
For example:
|
||||
|
||||
outputs = inputs@{ flake-parts, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } { /* module */ };
|
||||
|
||||
To avoid an infinite recursion, *DO NOT* pass `self.inputs` and
|
||||
*DO NOT* pass `inherit (self) inputs`, but pass the output function
|
||||
arguments as `inputs` like above.
|
||||
'';
|
||||
|
||||
flake-parts-lib = rec {
|
||||
evalFlakeModule =
|
||||
args@
|
||||
{ inputs ? self.inputs
|
||||
, specialArgs ? { }
|
||||
|
||||
# legacy
|
||||
, self ? inputs.self or (throw ''
|
||||
When invoking flake-parts, you must pass all the flake output arguments,
|
||||
and not just `self.inputs`.
|
||||
|
||||
${errorExample}
|
||||
'')
|
||||
, moduleLocation ? "${self.outPath}/flake.nix"
|
||||
}:
|
||||
let
|
||||
inputsPos = builtins.unsafeGetAttrPos "inputs" args;
|
||||
errorLocation =
|
||||
# Best case: user makes it explicit
|
||||
args.moduleLocation or (
|
||||
# Slightly worse: Nix does not technically commit to unsafeGetAttrPos semantics
|
||||
if inputsPos != null
|
||||
then inputsPos.file
|
||||
# Slightly worse: self may not be valid when an error occurs
|
||||
else if args?inputs.self.outPath
|
||||
then args.inputs.self.outPath + "/flake.nix"
|
||||
# Fallback
|
||||
else "<mkFlake argument>"
|
||||
);
|
||||
in
|
||||
throwIf
|
||||
(!args?self && !args?inputs) ''
|
||||
When invoking flake-parts, you must pass in the flake output arguments.
|
||||
|
||||
${errorExample}
|
||||
''
|
||||
warnIf
|
||||
(!args?inputs) ''
|
||||
When invoking flake-parts, it is recommended to pass all the flake output
|
||||
arguments in the `inputs` parameter. If you only pass `self`, it's not
|
||||
possible to use the `inputs` module argument in the module `imports`.
|
||||
|
||||
Please pass the output function arguments. ${errorExample}
|
||||
''
|
||||
|
||||
(module:
|
||||
lib.evalModules {
|
||||
specialArgs = {
|
||||
inherit self flake-parts-lib moduleLocation;
|
||||
inputs = args.inputs or /* legacy, warned above */ self.inputs;
|
||||
} // specialArgs;
|
||||
modules = [ ./all-modules.nix (lib.setDefaultModuleLocation errorLocation module) ];
|
||||
class = "flake";
|
||||
}
|
||||
);
|
||||
|
||||
# Function to extract the default flakeModule from
|
||||
# what may be a flake, returning the argument unmodified
|
||||
# if it's not a flake.
|
||||
#
|
||||
# Useful to map over an 'imports' list to make it less
|
||||
# verbose in the common case.
|
||||
defaultModule = maybeFlake:
|
||||
if isFlake maybeFlake
|
||||
then maybeFlake.flakeModules.default or maybeFlake
|
||||
else maybeFlake;
|
||||
|
||||
mkFlake = args: module:
|
||||
let
|
||||
eval = flake-parts-lib.evalFlakeModule args module;
|
||||
in
|
||||
eval.config.flake;
|
||||
|
||||
/**
|
||||
Deprecated. Declare options directly, e.g. `options.foo.bar = mkOption { ... }`,
|
||||
provided that `foo` is already declared as a submodule option.
|
||||
|
||||
In flake-parts, `flake` is declared as a submodule option by the core modules,
|
||||
so `options.flake.<name>` declarations work directly.
|
||||
|
||||
This function wraps option declarations in a submodule, allowing them to
|
||||
be merged into an existing submodule option. For example, if `foo` is
|
||||
already declared as a submodule option, using
|
||||
`options.foo = mkSubmoduleOptions { bar = mkOption {...}; }` would add
|
||||
`bar` to the `foo` submodule.
|
||||
|
||||
# History
|
||||
|
||||
This was a workaround for https://github.com/NixOS/nixpkgs/issues/146882,
|
||||
fixed in Nixpkgs 22.05 by https://github.com/NixOS/nixpkgs/pull/156533.
|
||||
With the fix, declaring `options.foo.bar` directly works when `foo` is
|
||||
already a submodule option. Documented as deprecated in flake-parts in January 2026.
|
||||
*/
|
||||
mkSubmoduleOptions =
|
||||
options:
|
||||
mkOption {
|
||||
type = types.submoduleWith {
|
||||
modules = [{ inherit options; }];
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
Deprecated. Use mkPerSystemType/mkPerSystemOption for `perSystem` type-merging, or
|
||||
use Nixpkgs `types.deferredModule` directly, noting the lack of list wrapping;
|
||||
see `deferredModuleWith` docs.
|
||||
*/
|
||||
mkDeferredModuleType = mkLegacyDeferredModuleType;
|
||||
|
||||
/**
|
||||
Given a module, construct an option type suitable for type-merging into `perSystem`'s type.
|
||||
*/
|
||||
mkPerSystemType = mkLegacyDeferredModuleType;
|
||||
|
||||
/**
|
||||
Deprecated. Use mkPerSystemOption for `perSystem` type-merging, or
|
||||
use `mkOption` and Nixpkgs `types.deferredModule` directly, noting the
|
||||
lack of list wrapping; see `deferredModuleWith` docs.
|
||||
*/
|
||||
mkDeferredModuleOption =
|
||||
module:
|
||||
mkOption {
|
||||
type = flake-parts-lib.mkPerSystemType module;
|
||||
};
|
||||
|
||||
/**
|
||||
Given a module, construct an option declaration suitable for merging into the core `perSystem` module.
|
||||
*/
|
||||
mkPerSystemOption = mkDeferredModuleOption;
|
||||
|
||||
# Polyfill https://github.com/NixOS/nixpkgs/pull/344216
|
||||
# Nixpkgs master 2024-12-09, Nixpkgs 25.05
|
||||
attrsWith = types.attrsWith or ({ elemType, lazy ? false, placeholder ? "name" }:
|
||||
if lazy then types.attrsOf elemType else types.lazyAttrsOf elemType);
|
||||
|
||||
# Helper function for defining a per-system option that
|
||||
# gets transposed by the usual flake system logic to a
|
||||
# top-level flake attribute.
|
||||
mkTransposedPerSystemModule = { name, option, file }: {
|
||||
_file = file;
|
||||
|
||||
options = {
|
||||
flake.${name} = mkOption {
|
||||
type = attrsWith {
|
||||
elemType = option.type;
|
||||
lazy = true;
|
||||
placeholder = "system";
|
||||
};
|
||||
default = { };
|
||||
description = ''
|
||||
See {option}`perSystem.${name}` for description and examples.
|
||||
'';
|
||||
};
|
||||
|
||||
perSystem = flake-parts-lib.mkPerSystemOption {
|
||||
_file = file;
|
||||
|
||||
options.${name} = option;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
transposition.${name} = { };
|
||||
};
|
||||
};
|
||||
|
||||
# Needed pending https://github.com/NixOS/nixpkgs/pull/198450
|
||||
mkAliasOptionModule = from: to: { config, options, ... }:
|
||||
let
|
||||
fromOpt = getAttrFromPath from options;
|
||||
toOf = attrByPath to
|
||||
(abort "Renaming error: option `${showOption to}' does not exist.");
|
||||
toType = let opt = attrByPath to { } options; in opt.type or (types.submodule { });
|
||||
in
|
||||
{
|
||||
options = setAttrByPath from (mkOption
|
||||
{
|
||||
visible = true;
|
||||
description = "Alias of {option}`${showOption to}`.";
|
||||
apply = x: (toOf config);
|
||||
} // optionalAttrs (toType != null) {
|
||||
type = toType;
|
||||
});
|
||||
config = mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt;
|
||||
};
|
||||
|
||||
# Helper function for importing while preserving module location. To be added
|
||||
# in nixpkgs: https://github.com/NixOS/nixpkgs/pull/230588
|
||||
# I expect these functions to remain identical. This one will stick around
|
||||
# for a while to support older nixpkgs-lib.
|
||||
importApply =
|
||||
modulePath: staticArgs:
|
||||
lib.setDefaultModuleLocation modulePath (import modulePath staticArgs);
|
||||
|
||||
inherit (import ./lib/memoize/memoize.nix {
|
||||
inherit lib;
|
||||
}) memoizeStr;
|
||||
|
||||
/**
|
||||
`importAndPublish name module` returns a module that both imports the `module`, and exposes it as flake attribute `modules.flake.${name}`.
|
||||
|
||||
This also imports the optional [`modules`](https://flake.parts/options/flake-parts-modules.html) module to support that.
|
||||
*/
|
||||
importAndPublish = name: module: { lib, ... }: {
|
||||
_class = "flake";
|
||||
imports = [
|
||||
module
|
||||
./extras/modules.nix
|
||||
];
|
||||
flake.modules.flake.${name} = module;
|
||||
};
|
||||
};
|
||||
|
||||
# A best effort, lenient estimate. Please use a recent nixpkgs lib if you
|
||||
# override it at all.
|
||||
minVersion = "23.05pre-git";
|
||||
|
||||
in
|
||||
|
||||
if builtins.compareVersions lib.version minVersion < 0
|
||||
then
|
||||
abort ''
|
||||
The nixpkgs-lib dependency of flake-parts was overridden but is too old.
|
||||
The minimum supported version of nixpkgs-lib is ${minVersion},
|
||||
but the actual version is ${lib.version}${revInfo}.
|
||||
''
|
||||
else
|
||||
|
||||
flake-parts-lib
|
||||
|
|
@ -18,7 +18,6 @@
|
|||
}: {
|
||||
imports = [
|
||||
./nodes
|
||||
./modules
|
||||
(snow.findImport /${root}/snow)
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
# Snow Module Backend
|
||||
This source code was tedious so it's just a modified version of the module backend of
|
||||
[github:hercules-ci/flake-parts](https://github.com/hercules-ci/flake-parts/tree/main/modules).
|
||||
|
|
@ -1,31 +1,23 @@
|
|||
{
|
||||
lib,
|
||||
snow,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
{ lib, flake-parts-lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
|
||||
inherit
|
||||
(snow)
|
||||
mkPerSystemFlakeOutput
|
||||
inherit (flake-parts-lib)
|
||||
mkTransposedPerSystemModule
|
||||
;
|
||||
|
||||
derivationType =
|
||||
lib.types.package
|
||||
// {
|
||||
check = lib.isDerivation;
|
||||
};
|
||||
|
||||
programType = lib.types.coercedTo derivationType lib.getExe lib.types.str;
|
||||
|
||||
derivationType = lib.types.package // {
|
||||
check = lib.isDerivation;
|
||||
};
|
||||
|
||||
appType = lib.types.submodule {
|
||||
options = {
|
||||
type = mkOption {
|
||||
type = lib.types.enum ["app"];
|
||||
type = lib.types.enum [ "app" ];
|
||||
default = "app";
|
||||
description = ''
|
||||
A type tag for `apps` consumers.
|
||||
|
|
@ -39,7 +31,7 @@
|
|||
};
|
||||
meta = mkOption {
|
||||
type = types.lazyAttrsOf lib.types.raw;
|
||||
default = {};
|
||||
default = { };
|
||||
# TODO refer to Nix manual 2.25
|
||||
description = ''
|
||||
Metadata information about the app.
|
||||
|
|
@ -51,19 +43,19 @@
|
|||
};
|
||||
};
|
||||
in
|
||||
mkPerSystemFlakeOutput {
|
||||
name = "apps";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf appType;
|
||||
default = {};
|
||||
description = ''
|
||||
Programs runnable with nix run `<name>`.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
default.program = "''${config.packages.hello}/bin/hello";
|
||||
}
|
||||
'';
|
||||
};
|
||||
file = ./apps.nix;
|
||||
}
|
||||
mkTransposedPerSystemModule {
|
||||
name = "apps";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf appType;
|
||||
default = { };
|
||||
description = ''
|
||||
Programs runnable with nix run `<name>`.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
default.program = "''${config.packages.hello}/bin/hello";
|
||||
}
|
||||
'';
|
||||
};
|
||||
file = ./apps.nix;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,21 @@
|
|||
{
|
||||
lib,
|
||||
snow,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
{ lib, flake-parts-lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
inherit
|
||||
(snow)
|
||||
mkPerSystemFlakeOutput
|
||||
inherit (flake-parts-lib)
|
||||
mkTransposedPerSystemModule
|
||||
;
|
||||
in
|
||||
mkPerSystemFlakeOutput {
|
||||
name = "checks";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf types.package;
|
||||
default = {};
|
||||
description = ''
|
||||
Derivations to be built by [`nix flake check`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake-check.html).
|
||||
'';
|
||||
};
|
||||
file = ./checks.nix;
|
||||
}
|
||||
mkTransposedPerSystemModule {
|
||||
name = "checks";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf types.package;
|
||||
default = { };
|
||||
description = ''
|
||||
Derivations to be built by [`nix flake check`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake-check.html).
|
||||
'';
|
||||
};
|
||||
file = ./checks.nix;
|
||||
}
|
||||
|
|
|
|||
78
nix/snow/flake/modules/debug.nix
Normal file
78
nix/snow/flake/modules/debug.nix
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
{ config, flake-parts-lib, lib, options, getSystem, extendModules, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mapAttrs
|
||||
mkIf
|
||||
mkOption
|
||||
optionalAttrs
|
||||
types
|
||||
;
|
||||
inherit (flake-parts-lib)
|
||||
mkPerSystemOption
|
||||
;
|
||||
|
||||
mkDebugConfig = { config, options, extendModules }: config // {
|
||||
inherit config;
|
||||
inherit (config) _module;
|
||||
inherit options;
|
||||
inherit extendModules;
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
debug = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to add the attributes `debug`, `allSystems` and `currentSystem`
|
||||
to the flake output. When `true`, this allows inspection of options via
|
||||
`nix repl`.
|
||||
|
||||
```
|
||||
$ nix repl
|
||||
nix-repl> :lf .
|
||||
nix-repl> currentSystem._module.args.pkgs.hello
|
||||
«derivation /nix/store/7vf0d0j7majv1ch1xymdylyql80cn5fp-hello-2.12.1.drv»
|
||||
```
|
||||
|
||||
Each of `debug`, `allSystems.<system>` and `currentSystem` is an
|
||||
attribute set consisting of the `config` attributes, plus the extra
|
||||
attributes `_module`, `config`, `options`, `extendModules`. So note that
|
||||
these are not part of the `config` parameter, but are merged in for
|
||||
debugging convenience.
|
||||
|
||||
- `debug`: The top-level options
|
||||
- `allSystems`: The `perSystem` submodule applied to the configured `systems`.
|
||||
- `currentSystem`: Shortcut into `allSystems`. Only available in impure mode.
|
||||
Works for arbitrary system values.
|
||||
|
||||
See [Expore and debug option values](../debug.html) for more examples.
|
||||
'';
|
||||
};
|
||||
perSystem = mkPerSystemOption
|
||||
({ options, config, extendModules, ... }: {
|
||||
_file = ./formatter.nix;
|
||||
options = {
|
||||
debug = mkOption {
|
||||
description = ''
|
||||
Values to return in e.g. `allSystems.<system>` when
|
||||
[`debug = true`](#opt-debug).
|
||||
'';
|
||||
type = types.lazyAttrsOf types.raw;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
debug = mkDebugConfig { inherit config options extendModules; };
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
config = mkIf config.debug {
|
||||
flake = {
|
||||
debug = mkDebugConfig { inherit config options extendModules; };
|
||||
allSystems = mapAttrs (_s: c: c.debug) config.allSystems;
|
||||
} // optionalAttrs (builtins?currentSystem) {
|
||||
currentSystem = (getSystem builtins.currentSystem).debug;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
{...}: {
|
||||
imports = [
|
||||
./outputs.nix
|
||||
|
||||
./apps.nix
|
||||
./checks.nix
|
||||
./devShells.nix
|
||||
./formatter.nix
|
||||
./legacyPackages.nix
|
||||
./nixosConfigurations.nix
|
||||
./nixosModules.nix
|
||||
./overlays.nix
|
||||
./packages.nix
|
||||
];
|
||||
}
|
||||
|
|
@ -1,35 +1,30 @@
|
|||
{
|
||||
lib,
|
||||
snow,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
{ lib, flake-parts-lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
literalExpression
|
||||
;
|
||||
inherit
|
||||
(snow)
|
||||
mkPerSystemFlakeOutput
|
||||
inherit (flake-parts-lib)
|
||||
mkTransposedPerSystemModule
|
||||
;
|
||||
in
|
||||
mkPerSystemFlakeOutput {
|
||||
name = "devShells";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf types.package;
|
||||
default = {};
|
||||
description = ''
|
||||
An attribute set of packages to be used as shells.
|
||||
[`nix develop .#<name>`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop.html) will run `devShells.<name>`.
|
||||
'';
|
||||
example = literalExpression ''
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs; [ wget bat cargo ];
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
file = ./devShells.nix;
|
||||
}
|
||||
mkTransposedPerSystemModule {
|
||||
name = "devShells";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf types.package;
|
||||
default = { };
|
||||
description = ''
|
||||
An attribute set of packages to be used as shells.
|
||||
[`nix develop .#<name>`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop.html) will run `devShells.<name>`.
|
||||
'';
|
||||
example = literalExpression ''
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs; [ wget bat cargo ];
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
file = ./devShells.nix;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
types
|
||||
;
|
||||
|
||||
outputs = mkOption {
|
||||
flake = mkOption {
|
||||
type = types.submoduleWith {
|
||||
modules = [
|
||||
{
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
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
|
||||
Many modules are listed at https://flake.parts
|
||||
- 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
|
||||
|
|
@ -38,7 +39,8 @@
|
|||
};
|
||||
in {
|
||||
options = {
|
||||
inherit outputs;
|
||||
inherit flake;
|
||||
output = {inherit flake;};
|
||||
};
|
||||
|
||||
config = {inherit (config) flake;};
|
||||
|
|
@ -1,26 +1,52 @@
|
|||
{
|
||||
lib,
|
||||
snow,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
{ config, lib, flake-parts-lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
filterAttrs
|
||||
mapAttrs
|
||||
mkOption
|
||||
optionalAttrs
|
||||
types
|
||||
;
|
||||
inherit
|
||||
(snow)
|
||||
mkPerSystemFlakeOutput
|
||||
inherit (flake-parts-lib)
|
||||
mkPerSystemOption
|
||||
;
|
||||
in
|
||||
mkPerSystemFlakeOutput {
|
||||
name = "formatter";
|
||||
option = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
default = null;
|
||||
{
|
||||
options = {
|
||||
flake.formatter = mkOption {
|
||||
type = types.lazyAttrsOf types.package;
|
||||
default = { };
|
||||
description = ''
|
||||
A package used by [`nix fmt`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html).
|
||||
An attribute set of per system a package used by [`nix fmt`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html).
|
||||
'';
|
||||
};
|
||||
file = ./apps.nix;
|
||||
}
|
||||
|
||||
perSystem = mkPerSystemOption {
|
||||
_file = ./formatter.nix;
|
||||
options = {
|
||||
formatter = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
default = null;
|
||||
description = ''
|
||||
A package used by [`nix fmt`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html).
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
flake.formatter =
|
||||
mapAttrs
|
||||
(k: v: v.formatter)
|
||||
(filterAttrs
|
||||
(k: v: v.formatter != null)
|
||||
config.allSystems
|
||||
);
|
||||
|
||||
perInput = system: flake:
|
||||
optionalAttrs (flake?formatter.${system}) {
|
||||
formatter = flake.formatter.${system};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,21 @@
|
|||
{
|
||||
lib,
|
||||
snow,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
{ lib, flake-parts-lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
inherit
|
||||
(snow)
|
||||
mkPerSystemFlakeOutput
|
||||
inherit (flake-parts-lib)
|
||||
mkTransposedPerSystemModule
|
||||
;
|
||||
in
|
||||
mkPerSystemFlakeOutput {
|
||||
name = "legacyPackages";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf types.raw;
|
||||
default = {};
|
||||
description = ''
|
||||
Used for nixpkgs packages, also accessible via `nix build .#<name>` [`nix build .#<name>`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-build.html).
|
||||
'';
|
||||
};
|
||||
file = ./legacyPackages.nix;
|
||||
}
|
||||
mkTransposedPerSystemModule {
|
||||
name = "legacyPackages";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf types.raw;
|
||||
default = { };
|
||||
description = ''
|
||||
An attribute set of unmergeable values. This is also used by [`nix build .#<attrpath>`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-build.html).
|
||||
'';
|
||||
};
|
||||
file = ./legacyPackages.nix;
|
||||
}
|
||||
|
|
|
|||
32
nix/snow/flake/modules/moduleWithSystem.nix
Normal file
32
nix/snow/flake/modules/moduleWithSystem.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{ withSystem, ... }:
|
||||
{
|
||||
config = {
|
||||
_module.args = {
|
||||
moduleWithSystem =
|
||||
module:
|
||||
|
||||
{ config, ... }:
|
||||
let
|
||||
system =
|
||||
config._module.args.system or
|
||||
config._module.args.pkgs.stdenv.hostPlatform.system or
|
||||
(throw "moduleWithSystem: Could not determine the configuration's system parameter for this module system application.");
|
||||
|
||||
allArgs = withSystem system (args: args);
|
||||
|
||||
lazyArgsPerParameter = f: builtins.mapAttrs
|
||||
(k: v: allArgs.${k} or (throw "moduleWithSystem: module argument `${k}` does not exist."))
|
||||
(builtins.functionArgs f);
|
||||
|
||||
# Use reflection to make the call lazy in the argument.
|
||||
# Restricts args to the ones declared.
|
||||
callLazily = f: a: f (lazyArgsPerParameter f);
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(callLazily module allArgs)
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
{lib, ...}: let
|
||||
inherit
|
||||
(lib)
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
literalExpression
|
||||
;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
outputs.nixosConfigurations = mkOption {
|
||||
flake.nixosConfigurations = mkOption {
|
||||
type = types.lazyAttrsOf types.raw;
|
||||
default = {};
|
||||
default = { };
|
||||
description = ''
|
||||
Instantiated NixOS configurations. Used by `nixos-rebuild`.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
{
|
||||
lib,
|
||||
moduleLocation,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
{ self, lib, moduleLocation, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mapAttrs
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
outputs.nixosModules = mkOption {
|
||||
flake.nixosModules = mkOption {
|
||||
type = types.lazyAttrsOf types.deferredModule;
|
||||
default = {};
|
||||
default = { };
|
||||
apply = mapAttrs (k: v: {
|
||||
_class = "nixos";
|
||||
_file = "${toString moduleLocation}#nixosModules.${k}";
|
||||
imports = [v];
|
||||
imports = [ v ];
|
||||
});
|
||||
description = ''
|
||||
NixOS modules.
|
||||
|
|
|
|||
26
nix/snow/flake/modules/nixpkgs.nix
Normal file
26
nix/snow/flake/modules/nixpkgs.nix
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
# Nixpkgs module. The only exception to the rule.
|
||||
#
|
||||
# Provides a `pkgs` argument in `perSystem`.
|
||||
#
|
||||
# Arguably, this shouldn't be in flake-parts, but in nixpkgs.
|
||||
# Nixpkgs could define its own module that does this, which would be
|
||||
# a more consistent UX, but for now this will do.
|
||||
#
|
||||
# The existence of this module does not mean that other flakes' logic
|
||||
# will be accepted into flake-parts, because it's against the
|
||||
# spirit of Flakes.
|
||||
#
|
||||
{
|
||||
config = {
|
||||
perSystem = { inputs', lib, ... }: {
|
||||
config = {
|
||||
_module.args.pkgs = lib.mkOptionDefault (
|
||||
builtins.seq
|
||||
(inputs'.nixpkgs or (throw "flake-parts: The flake does not have a `nixpkgs` input. Please add it, or set `perSystem._module.args.pkgs` yourself."))
|
||||
inputs'.nixpkgs.legacyPackages
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,18 +1,19 @@
|
|||
{lib, ...}: let
|
||||
inherit
|
||||
(lib)
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
outputs.overlays = mkOption {
|
||||
flake.overlays = mkOption {
|
||||
# uniq -> ordered: https://github.com/NixOS/nixpkgs/issues/147052
|
||||
# also update description when done
|
||||
type = types.lazyAttrsOf (types.uniq (types.functionTo (types.functionTo (types.lazyAttrsOf types.unspecified))));
|
||||
# This eta expansion exists for the sole purpose of making nix flake check happy.
|
||||
apply = lib.mapAttrs (_k: f: final: prev: f final prev);
|
||||
default = {};
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
default = final: prev: {};
|
||||
|
|
|
|||
|
|
@ -1,29 +1,23 @@
|
|||
{
|
||||
lib,
|
||||
snow,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
{ lib, flake-parts-lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
|
||||
inherit
|
||||
(snow)
|
||||
mkPerSystemFlakeOutput
|
||||
inherit (flake-parts-lib)
|
||||
mkTransposedPerSystemModule
|
||||
;
|
||||
in
|
||||
mkPerSystemFlakeOutput {
|
||||
name = "packages";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf types.package;
|
||||
default = {};
|
||||
description = ''
|
||||
An attribute set of packages to be built by [`nix build`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-build.html).
|
||||
mkTransposedPerSystemModule {
|
||||
name = "packages";
|
||||
option = mkOption {
|
||||
type = types.lazyAttrsOf types.package;
|
||||
default = { };
|
||||
description = ''
|
||||
An attribute set of packages to be built by [`nix build`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-build.html).
|
||||
|
||||
`nix build .#<name>` will build `packages.<name>`.
|
||||
'';
|
||||
};
|
||||
file = ./packages.nix;
|
||||
}
|
||||
`nix build .#<name>` will build `packages.<name>`.
|
||||
'';
|
||||
};
|
||||
file = ./packages.nix;
|
||||
}
|
||||
|
|
|
|||
159
nix/snow/flake/modules/perSystem.nix
Normal file
159
nix/snow/flake/modules/perSystem.nix
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
{ config, lib, flake-parts-lib, self, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
genAttrs
|
||||
mapAttrs
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
inherit (lib.strings)
|
||||
escapeNixIdentifier
|
||||
;
|
||||
inherit (flake-parts-lib)
|
||||
mkPerSystemType
|
||||
;
|
||||
|
||||
rootConfig = config;
|
||||
|
||||
# Stubs for self and inputs. While it'd be possible to define aliases
|
||||
# inside perSystem, that is not a general solution, and it would make
|
||||
# top.config harder to discover, stretching the learning curve rather
|
||||
# than flattening it.
|
||||
|
||||
throwAliasError' = param:
|
||||
throw ''
|
||||
`${param}` (without `'`) is not a `perSystem` module argument, but a
|
||||
module argument of the top level config.
|
||||
|
||||
The following is an example usage of `${param}`. Note that its binding
|
||||
is in the `top` parameter list, which is declared by the top level module
|
||||
rather than the `perSystem` module.
|
||||
|
||||
top@{ config, lib, ${param}, ... }: {
|
||||
perSystem = { config, ${param}', ... }: {
|
||||
# in scope here:
|
||||
# - ${param}
|
||||
# - ${param}'
|
||||
# - config (of perSystem)
|
||||
# - top.config (note the `top@` pattern)
|
||||
};
|
||||
}
|
||||
'';
|
||||
|
||||
throwAliasError = param:
|
||||
throw ''
|
||||
`${param}` is not a `perSystem` module argument, but a module argument of
|
||||
the top level config.
|
||||
|
||||
The following is an example usage of `${param}`. Note that its binding
|
||||
is in the `top` parameter list, which is declared by the top level module
|
||||
rather than the `perSystem` module.
|
||||
|
||||
top@{ config, lib, ${param}, ... }: {
|
||||
perSystem = { config, ... }: {
|
||||
# in scope here:
|
||||
# - ${param}
|
||||
# - config (of perSystem)
|
||||
# - top.config (note the `top@` pattern)
|
||||
};
|
||||
}
|
||||
'';
|
||||
|
||||
/**
|
||||
We primarily use `systems` to help memoize the per system context, but that
|
||||
doesn't extend to arbitrary `system`s.
|
||||
For that, we use the slightly less efficient, but perfectly acceptable
|
||||
`memoizeStr` function.
|
||||
*/
|
||||
otherMemoizedSystems = flake-parts-lib.memoizeStr config.perSystem;
|
||||
|
||||
in
|
||||
{
|
||||
options = {
|
||||
systems = mkOption {
|
||||
description = ''
|
||||
All the system types to enumerate in the flake output subattributes.
|
||||
|
||||
In other words, all valid values for `system` in e.g. `packages.<system>.foo`.
|
||||
'';
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
|
||||
perInput = mkOption {
|
||||
description = ''
|
||||
A function that pre-processes flake inputs.
|
||||
|
||||
It is called for users of `perSystem` such that `inputs'.''${name} = config.perInput system inputs.''${name}`.
|
||||
|
||||
This is used for [`inputs'`](../module-arguments.html#inputs) and [`self'`](../module-arguments.html#self).
|
||||
|
||||
The attributes returned by the `perInput` function definitions are merged into a single namespace (per input),
|
||||
so each module should return an attribute set with usually only one or two predictable attribute names. Otherwise,
|
||||
the `inputs'` namespace gets polluted.
|
||||
'';
|
||||
type = types.functionTo (types.functionTo (types.lazyAttrsOf types.unspecified));
|
||||
};
|
||||
|
||||
perSystem = mkOption {
|
||||
description = ''
|
||||
A function from system to flake-like attributes omitting the `<system>` attribute.
|
||||
|
||||
Modules defined here have access to the suboptions and [some convenient module arguments](../module-arguments.html).
|
||||
'';
|
||||
type = mkPerSystemType ({ config, system, ... }: {
|
||||
_file = ./perSystem.nix;
|
||||
config = {
|
||||
_module.args.inputs' =
|
||||
mapAttrs
|
||||
(inputName: input:
|
||||
builtins.addErrorContext "while retrieving system-dependent attributes for input ${escapeNixIdentifier inputName}" (
|
||||
if input._type or null == "flake"
|
||||
then rootConfig.perInput system input
|
||||
else
|
||||
throw "Trying to retrieve system-dependent attributes for input ${escapeNixIdentifier inputName}, but this input is not a flake. Perhaps flake = false was added to the input declarations by mistake, or you meant to use a different input, or you meant to use plain old inputs, not inputs'."
|
||||
)
|
||||
)
|
||||
self.inputs;
|
||||
_module.args.self' =
|
||||
builtins.addErrorContext "while retrieving system-dependent attributes for a flake's own outputs" (
|
||||
rootConfig.perInput system self
|
||||
);
|
||||
|
||||
# Custom error messages
|
||||
_module.args.self = throwAliasError' "self";
|
||||
_module.args.inputs = throwAliasError' "inputs";
|
||||
_module.args.getSystem = throwAliasError "getSystem";
|
||||
_module.args.withSystem = throwAliasError "withSystem";
|
||||
_module.args.moduleWithSystem = throwAliasError "moduleWithSystem";
|
||||
};
|
||||
});
|
||||
apply = modules: system:
|
||||
(lib.evalModules {
|
||||
inherit modules;
|
||||
prefix = [ "perSystem" system ];
|
||||
specialArgs = {
|
||||
inherit system;
|
||||
};
|
||||
class = "perSystem";
|
||||
}).config;
|
||||
};
|
||||
|
||||
allSystems = mkOption {
|
||||
type = types.lazyAttrsOf types.unspecified;
|
||||
description = "The system-specific config for each of systems.";
|
||||
internal = true;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
allSystems = genAttrs config.systems config.perSystem;
|
||||
_module.args.getSystem = system: config.allSystems.${system} or (otherMemoizedSystems system);
|
||||
|
||||
# The warning is there for a reason. Only use this in situations where the
|
||||
# performance cost has already been incurred, such as in `flakeModules.easyOverlay`,
|
||||
# where we run in the context of an overlay, and the performance cost of the
|
||||
# extra `pkgs` makes the cost of running `perSystem` probably negligible.
|
||||
_module.args.getSystemIgnoreWarning = system: config.allSystems.${system} or (config.perSystem system);
|
||||
};
|
||||
|
||||
}
|
||||
132
nix/snow/flake/modules/transposition.nix
Normal file
132
nix/snow/flake/modules/transposition.nix
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
{ config, lib, flake-parts-lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
filterAttrs
|
||||
mapAttrs
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
inherit (lib.strings)
|
||||
escapeNixIdentifier
|
||||
;
|
||||
|
||||
transpositionModule = {
|
||||
options = {
|
||||
adHoc = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to provide a stub option declaration for {option}`perSystem.<name>`.
|
||||
|
||||
The stub option declaration does not support merging and lacks
|
||||
documentation, so you are recommended to declare the {option}`perSystem.<name>`
|
||||
option yourself and avoid {option}`adHoc`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
perInputAttributeError = { flake, attrName, system, attrConfig }:
|
||||
# This uses flake.outPath for lack of a better identifier.
|
||||
# Consider adding a perInput variation that has a normally-redundant argument for the input name.
|
||||
# Tested manually with
|
||||
# perSystem = { inputs', ... }: {
|
||||
# packages.extra = inputs'.nixpkgs.extra;
|
||||
# packages.default = inputs'.nixpkgs.packages.default;
|
||||
# packages.veryWrong = (top.config.perInput "x86_64-linux" inputs'.nixpkgs.legacyPackages.hello).packages.default;
|
||||
# };
|
||||
# transposition.extra = {};
|
||||
let
|
||||
attrPath = "${escapeNixIdentifier attrName}.${escapeNixIdentifier system}";
|
||||
flakeIdentifier =
|
||||
if flake._type or null != "flake"
|
||||
then
|
||||
throw "An attempt was made to access attribute ${attrPath} on a value that's supposed to be a flake, but may not be a proper flake."
|
||||
else
|
||||
builtins.addErrorContext "while trying to find out how to describe what is supposedly a flake, whose attribute ${attrPath} was accessed but does not exist" (
|
||||
toString flake.outPath
|
||||
);
|
||||
# This ought to be generalized by extending attrConfig, but this is the only known and common mistake for now.
|
||||
alternateAttrNameHint =
|
||||
if attrName == "packages" && flake?legacyPackages
|
||||
then # Unfortunately we can't just switch them out, because that will put packages *sets* where single packages are expected in user code, resulting in potentially much worse and more confusing errors down the line.
|
||||
"\nIt does define legacyPackages; try that instead?"
|
||||
else "";
|
||||
in
|
||||
if flake?${attrName}
|
||||
then
|
||||
throw ''
|
||||
Attempt to access ${attrPath} of flake ${flakeIdentifier}, but it does not have it.
|
||||
It does have attribute ${escapeNixIdentifier attrName}, so it appears that it does not support system type ${escapeNixIdentifier system}.
|
||||
''
|
||||
else
|
||||
throw ''
|
||||
Attempt to access ${attrPath} of flake ${flakeIdentifier}, but it does not have attribute ${escapeNixIdentifier attrName}.${alternateAttrNameHint}
|
||||
'';
|
||||
|
||||
|
||||
in
|
||||
{
|
||||
options = {
|
||||
transposition = lib.mkOption {
|
||||
description = ''
|
||||
A helper that defines transposed attributes in the flake outputs.
|
||||
|
||||
When you define `transposition.foo = { };`, definitions are added to the effect of (pseudo-code):
|
||||
|
||||
```nix
|
||||
flake.foo.''${system} = (perSystem system).foo;
|
||||
perInput = system: inputFlake: inputFlake.foo.''${system};
|
||||
```
|
||||
|
||||
Transposition is the operation that swaps the indices of a data structure.
|
||||
Here it refers specifically to the transposition between
|
||||
|
||||
```plain
|
||||
perSystem: .''${system}.''${attribute}
|
||||
outputs: .''${attribute}.''${system}
|
||||
```
|
||||
|
||||
It also defines the reverse operation in [{option}`perInput`](#opt-perInput).
|
||||
'';
|
||||
type =
|
||||
types.lazyAttrsOf
|
||||
(types.submoduleWith { modules = [ transpositionModule ]; });
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
flake =
|
||||
lib.mapAttrs
|
||||
(attrName: attrConfig:
|
||||
mapAttrs
|
||||
(system: v: v.${attrName} or (
|
||||
abort ''
|
||||
Could not find option ${attrName} in the perSystem module. It is required to declare such an option whenever transposition.<name> is defined (and in this instance <name> is ${attrName}).
|
||||
''))
|
||||
config.allSystems
|
||||
)
|
||||
config.transposition;
|
||||
|
||||
perInput =
|
||||
system: flake:
|
||||
mapAttrs
|
||||
(attrName: attrConfig:
|
||||
flake.${attrName}.${system} or (
|
||||
throw (perInputAttributeError { inherit system flake attrName attrConfig; })
|
||||
)
|
||||
)
|
||||
config.transposition;
|
||||
|
||||
perSystem = {
|
||||
options =
|
||||
mapAttrs
|
||||
(k: v: lib.mkOption { })
|
||||
(filterAttrs
|
||||
(k: v: v.adHoc)
|
||||
config.transposition
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
37
nix/snow/flake/modules/withSystem.nix
Normal file
37
nix/snow/flake/modules/withSystem.nix
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{ lib, flake-parts-lib, getSystem, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
inherit (flake-parts-lib)
|
||||
mkPerSystemOption
|
||||
;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
perSystem = mkPerSystemOption ({ config, options, specialArgs, ... }: {
|
||||
_file = ./perSystem.nix;
|
||||
options = {
|
||||
allModuleArgs = mkOption {
|
||||
type = types.lazyAttrsOf (types.raw or types.unspecified);
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
description = "Internal option that exposes _module.args, for use by withSystem.";
|
||||
};
|
||||
};
|
||||
config = {
|
||||
allModuleArgs = config._module.args // specialArgs // { inherit config options; };
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
config = {
|
||||
_module.args = {
|
||||
withSystem =
|
||||
system: f:
|
||||
f
|
||||
(getSystem system).allModuleArgs;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{
|
||||
_snow,
|
||||
lib,
|
||||
specialArgs,
|
||||
...
|
||||
|
|
@ -26,20 +25,38 @@
|
|||
in
|
||||
mkOption {
|
||||
description = ''
|
||||
Snowflake node declarations.
|
||||
Cerulean node declarations.
|
||||
'';
|
||||
type = types.submoduleWith {
|
||||
inherit specialArgs;
|
||||
|
||||
modules = [
|
||||
./nodes.nix
|
||||
{
|
||||
imports = [./shared.nix];
|
||||
|
||||
options = {
|
||||
groups = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = lib.literalExpression "{ servers = { staging = {}; production = {}; }; }";
|
||||
description = ''
|
||||
Hierarchical groups that nodes can be a member of.
|
||||
'';
|
||||
};
|
||||
|
||||
nodes = mkOption {
|
||||
type = types.attrsOf (types.submoduleWith {
|
||||
inherit specialArgs;
|
||||
modules = [(import ./submodule.nix)];
|
||||
});
|
||||
# example = { ... }; # TODO
|
||||
description = ''
|
||||
Node (host systems) declarations.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
nodes = {
|
||||
base = _snow.inputs.nixpkgs;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -11,13 +11,7 @@
|
|||
# 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.
|
||||
{
|
||||
_snow,
|
||||
lib,
|
||||
config,
|
||||
specialArgs,
|
||||
...
|
||||
}: let
|
||||
{lib, ...}: let
|
||||
inherit
|
||||
(lib)
|
||||
mkOption
|
||||
|
|
@ -25,8 +19,6 @@
|
|||
;
|
||||
|
||||
flakeRef = types.either types.str types.path;
|
||||
|
||||
groupLibs = import ./groups.nix {inherit (_snow.inputs) nt;};
|
||||
in {
|
||||
options = {
|
||||
base = lib.mkOption {
|
||||
|
|
@ -57,18 +49,6 @@ in {
|
|||
'';
|
||||
};
|
||||
|
||||
homeManager = mkOption {
|
||||
type = types.nullOr flakeRef;
|
||||
default = null;
|
||||
example = lib.literalExpression "inputs.home-manager";
|
||||
description = ''
|
||||
The path to the home-manager source. A `homeManager` flake reference
|
||||
is required to be set for `homes/` to be evaluated, and can be specified via either:
|
||||
1. `options.nodes.homeManager` (default `homManager` used for all systems)
|
||||
2. `options.nodes.nodes.<name>.homeManager` (takes prescedence over `options.nodes.homeManager`)
|
||||
'';
|
||||
};
|
||||
|
||||
modules = mkOption {
|
||||
type = types.listOf types.raw;
|
||||
default = [];
|
||||
|
|
@ -87,28 +67,15 @@ in {
|
|||
'';
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = lib.literalExpression "{ servers = { staging = {}; production = {}; }; }";
|
||||
homeManager = mkOption {
|
||||
type = types.nullOr flakeRef;
|
||||
default = null;
|
||||
example = lib.literalExpression "inputs.home-manager";
|
||||
description = ''
|
||||
Hierarchical groups that nodes can be a member of.
|
||||
'';
|
||||
|
||||
apply = groupLibs.parseGroupsDecl;
|
||||
};
|
||||
|
||||
nodes = mkOption {
|
||||
type = types.attrsOf (types.submoduleWith {
|
||||
specialArgs =
|
||||
specialArgs
|
||||
// {
|
||||
nodeConfig = config;
|
||||
};
|
||||
modules = [./node.nix];
|
||||
});
|
||||
description = ''
|
||||
Node (host systems) declarations.
|
||||
The path to the home-manager source. A `homeManager` flake reference
|
||||
is required to be set for `homes/` to be evaluated, and can be specified via either:
|
||||
1. `options.nodes.homeManager` (default `homManager` used for all systems)
|
||||
2. `options.nodes.nodes.<name>.homeManager` (takes prescedence over `options.nodes.homeManager`)
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
@ -14,18 +14,16 @@
|
|||
{
|
||||
lib,
|
||||
systems,
|
||||
config,
|
||||
nodesConfig,
|
||||
...
|
||||
}: {
|
||||
imports = [./shared.nix];
|
||||
|
||||
options = let
|
||||
inherit
|
||||
(lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
|
||||
flakeRef = types.either types.str types.path;
|
||||
in {
|
||||
enabled = lib.mkOption {
|
||||
type = types.bool;
|
||||
|
|
@ -45,65 +43,6 @@
|
|||
'';
|
||||
};
|
||||
|
||||
base = lib.mkOption {
|
||||
# In newer Nix versions, particularly with lazy trees, outPath of
|
||||
# flakes becomes a Nix-language path object. We deliberately allow this
|
||||
# to gracefully come through the interface in discussion with @roberth.
|
||||
#
|
||||
# See: https://github.com/NixOS/nixpkgs/pull/278522#discussion_r1460292639
|
||||
type = types.nullOr flakeRef;
|
||||
|
||||
default = nodesConfig.base;
|
||||
defaultText = "nodes.base";
|
||||
|
||||
example = lib.literalExpression "inputs.nixpkgs";
|
||||
|
||||
description = ''
|
||||
The path to the nixpkgs source used to build a system. A `base` package set
|
||||
is required to be set, and can be specified via either:
|
||||
1. `options.nodes.base` (default `base` used for all systems)
|
||||
2. `options.nodes.nodes.<name>.base` (takes prescedence over `options.nodes.base`)
|
||||
|
||||
This can also be optionally set if the NixOS system is not built with a flake but still uses
|
||||
pinned sources: set this to the store path for the nixpkgs sources used to build the system,
|
||||
as may be obtained by `fetchTarball`, for example.
|
||||
|
||||
Note: the name of the store path must be "source" due to
|
||||
<https://github.com/NixOS/nix/issues/7075>.
|
||||
'';
|
||||
};
|
||||
|
||||
homeManager = mkOption {
|
||||
type = types.nullOr flakeRef;
|
||||
default = nodesConfig.homeManager;
|
||||
defaultText = "nodes.homeManager";
|
||||
example = lib.literalExpression "inputs.home-manager";
|
||||
description = ''
|
||||
The path to the home-manager source. A `homeManager` flake reference
|
||||
is required to be set for `homes/` to be evaluated, and can be specified via either:
|
||||
1. `options.nodes.homeManager` (default `homManager` used for all systems)
|
||||
2. `options.nodes.nodes.<name>.homeManager` (takes prescedence over `options.nodes.homeManager`)
|
||||
'';
|
||||
};
|
||||
|
||||
modules = mkOption {
|
||||
type = types.listOf types.raw;
|
||||
default = [];
|
||||
example = lib.literalExpression "[ { environment.systemPackages = [ pkgs.git ]; } ]";
|
||||
description = ''
|
||||
Shared modules to import; equivalent to the NixOS module system's `extraModules`.
|
||||
'';
|
||||
};
|
||||
|
||||
args = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = lib.literalExpression "{ inherit inputs; }";
|
||||
description = ''
|
||||
Shared args to provided for each node; equivalent to the NixOS module system's `specialArgs`.
|
||||
'';
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
# TODO: write a custom group type that validates better than types.attrs lol
|
||||
type = types.functionTo (types.listOf types.attrs);
|
||||
|
|
@ -112,9 +51,6 @@
|
|||
description = ''
|
||||
A function from the `groups` hierarchy to a list of groups this node inherits from.
|
||||
'';
|
||||
|
||||
apply = groupsFn:
|
||||
groupsFn nodesConfig.groups;
|
||||
};
|
||||
|
||||
deploy = {
|
||||
|
|
@ -155,7 +91,7 @@
|
|||
example = false;
|
||||
description = ''
|
||||
Whether to enable interactive sudo (password based sudo).
|
||||
NOT RECOMMENDED. Use one of Snowflake's recommended auth methods instead.
|
||||
NOT RECOMMENDED. Use one of Cerulean's recommended auth methods instead.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -228,7 +164,7 @@
|
|||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "snowbld";
|
||||
default = "cerubld";
|
||||
example = "custom-user";
|
||||
description = ''
|
||||
The user to connect to over ssh during deployment.
|
||||
|
|
@ -247,7 +183,7 @@
|
|||
publicKeys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIeyZuUUmyUYrYaEJwEMvcXqZFYm1NaZab8klOyK6Imr me@myputer"];
|
||||
example = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIeyZuUUmyUYrYaEJwEMvcXqZFYm1NaZab8klOyK6Imr me@puter"];
|
||||
description = ''
|
||||
SSH public keys that will be authorized to the deployment user.
|
||||
This key is intended solely for deployment, allowing for fine-grained permission control.
|
||||
|
|
@ -265,33 +201,4 @@
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = let
|
||||
throwGotNull = name:
|
||||
throw ''
|
||||
[snow] `nodes.<name>.${name}` must be set for all nodes! (got: <null>)
|
||||
'';
|
||||
givenSystem =
|
||||
(config.system != null)
|
||||
|| throwGotNull "system";
|
||||
|
||||
givenBase =
|
||||
(config.base != null)
|
||||
|| throwGotNull "base";
|
||||
|
||||
givenHomeManager =
|
||||
(config.homeManager != null)
|
||||
|| throwGotNull "homeManager";
|
||||
|
||||
givenDeployHost =
|
||||
(config.deploy.ssh.host != null)
|
||||
|| throwGotNull "deploy.ssh.host";
|
||||
in
|
||||
assert givenSystem
|
||||
&& givenBase
|
||||
&& givenHomeManager
|
||||
&& givenDeployHost; {
|
||||
# extend these from the nodes configuration
|
||||
inherit (nodesConfig) modules args;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,10 +1,5 @@
|
|||
{
|
||||
config,
|
||||
_snow,
|
||||
...
|
||||
}: {
|
||||
outputs.checks =
|
||||
_snow.inputs.deploy-rs.lib
|
||||
|> builtins.mapAttrs (system: deployLib:
|
||||
deployLib.deployChecks config.outputs.deploy);
|
||||
}
|
||||
checks =
|
||||
inputs.deploy-rs.lib
|
||||
|> mapAttrs (system: deployLib:
|
||||
deployLib.deployChecks deploy);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,90 +1,57 @@
|
|||
{
|
||||
_snow,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(builtins)
|
||||
mapAttrs
|
||||
;
|
||||
deploy.nodes = mapNodes nodes ({
|
||||
name,
|
||||
node,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(node.deploy)
|
||||
ssh
|
||||
user
|
||||
interactiveSudo
|
||||
remoteBuild
|
||||
rollback
|
||||
autoRollback
|
||||
magicRollback
|
||||
activationTimeout
|
||||
confirmTimeout
|
||||
;
|
||||
|
||||
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;
|
||||
nixosFor = system: inputs.deploy-rs.lib.${system}.activate.nixos;
|
||||
in {
|
||||
hostname =
|
||||
if ssh.host != null
|
||||
then ssh.host
|
||||
else "";
|
||||
|
||||
groups = node.groups (parseGroupsDecl nodes.groups);
|
||||
groupModules = root: getGroupModules root groups;
|
||||
});
|
||||
in {
|
||||
outputs.deploy.nodes = mapNodes config.nodes ({
|
||||
name,
|
||||
node,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(node.deploy)
|
||||
ssh
|
||||
user
|
||||
interactiveSudo
|
||||
remoteBuild
|
||||
rollback
|
||||
autoRollback
|
||||
magicRollback
|
||||
activationTimeout
|
||||
confirmTimeout
|
||||
;
|
||||
profilesOrder = ["default"]; # profiles priority
|
||||
profiles.default = {
|
||||
path = nixosFor node.system nixosConfigurations.${name};
|
||||
|
||||
nixosFor = system: _snow.inputs.deploy-rs.lib.${system}.activate.nixos;
|
||||
in {
|
||||
hostname =
|
||||
if ssh.host != null
|
||||
then ssh.host
|
||||
else "";
|
||||
user = user;
|
||||
sudo = "sudo -u";
|
||||
interactiveSudo = interactiveSudo;
|
||||
|
||||
profilesOrder = ["default"]; # profiles priority
|
||||
profiles.default = {
|
||||
path = nixosFor node.system config.outputs.nixosConfigurations.${name};
|
||||
fastConnection = false;
|
||||
|
||||
user = user;
|
||||
sudo = "sudo -u";
|
||||
interactiveSudo = interactiveSudo;
|
||||
autoRollback = autoRollback -> rollback;
|
||||
magicRollback = magicRollback -> rollback;
|
||||
activationTimeout = activationTimeout;
|
||||
confirmTimeout = confirmTimeout;
|
||||
|
||||
fastConnection = false;
|
||||
remoteBuild = remoteBuild;
|
||||
sshUser = ssh.user;
|
||||
sshOpts =
|
||||
ssh.opts
|
||||
++ (
|
||||
if elem "-p" ssh.opts
|
||||
then []
|
||||
else ["-p" (toString ssh.port)]
|
||||
)
|
||||
++ (
|
||||
if elem "-A" ssh.opts
|
||||
then []
|
||||
else ["-A"]
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
autoRollback = autoRollback -> rollback;
|
||||
magicRollback = magicRollback -> rollback;
|
||||
activationTimeout = activationTimeout;
|
||||
confirmTimeout = confirmTimeout;
|
||||
|
||||
remoteBuild = remoteBuild;
|
||||
sshUser = ssh.user;
|
||||
sshOpts =
|
||||
ssh.opts
|
||||
++ (
|
||||
if builtins.elem "-p" ssh.opts
|
||||
then []
|
||||
else ["-p" (toString ssh.port)]
|
||||
)
|
||||
++ (
|
||||
if builtins.elem "-A" ssh.opts
|
||||
then []
|
||||
else ["-A"]
|
||||
);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,78 +8,60 @@
|
|||
# options = { ... };
|
||||
# type = { ... };
|
||||
# }
|
||||
{
|
||||
snow,
|
||||
config,
|
||||
systems,
|
||||
root,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(builtins)
|
||||
all
|
||||
attrNames
|
||||
warn
|
||||
;
|
||||
nixosConfigurations = mapNodes nodes (
|
||||
{
|
||||
base,
|
||||
lib,
|
||||
name,
|
||||
node,
|
||||
groupModules,
|
||||
...
|
||||
}: let
|
||||
homeManager =
|
||||
if node.homeManager != null
|
||||
then node.homeManager
|
||||
else if nodes.homeManager != null
|
||||
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;
|
||||
|
||||
inherit
|
||||
(config)
|
||||
nodes
|
||||
;
|
||||
in {
|
||||
outputs.nixosConfigurations = mapNodes nodes (
|
||||
{
|
||||
base,
|
||||
lib,
|
||||
name,
|
||||
node,
|
||||
groupModules,
|
||||
...
|
||||
}: let
|
||||
homeManager =
|
||||
if node.homeManager != null
|
||||
then node.homeManager
|
||||
else if nodes.homeManager != null
|
||||
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;
|
||||
userArgs = nodes.args // node.args;
|
||||
ceruleanArgs = {
|
||||
inherit systems root base nodes node;
|
||||
inherit (node) system;
|
||||
inherit (this) snow;
|
||||
hostname = name;
|
||||
|
||||
userArgs = nodes.args // node.args;
|
||||
snowArgs = {
|
||||
inherit systems snow root base nodes node;
|
||||
inherit (node) system;
|
||||
hostname = name;
|
||||
|
||||
_snow = {
|
||||
inherit inputs userArgs snowArgs homeManager;
|
||||
specialArgs = userArgs // snowArgs;
|
||||
_cerulean = {
|
||||
inherit inputs userArgs ceruleanArgs homeManager;
|
||||
specialArgs = userArgs // ceruleanArgs;
|
||||
};
|
||||
};
|
||||
};
|
||||
specialArgs = assert (userArgs
|
||||
|> attrNames
|
||||
|> all (argName:
|
||||
! snowArgs ? argName
|
||||
|| abort ''
|
||||
`specialArgs` are like super important to Snow my love... </3
|
||||
But `args.${argName}` is a reserved argument name :(
|
||||
''));
|
||||
snowArgs._snow.specialArgs;
|
||||
in
|
||||
lib.nixosSystem {
|
||||
inherit (node) system;
|
||||
inherit specialArgs;
|
||||
modules =
|
||||
[
|
||||
snow.nixosModules.default
|
||||
(snow.findImport /${root}/hosts/${name})
|
||||
]
|
||||
++ (groupModules root)
|
||||
++ node.modules
|
||||
++ nodes.modules;
|
||||
}
|
||||
);
|
||||
}
|
||||
specialArgs = assert (userArgs
|
||||
|> attrNames
|
||||
|> all (argName:
|
||||
! ceruleanArgs ? argName
|
||||
|| abort ''
|
||||
`specialArgs` are like super important to Cerulean my love... </3
|
||||
But `args.${argName}` is a reserved argument name :(
|
||||
''));
|
||||
ceruleanArgs._cerulean.specialArgs;
|
||||
in
|
||||
lib.nixosSystem {
|
||||
inherit (node) system;
|
||||
inherit specialArgs;
|
||||
modules =
|
||||
[
|
||||
self.nixosModules.default
|
||||
(this.findImport /${root}/hosts/${name})
|
||||
]
|
||||
++ (groupModules root)
|
||||
++ node.modules
|
||||
++ nodes.modules;
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +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,
|
||||
mix,
|
||||
...
|
||||
} @ args: let
|
||||
inherit (nt) findImport;
|
||||
in
|
||||
mix.newMixture args (mixture: {
|
||||
includes.public = [
|
||||
./nixpkgs.nix
|
||||
];
|
||||
|
||||
inherit findImport;
|
||||
})
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
inputs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
|
||||
# A best effort, lenient estimate. Please use a recent nixpkgs lib if you
|
||||
# override it at all.
|
||||
minVersion = "23.05pre-git";
|
||||
|
||||
isNixpkgsValidVersion = let
|
||||
revInfo = lib.optional (inputs.nixpkgs?rev) " (nixpkgs-lib.rev: ${inputs.nixpkgs.rev})";
|
||||
in
|
||||
(builtins.compareVersions lib.version minVersion < 0)
|
||||
|| abort ''
|
||||
The nixpkgs dependency of snow was overridden but is too old.
|
||||
The minimum supported version of nixpkgs-lib is ${minVersion},
|
||||
but the actual version is ${lib.version}${revInfo}.
|
||||
'';
|
||||
in
|
||||
assert isNixpkgsValidVersion; {
|
||||
# Helper function for defining a per-system option that
|
||||
# gets transposed by the usual flake system logic to a
|
||||
# top-level outputs attribute.
|
||||
mkPerSystemFlakeOutput = {
|
||||
name,
|
||||
option,
|
||||
file,
|
||||
}: {
|
||||
_file = file;
|
||||
|
||||
options = {
|
||||
outputs.${name} = mkOption {
|
||||
type = types.attrsWith {
|
||||
elemType = option.type;
|
||||
lazy = true;
|
||||
placeholder = "system";
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
See {option}`perSystem.${name}` for description and examples.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
96
nix/snow/lib/nodes.nix
Normal file
96
nix/snow/lib/nodes.nix
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# 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";
|
||||
|
||||
parseGroupsDecl = groups: let
|
||||
validGroup = g:
|
||||
isAttrs g
|
||||
|| throw ''
|
||||
Cerulean Nexus groups must be provided as attribute sets, got "${typeOf g}" instead!
|
||||
Ensure all the group definitions are attribute sets under your call to `cerulean.mkNexus`.
|
||||
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;
|
||||
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 ''
|
||||
Cerulean 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;
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue