chore: initial commit
This commit is contained in:
commit
7e8aabfaff
19 changed files with 2505 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
tmp
|
||||||
10
default.nix
Normal file
10
default.nix
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
(import
|
||||||
|
(
|
||||||
|
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||||
|
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{ src = ./.; }
|
||||||
|
).defaultNix
|
||||||
137
flake.lock
generated
Normal file
137
flake.lock
generated
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"darwin": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1661882940,
|
||||||
|
"narHash": "sha256-4LaVFnV22WrOA0aolqqk9dXrM8crikcrLQt29G18F7M=",
|
||||||
|
"owner": "lnl7",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"rev": "80cec5115aae74accc4ccfb9f84306d7863f0632",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "lnl7",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1650374568,
|
||||||
|
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1644229661,
|
||||||
|
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils-plus": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1657226504,
|
||||||
|
"narHash": "sha256-GIYNjuq4mJlFgqKsZ+YrgzWm0IpA4axA3MCrdKYj7gs=",
|
||||||
|
"owner": "gytis-ivaskevicius",
|
||||||
|
"repo": "flake-utils-plus",
|
||||||
|
"rev": "2bf0f91643c2e5ae38c1b26893ac2927ac9bd82a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "gytis-ivaskevicius",
|
||||||
|
"repo": "flake-utils-plus",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixlib": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1636849918,
|
||||||
|
"narHash": "sha256-nzUK6dPcTmNVrgTAC1EOybSMsrcx+QrVPyqRdyKLkjA=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"rev": "28a5b0557f14124608db68d3ee1f77e9329e9dd5",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixos-generators": {
|
||||||
|
"inputs": {
|
||||||
|
"nixlib": "nixlib",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1660727616,
|
||||||
|
"narHash": "sha256-zYTIvdPMYMx/EYqXODAwIIU30RiEHqNHdgarIHuEYZc=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixos-generators",
|
||||||
|
"rev": "adccd191a0e83039d537e021f19495b7bad546a1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixos-generators",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1662316000,
|
||||||
|
"narHash": "sha256-NkJHCVi6sj1+QqqXaozSJ0K23ANmvsnDmeC/6WXo+wI=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "50c62eeda9df340ff6b83a0e2343a447af04237c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "release-22.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"darwin": "darwin",
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"flake-utils-plus": "flake-utils-plus",
|
||||||
|
"nixos-generators": "nixos-generators",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
42
flake.nix
Normal file
42
flake.nix
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
description = "A very basic flake";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/release-22.05";
|
||||||
|
flake-utils-plus.url = "github:gytis-ivaskevicius/flake-utils-plus";
|
||||||
|
|
||||||
|
flake-compat = {
|
||||||
|
url = "github:edolstra/flake-compat";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = inputs:
|
||||||
|
let
|
||||||
|
core-inputs = inputs // {
|
||||||
|
src = ./.;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Create the library, extending the nixpkgs library and merging
|
||||||
|
# libraries from other inputs to make them available like
|
||||||
|
# `lib.flake-utils-plus.mkApp`.
|
||||||
|
# Usage: mkLib { inherit inputs; src = ./.; }
|
||||||
|
# result: lib
|
||||||
|
mkLib = import ./lib core-inputs;
|
||||||
|
|
||||||
|
# A convenience wrapper to create the library and then call `lib.mkFlake`.
|
||||||
|
# Usage: mkFlake { inherit inputs; src = ./.; ... }
|
||||||
|
# result: <flake-outputs>
|
||||||
|
mkFlake = flake-and-lib-options@{ inputs, src, ... }:
|
||||||
|
let
|
||||||
|
lib = mkLib {
|
||||||
|
inherit inputs src;
|
||||||
|
};
|
||||||
|
flake-options = builtins.removeAttrs flake-and-lib-options [ "inputs" "src" ];
|
||||||
|
in
|
||||||
|
lib.mkFlake flake-options;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit mkLib mkFlake;
|
||||||
|
};
|
||||||
|
}
|
||||||
36
lib/attrs/default.nix
Normal file
36
lib/attrs/default.nix
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (core-inputs.nixpkgs.lib)
|
||||||
|
assertMsg
|
||||||
|
mapAttrsToList
|
||||||
|
flatten
|
||||||
|
fold
|
||||||
|
recursiveUpdate
|
||||||
|
mergeAttrs;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
attrs = {
|
||||||
|
# Map and flatten an attribute set into a list.
|
||||||
|
# Type: (a -> b -> [c]) -> Attrs -> [c]
|
||||||
|
# Usage: map-concat-attrs-to-list (name: value: [name value]) { x = 1; y = 2; }
|
||||||
|
# result: [ "x" 1 "y" 2 ]
|
||||||
|
map-concat-attrs-to-list = f: attrs:
|
||||||
|
flatten (mapAttrsToList f attrs);
|
||||||
|
|
||||||
|
# Recursively merge a list of attribute sets.
|
||||||
|
# Type: [Attrs] -> Attrs
|
||||||
|
# Usage: merge-deep [{ x = 1; } { x = 2; }]
|
||||||
|
# result: { x = 2; }
|
||||||
|
merge-deep = fold recursiveUpdate { };
|
||||||
|
|
||||||
|
# Merge the root of a list of attribute sets.
|
||||||
|
# Type: [Attrs] -> Attrs
|
||||||
|
# Usage: merge-shallow [{ x = 1; } { x = 2; }]
|
||||||
|
# result: { x = 2; }
|
||||||
|
merge-shallow = fold mergeAttrs { };
|
||||||
|
};
|
||||||
|
}
|
||||||
109
lib/default.nix
Normal file
109
lib/default.nix
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
# @NOTE(jakehamilton): The role of this file is to bootstrap the
|
||||||
|
# Snowfall library. There is some duplication shared between this
|
||||||
|
# file and the library itself due to the library needing to pass through
|
||||||
|
# another extended library for its own applications.
|
||||||
|
core-inputs:
|
||||||
|
user-options:
|
||||||
|
|
||||||
|
let
|
||||||
|
user-inputs = user-options.inputs // { src = user-options.src; };
|
||||||
|
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg fix filterAttrs mergeAttrs fold recursiveUpdate;
|
||||||
|
|
||||||
|
# Recursively merge a list of attribute sets.
|
||||||
|
# Type: [Attrs] -> Attrs
|
||||||
|
# Usage: merge-deep [{ x = 1; } { x = 2; }]
|
||||||
|
# result: { x = 2; }
|
||||||
|
merge-deep = fold recursiveUpdate { };
|
||||||
|
|
||||||
|
# Merge the root of a list of attribute sets.
|
||||||
|
# Type: [Attrs] -> Attrs
|
||||||
|
# Usage: merge-shallow [{ x = 1; } { x = 2; }]
|
||||||
|
# result: { x = 2; }
|
||||||
|
merge-shallow = fold mergeAttrs { };
|
||||||
|
|
||||||
|
# Transform an attribute set of inputs into an attribute set where
|
||||||
|
# the values are the inputs' `lib` attribute. Entries without a `lib`
|
||||||
|
# attribute are removed.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: get-lib { x = nixpkgs; y = {}; }
|
||||||
|
# result: { x = nixpkgs.lib; }
|
||||||
|
get-libs = attrs:
|
||||||
|
let
|
||||||
|
# @PERF(jakehamilton): Replace filter+map with a fold.
|
||||||
|
attrs-with-libs = filterAttrs
|
||||||
|
(name: value: builtins.isAttrs (value.lib or null))
|
||||||
|
attrs;
|
||||||
|
libs =
|
||||||
|
builtins.mapAttrs (name: input: input.lib) attrs-with-libs;
|
||||||
|
in
|
||||||
|
libs;
|
||||||
|
|
||||||
|
# Remove the `self` attribute from an attribute set.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: without-self { self = {}; x = true; }
|
||||||
|
# result: { x = true; }
|
||||||
|
without-self = attrs: builtins.removeAttrs attrs [ "self" ];
|
||||||
|
|
||||||
|
core-inputs-libs = get-libs (without-self core-inputs);
|
||||||
|
user-inputs-libs = get-libs (without-self user-inputs);
|
||||||
|
|
||||||
|
snowfall-lib-root = "${core-inputs.src}/lib";
|
||||||
|
snowfall-lib-dirs =
|
||||||
|
let
|
||||||
|
files = builtins.readDir snowfall-lib-root;
|
||||||
|
dirs = filterAttrs (name: kind: kind == "directory") files;
|
||||||
|
names = builtins.attrNames dirs;
|
||||||
|
in
|
||||||
|
names;
|
||||||
|
|
||||||
|
snowfall-lib = fix (snowfall-lib:
|
||||||
|
let
|
||||||
|
attrs = {
|
||||||
|
inherit snowfall-lib core-inputs user-inputs;
|
||||||
|
};
|
||||||
|
libs = builtins.map
|
||||||
|
(dir: import "${snowfall-lib-root}/${dir}" attrs)
|
||||||
|
snowfall-lib-dirs;
|
||||||
|
in
|
||||||
|
merge-deep libs
|
||||||
|
);
|
||||||
|
|
||||||
|
snowfall-top-level-lib = filterAttrs (name: value: !builtins.isAttrs value) snowfall-lib;
|
||||||
|
|
||||||
|
base-lib = merge-shallow [
|
||||||
|
core-inputs.nixpkgs.lib
|
||||||
|
core-inputs-libs
|
||||||
|
user-inputs-libs
|
||||||
|
snowfall-top-level-lib
|
||||||
|
{ snowfall = snowfall-lib; }
|
||||||
|
];
|
||||||
|
|
||||||
|
user-lib-root = "${user-inputs.src}/lib";
|
||||||
|
user-lib-modules = snowfall-lib.fs.get-default-nix-files-recursive user-lib-root;
|
||||||
|
|
||||||
|
user-lib = fix (user-lib:
|
||||||
|
let
|
||||||
|
attrs = {
|
||||||
|
inherit (user-options) inputs;
|
||||||
|
snowfall-inputs = core-inputs;
|
||||||
|
lib = merge-shallow [ base-lib user-lib ];
|
||||||
|
};
|
||||||
|
libs = builtins.map
|
||||||
|
(path: import path attrs)
|
||||||
|
user-lib-modules;
|
||||||
|
in
|
||||||
|
merge-deep libs
|
||||||
|
);
|
||||||
|
|
||||||
|
lib = merge-deep [
|
||||||
|
base-lib
|
||||||
|
user-lib
|
||||||
|
];
|
||||||
|
|
||||||
|
user-inputs-has-self = builtins.elem "self" (builtins.attrNames user-inputs);
|
||||||
|
user-inputs-has-src = builtins.elem "src" (builtins.attrNames user-inputs);
|
||||||
|
in
|
||||||
|
assert (assertMsg (user-inputs-has-self) "Missing attribute `self` for mkLib.");
|
||||||
|
assert (assertMsg (user-inputs-has-src) "Missing attribute `src` for mkLib.");
|
||||||
|
lib
|
||||||
130
lib/flake/default.nix
Normal file
130
lib/flake/default.nix
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg fold filterAttrs const;
|
||||||
|
in
|
||||||
|
rec {
|
||||||
|
flake = rec {
|
||||||
|
# Remove the `self` attribute from an attribute set.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: without-self { self = {}; x = true; }
|
||||||
|
# result: { x = true; }
|
||||||
|
without-self = flake-inputs: builtins.removeAttrs flake-inputs [ "self" ];
|
||||||
|
|
||||||
|
# Remove the `src` attribute from an attribute set.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: without-src { src = ./.; x = true; }
|
||||||
|
# result: { x = true; }
|
||||||
|
without-src = flake-inputs: builtins.removeAttrs flake-inputs [ "src" ];
|
||||||
|
|
||||||
|
# Remove the `src` and `self` attributes from an attribute set.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: without-snowfall-inputs { self = {}; src = ./.; x = true; }
|
||||||
|
# result: { x = true; }
|
||||||
|
without-snowfall-inputs = snowfall-lib.fp.compose without-self without-src;
|
||||||
|
|
||||||
|
# Remove Snowfall-specific attributes so the rest can be safely
|
||||||
|
# passed to flake-utils-plus.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: without-snowfall-options { src = ./.; x = true; }
|
||||||
|
# result: { x = true; }
|
||||||
|
without-snowfall-options = flake-options:
|
||||||
|
builtins.removeAttrs
|
||||||
|
flake-options
|
||||||
|
[
|
||||||
|
"systems"
|
||||||
|
"modules"
|
||||||
|
"overlays"
|
||||||
|
"packages"
|
||||||
|
"outputs-builder"
|
||||||
|
"outputsBuilder"
|
||||||
|
"packagesPrefix"
|
||||||
|
"hosts"
|
||||||
|
"channels-config"
|
||||||
|
"templates"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Transform an attribute set of inputs into an attribute set where
|
||||||
|
# the values are the inputs' `lib` attribute. Entries without a `lib`
|
||||||
|
# attribute are removed.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: get-lib { x = nixpkgs; y = {}; }
|
||||||
|
# result: { x = nixpkgs.lib; }
|
||||||
|
get-libs = attrs:
|
||||||
|
let
|
||||||
|
# @PERF(jakehamilton): Replace filter+map with a fold.
|
||||||
|
attrs-with-libs = filterAttrs
|
||||||
|
(name: value: builtins.isAttrs (value.lib or null))
|
||||||
|
attrs;
|
||||||
|
libs =
|
||||||
|
builtins.mapAttrs (name: input: input.lib) attrs-with-libs;
|
||||||
|
in
|
||||||
|
libs;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
mkFlake = full-flake-options:
|
||||||
|
let
|
||||||
|
custom-flake-options = flake.without-snowfall-options full-flake-options;
|
||||||
|
systems = snowfall-lib.system.create-systems (full-flake-options.systems or {});
|
||||||
|
hosts = snowfall-lib.attrs.merge-shallow [ (full-flake-options.systems.hosts or {}) systems ];
|
||||||
|
templates = snowfall-lib.template.create-templates {
|
||||||
|
overrides = (full-flake-options.templates or {});
|
||||||
|
};
|
||||||
|
modules = snowfall-lib.module.create-modules {
|
||||||
|
overrides = (full-flake-options.modules or {});
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs-builder = channels:
|
||||||
|
let
|
||||||
|
user-outputs-builder =
|
||||||
|
full-flake-options.outputs-builder
|
||||||
|
or full-flake-options.outputsBuilder
|
||||||
|
or (const {});
|
||||||
|
user-outputs = user-outputs-builder channels;
|
||||||
|
packages = snowfall-lib.package.create-packages {
|
||||||
|
inherit channels;
|
||||||
|
overrides = (full-flake-options.packages or {}) // (user-outputs.packages or {});
|
||||||
|
};
|
||||||
|
shells = snowfall-lib.shell.create-shells {
|
||||||
|
inherit channels;
|
||||||
|
overrides = (full-flake-options.shells or {}) // (user-outputs.devShells or {});
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = {
|
||||||
|
inherit packages;
|
||||||
|
|
||||||
|
devShells = shells;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
snowfall-lib.attrs.merge-deep [ user-outputs outputs ];
|
||||||
|
|
||||||
|
flake-options = custom-flake-options // {
|
||||||
|
inherit hosts templates;
|
||||||
|
inherit (user-inputs) self;
|
||||||
|
|
||||||
|
lib = snowfall-lib.internal.system-lib;
|
||||||
|
inputs = snowfall-lib.flake.without-src user-inputs;
|
||||||
|
|
||||||
|
nixosModules = modules;
|
||||||
|
|
||||||
|
channelsConfig = full-flake-options.channels-config or {};
|
||||||
|
|
||||||
|
overlays = core-inputs.flake-utils-plus.lib.exportOverlays ({
|
||||||
|
inherit (user-inputs.self) pkgs;
|
||||||
|
inputs = user-inputs;
|
||||||
|
});
|
||||||
|
|
||||||
|
channels.nixpkgs.overlaysBuilder = snowfall-lib.overlay.create-overlays {
|
||||||
|
overlay-package-namespace = full-flake-options.overlay-package-namespace or null;
|
||||||
|
extra-overlays = full-flake-options.overlays or [];
|
||||||
|
};
|
||||||
|
|
||||||
|
outputsBuilder = outputs-builder;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
core-inputs.flake-utils-plus.lib.mkFlake flake-options;
|
||||||
|
}
|
||||||
36
lib/fp/default.nix
Normal file
36
lib/fp/default.nix
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) baseNameOf dirOf;
|
||||||
|
inherit (core-inputs.nixpkgs.lib) id foldr flip;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
fp = rec {
|
||||||
|
# Compose two functions.
|
||||||
|
# Type: (b -> c) -> (a -> b) -> a -> c
|
||||||
|
# Usage: compose add-two add-one
|
||||||
|
# result: (x: add-two (add-one x))
|
||||||
|
compose = f: g: x: f (g x);
|
||||||
|
|
||||||
|
# Compose many functions.
|
||||||
|
# Type: [(x -> y)] -> a -> b
|
||||||
|
# Usage: compose-all [ add-two add-one ]
|
||||||
|
# result: (x: add-two (add-one x))
|
||||||
|
compose-all = foldr compose id;
|
||||||
|
|
||||||
|
# Call a function with an argument.
|
||||||
|
# Type: (a -> b) -> a -> b
|
||||||
|
# Usage: call (x: x + 1) 0
|
||||||
|
# result: 1
|
||||||
|
call = f: x: f x;
|
||||||
|
|
||||||
|
# Apply an argument to a function.
|
||||||
|
# Type: a -> (a -> b) -> b
|
||||||
|
# Usage: call (x: x + 1) 0
|
||||||
|
# result: 1
|
||||||
|
apply = flip call;
|
||||||
|
};
|
||||||
|
}
|
||||||
153
lib/fs/default.nix
Normal file
153
lib/fs/default.nix
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) readDir pathExists;
|
||||||
|
inherit (core-inputs) flake-utils-plus;
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg filterAttrs mapAttrsToList flatten;
|
||||||
|
|
||||||
|
file-name-regex = "(.*)\\.(.*)$";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
fs = rec {
|
||||||
|
# Matchers for file kinds. These are often used with `readDir`.
|
||||||
|
# Type: String -> Bool
|
||||||
|
# Usage: is-file-kind "directory"
|
||||||
|
# result: false
|
||||||
|
is-file-kind = kind: kind == "regular";
|
||||||
|
is-symlink-kind = kind: kind == "symlink";
|
||||||
|
is-directory-kind = kind: kind == "directory";
|
||||||
|
is-unknown-kind = kind: kind == "unknown";
|
||||||
|
|
||||||
|
# Get a file path relative to the user's flake.
|
||||||
|
# Type: Path -> Path
|
||||||
|
# Usage: get-file "systems"
|
||||||
|
# result: "/user-source/systems"
|
||||||
|
get-file = path: "${user-inputs.src}/${path}";
|
||||||
|
|
||||||
|
# Get a file path relative to the this flake.
|
||||||
|
# Type: Path -> Path
|
||||||
|
# Usage: get-file "systems"
|
||||||
|
# result: "/user-source/systems"
|
||||||
|
internal-get-file = path: "${core-inputs.src}/${path}";
|
||||||
|
|
||||||
|
# Safely read from a directory if it exists.
|
||||||
|
# Type: Path -> Attrs
|
||||||
|
# Usage: safe-read-directory ./some/path
|
||||||
|
# result: { "my-file.txt" = "regular"; }
|
||||||
|
safe-read-directory = path:
|
||||||
|
if pathExists path then
|
||||||
|
readDir path
|
||||||
|
else
|
||||||
|
{};
|
||||||
|
|
||||||
|
# Get directories at a given path.
|
||||||
|
# Type: Path -> [Path]
|
||||||
|
# Usage: get-directories ./something
|
||||||
|
# result: [ "./something/a-directory" ]
|
||||||
|
get-directories = path:
|
||||||
|
let
|
||||||
|
entries = safe-read-directory path;
|
||||||
|
filtered-entries = filterAttrs (name: kind: is-directory-kind kind) entries;
|
||||||
|
in
|
||||||
|
mapAttrsToList (name: kind: "${path}/${name}") filtered-entries;
|
||||||
|
|
||||||
|
# Get files at a given path.
|
||||||
|
# Type: Path -> [Path]
|
||||||
|
# Usage: get-files ./something
|
||||||
|
# result: [ "./something/a-file" ]
|
||||||
|
get-files = path:
|
||||||
|
let
|
||||||
|
entries = safe-read-directory path;
|
||||||
|
filtered-entries = filterAttrs (name: kind: is-file-kind kind) entries;
|
||||||
|
in
|
||||||
|
mapAttrsToList (name: kind: "${path}/${name}") filtered-entries;
|
||||||
|
|
||||||
|
# Get files at a given path, traversing any directories within.
|
||||||
|
# Type: Path -> [Path]
|
||||||
|
# Usage: get-files-recursive ./something
|
||||||
|
# result: [ "./something/some-directory/a-file" ]
|
||||||
|
get-files-recursive = path:
|
||||||
|
let
|
||||||
|
entries = safe-read-directory path;
|
||||||
|
filtered-entries =
|
||||||
|
filterAttrs
|
||||||
|
(name: kind: (is-file-kind kind) || (is-directory-kind kind))
|
||||||
|
entries;
|
||||||
|
map-file = name: kind:
|
||||||
|
let
|
||||||
|
path' = "${path}/${name}";
|
||||||
|
in if is-directory-kind kind then
|
||||||
|
get-files-recursive path'
|
||||||
|
else
|
||||||
|
path';
|
||||||
|
files = snowfall-lib.attrs.map-concat-attrs-to-list
|
||||||
|
map-file
|
||||||
|
filtered-entries;
|
||||||
|
in
|
||||||
|
files;
|
||||||
|
|
||||||
|
# Get nix files at a given path.
|
||||||
|
# Type: Path -> [Path]
|
||||||
|
# Usage: get-nix-files "./something"
|
||||||
|
# result: [ "./something/a.nix" ]
|
||||||
|
get-nix-files = path:
|
||||||
|
builtins.filter
|
||||||
|
(snowfall-lib.path.has-file-extension "nix")
|
||||||
|
(get-files path);
|
||||||
|
|
||||||
|
# Get nix files at a given path, traversing any directories within.
|
||||||
|
# Type: Path -> [Path]
|
||||||
|
# Usage: get-nix-files "./something"
|
||||||
|
# result: [ "./something/a.nix" ]
|
||||||
|
get-nix-files-recursive = path:
|
||||||
|
builtins.filter
|
||||||
|
(snowfall-lib.path.has-file-extension "nix")
|
||||||
|
(get-files-recursive path);
|
||||||
|
|
||||||
|
# Get nix files at a given path named "default.nix".
|
||||||
|
# Type: Path -> [Path]
|
||||||
|
# Usage: get-default-nix-files "./something"
|
||||||
|
# result: [ "./something/default.nix" ]
|
||||||
|
get-default-nix-files = path:
|
||||||
|
builtins.filter
|
||||||
|
(name: builtins.baseNameOf name == "default.nix")
|
||||||
|
(get-files path);
|
||||||
|
|
||||||
|
# Get nix files at a given path named "default.nix", traversing any directories within.
|
||||||
|
# Type: Path -> [Path]
|
||||||
|
# Usage: get-default-nix-files-recursive "./something"
|
||||||
|
# result: [ "./something/some-directory/default.nix" ]
|
||||||
|
get-default-nix-files-recursive = path:
|
||||||
|
builtins.filter
|
||||||
|
(name: builtins.baseNameOf name == "default.nix")
|
||||||
|
(get-files-recursive path);
|
||||||
|
|
||||||
|
# Get nix files at a given path not named "default.nix".
|
||||||
|
# Type: Path -> [Path]
|
||||||
|
# Usage: get-non-default-nix-files "./something"
|
||||||
|
# result: [ "./something/a.nix" ]
|
||||||
|
get-non-default-nix-files = path:
|
||||||
|
builtins.filter
|
||||||
|
(name:
|
||||||
|
(snowfall-lib.path.has-file-extension "nix" name)
|
||||||
|
&& (builtins.baseNameOf name != "default.nix")
|
||||||
|
)
|
||||||
|
(get-files path);
|
||||||
|
|
||||||
|
# Get nix files at a given path not named "default.nix",
|
||||||
|
# traversing any directories within.
|
||||||
|
# Type: Path -> [Path]
|
||||||
|
# Usage: get-non-default-nix-files-recursive "./something"
|
||||||
|
# result: [ "./something/some-directory/a.nix" ]
|
||||||
|
get-non-default-nix-files-recursive = path:
|
||||||
|
builtins.filter
|
||||||
|
(name:
|
||||||
|
(snowfall-lib.path.has-file-extension "nix" name)
|
||||||
|
&& (builtins.baseNameOf name != "default.nix")
|
||||||
|
)
|
||||||
|
(get-files-recursive path);
|
||||||
|
};
|
||||||
|
}
|
||||||
48
lib/internal/default.nix
Normal file
48
lib/internal/default.nix
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg fix fold filterAttrs;
|
||||||
|
|
||||||
|
core-inputs-libs = snowfall-lib.flake.get-libs (snowfall-lib.flake.without-self core-inputs);
|
||||||
|
user-inputs-libs = snowfall-lib.flake.get-libs (snowfall-lib.flake.without-self user-inputs);
|
||||||
|
|
||||||
|
snowfall-top-level-lib = filterAttrs (name: value: !builtins.isAttrs value) snowfall-lib;
|
||||||
|
|
||||||
|
base-lib = snowfall-lib.attrs.merge-shallow [
|
||||||
|
core-inputs.nixpkgs.lib
|
||||||
|
core-inputs-libs
|
||||||
|
user-inputs-libs
|
||||||
|
snowfall-top-level-lib
|
||||||
|
{ snowfall = snowfall-lib; }
|
||||||
|
];
|
||||||
|
|
||||||
|
user-lib-root = snowfall-lib.fs.get-file "lib";
|
||||||
|
user-lib-modules = snowfall-lib.fs.get-default-nix-files-recursive user-lib-root;
|
||||||
|
|
||||||
|
user-lib = fix (user-lib:
|
||||||
|
let
|
||||||
|
attrs = {
|
||||||
|
inputs = snowfall-lib.flake.without-snowfall-inputs user-inputs;
|
||||||
|
snowfall-inputs = core-inputs;
|
||||||
|
lib = snowfall-lib.attrs.merge-shallow [ base-lib user-lib ];
|
||||||
|
};
|
||||||
|
libs = builtins.map
|
||||||
|
(path: import path attrs)
|
||||||
|
user-lib-modules;
|
||||||
|
in
|
||||||
|
snowfall-lib.attrs.merge-deep libs
|
||||||
|
);
|
||||||
|
|
||||||
|
system-lib = snowfall-lib.attrs.merge-shallow [
|
||||||
|
base-lib
|
||||||
|
user-lib
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
internal = {
|
||||||
|
inherit system-lib;
|
||||||
|
};
|
||||||
|
}
|
||||||
48
lib/module/default.nix
Normal file
48
lib/module/default.nix
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) baseNameOf;
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg foldl;
|
||||||
|
|
||||||
|
user-modules-root = snowfall-lib.fs.get-file "modules";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
module = {
|
||||||
|
# Create flake output modules.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: create-modules { src = ./my-modules; overrides = { inherit another-module; default = "my-module"; }; }
|
||||||
|
# result: { another-module = ...; my-module = ...; default = ...; }
|
||||||
|
create-modules =
|
||||||
|
{ src ? user-modules-root
|
||||||
|
, overrides ? { }
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
user-modules = snowfall-lib.fs.get-default-nix-files-recursive src;
|
||||||
|
create-module-metadata = module: {
|
||||||
|
name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory module);
|
||||||
|
path = module;
|
||||||
|
};
|
||||||
|
modules-metadata = builtins.map create-module-metadata user-modules;
|
||||||
|
merge-modules = modules: metadata:
|
||||||
|
modules // {
|
||||||
|
${metadata.name} = metadata.path;
|
||||||
|
};
|
||||||
|
modules-without-default = foldl merge-modules { } modules-metadata;
|
||||||
|
default-module =
|
||||||
|
if overrides.default or null == null then
|
||||||
|
{ }
|
||||||
|
else if builtins.isAttrs overrides.default then
|
||||||
|
{ default = overrides.default; }
|
||||||
|
else if modules-without-default.${overrides.default} or null != null then
|
||||||
|
{ default = modules-without-default.${overrides.default}; }
|
||||||
|
else
|
||||||
|
{ };
|
||||||
|
overrides-without-default = builtins.removeAttrs overrides [ "default" ];
|
||||||
|
modules = modules-without-default // default-module // overrides-without-default;
|
||||||
|
in
|
||||||
|
modules;
|
||||||
|
};
|
||||||
|
}
|
||||||
43
lib/overlay/default.nix
Normal file
43
lib/overlay/default.nix
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg;
|
||||||
|
|
||||||
|
user-overlays-root = snowfall-lib.fs.get-file "overlays";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
overlay = {
|
||||||
|
# Create a flake-utils-plus overlays builder.
|
||||||
|
# Type: Attrs -> Attrs -> [(a -> b -> c)]
|
||||||
|
# Usage: create-overlays { src = ./my-overlays; overlay-package-namespace = "my-packages"; }
|
||||||
|
# result: (channels: [ ... ])
|
||||||
|
create-overlays =
|
||||||
|
{ src ? user-overlays-root
|
||||||
|
, overlay-package-namespace ? null
|
||||||
|
, extra-overlays ? [ ]
|
||||||
|
}: channels:
|
||||||
|
let
|
||||||
|
user-overlays = snowfall-lib.fs.get-default-nix-files-recursive src;
|
||||||
|
create-overlay = overlay: import overlay (user-inputs // { inherit channels; });
|
||||||
|
user-packages-overlay = final: prev:
|
||||||
|
let
|
||||||
|
user-packages = snowfall-lib.package.create-packages {
|
||||||
|
channels = channels;
|
||||||
|
};
|
||||||
|
user-packages-without-default = builtins.removeAttrs
|
||||||
|
(user-packages) [ "default" ];
|
||||||
|
in
|
||||||
|
if overlay-package-namespace == null then
|
||||||
|
user-packages-without-default
|
||||||
|
else
|
||||||
|
{
|
||||||
|
${overlay-package-namespace} = user-packages-without-default;
|
||||||
|
};
|
||||||
|
overlays = [ user-packages-overlay ] ++ extra-overlays ++ (builtins.map create-overlay user-overlays);
|
||||||
|
in
|
||||||
|
overlays;
|
||||||
|
};
|
||||||
|
}
|
||||||
51
lib/package/default.nix
Normal file
51
lib/package/default.nix
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg foldl;
|
||||||
|
|
||||||
|
user-packages-root = snowfall-lib.fs.get-file "packages";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
package = {
|
||||||
|
# Create flake output packages.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: create-packages { inherit channels; src = ./my-packages; overrides = { inherit another-package; default = "my-package"; }; }
|
||||||
|
# result: { another-package = ...; my-package = ...; default = ...; }
|
||||||
|
create-packages =
|
||||||
|
{ channels
|
||||||
|
, src ? user-packages-root
|
||||||
|
, overrides ? { }
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
user-packages = snowfall-lib.fs.get-default-nix-files-recursive src;
|
||||||
|
create-package-metadata = package: {
|
||||||
|
name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory package);
|
||||||
|
drv = channels.nixpkgs.callPackage package {
|
||||||
|
inherit channels;
|
||||||
|
lib = snowfall-lib.internal.system-lib;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
packages-metadata = builtins.map create-package-metadata user-packages;
|
||||||
|
merge-packages = packages: metadata:
|
||||||
|
packages // {
|
||||||
|
${metadata.name} = metadata.drv;
|
||||||
|
};
|
||||||
|
packages-without-default = foldl merge-packages { } packages-metadata;
|
||||||
|
default-package =
|
||||||
|
if overrides.default or null == null then
|
||||||
|
{ }
|
||||||
|
else if builtins.isAttrs overrides.default then
|
||||||
|
{ default = overrides.default; }
|
||||||
|
else if packages-without-default.${overrides.default} or null != null then
|
||||||
|
{ default = packages-without-default.${overrides.default}; }
|
||||||
|
else
|
||||||
|
{ };
|
||||||
|
overrides-without-default = builtins.removeAttrs overrides [ "default" ];
|
||||||
|
packages = packages-without-default // default-package // overrides-without-default;
|
||||||
|
in
|
||||||
|
packages;
|
||||||
|
};
|
||||||
|
}
|
||||||
77
lib/path/default.nix
Normal file
77
lib/path/default.nix
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) toString baseNameOf dirOf concatStringsSep;
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg last init;
|
||||||
|
|
||||||
|
file-name-regex = "(.*)\\.(.*)$";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
path = rec {
|
||||||
|
# Split a file name and its extension.
|
||||||
|
# Type: String -> [String]
|
||||||
|
# Usage: split-file-extension "my-file.md"
|
||||||
|
# result: [ "my-file" "md" ]
|
||||||
|
split-file-extension = file:
|
||||||
|
let
|
||||||
|
match = builtins.match file-name-regex file;
|
||||||
|
in
|
||||||
|
assert assertMsg (match != null) "lib.snowfall.split-file-extension: File must have an extension to split.";
|
||||||
|
match;
|
||||||
|
|
||||||
|
# Check if a file name has a file extension.
|
||||||
|
# Type: String -> Bool
|
||||||
|
# Usage: has-any-file-extension "my-file.txt"
|
||||||
|
# result: true
|
||||||
|
has-any-file-extension = file:
|
||||||
|
let
|
||||||
|
match = builtins.match file-name-regex (toString file);
|
||||||
|
in
|
||||||
|
match != null;
|
||||||
|
|
||||||
|
# Get the file extension of a file name.
|
||||||
|
# Type: String -> String
|
||||||
|
# Usage: get-file-extension "my-file.final.txt"
|
||||||
|
# result: "txt"
|
||||||
|
get-file-extension = file:
|
||||||
|
if has-any-file-extension file then
|
||||||
|
let
|
||||||
|
match = builtins.match file-name-regex (toString file);
|
||||||
|
in
|
||||||
|
last match
|
||||||
|
else
|
||||||
|
"";
|
||||||
|
|
||||||
|
# Check if a file name has a specific file extension.
|
||||||
|
# Type: String -> String -> Bool
|
||||||
|
# Usage: has-file-extension "txt" "my-file.txt"
|
||||||
|
# result: true
|
||||||
|
has-file-extension = extension: file:
|
||||||
|
if has-any-file-extension file then
|
||||||
|
extension == get-file-extension file
|
||||||
|
else
|
||||||
|
false;
|
||||||
|
|
||||||
|
# Get the parent directory for a given path.
|
||||||
|
# Type: Path -> Path
|
||||||
|
# Usage: get-parent-directory "/a/b/c"
|
||||||
|
# result: "/a/b"
|
||||||
|
get-parent-directory = snowfall-lib.fp.compose baseNameOf dirOf;
|
||||||
|
|
||||||
|
# Get the file name of a path without its extension.
|
||||||
|
# Type: Path -> String
|
||||||
|
# Usage: get-file-name-without-extension ./some-directory/my-file.pdf
|
||||||
|
# result: "my-file"
|
||||||
|
get-file-name-without-extension = path:
|
||||||
|
let
|
||||||
|
file-name = baseNameOf path;
|
||||||
|
in
|
||||||
|
if has-any-file-extension file-name then
|
||||||
|
concatStringsSep "" (init (split-file-extension file-name))
|
||||||
|
else
|
||||||
|
file-name;
|
||||||
|
};
|
||||||
|
}
|
||||||
51
lib/shell/default.nix
Normal file
51
lib/shell/default.nix
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg foldl;
|
||||||
|
|
||||||
|
user-shells-root = snowfall-lib.fs.get-file "shells";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
shell = {
|
||||||
|
# Create flake output packages.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: create-shells { inherit channels; src = ./my-shells; overrides = { inherit another-shell; default = "my-shell"; }; }
|
||||||
|
# result: { another-shell = ...; my-shell = ...; default = ...; }
|
||||||
|
create-shells =
|
||||||
|
{ channels
|
||||||
|
, src ? user-shells-root
|
||||||
|
, overrides ? { }
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
user-shells = snowfall-lib.fs.get-default-nix-files-recursive src;
|
||||||
|
create-shell-metadata = shell:
|
||||||
|
{
|
||||||
|
name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory shell);
|
||||||
|
drv = channels.nixpkgs.callPackage shell {
|
||||||
|
lib = snowfall-lib.internal.system-lib;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
shells-metadata = builtins.map create-shell-metadata user-shells;
|
||||||
|
merge-shells = shells: metadata:
|
||||||
|
shells // {
|
||||||
|
${metadata.name} = metadata.drv;
|
||||||
|
};
|
||||||
|
shells-without-default = foldl merge-shells { } shells-metadata;
|
||||||
|
default-shell =
|
||||||
|
if overrides.default or null == null then
|
||||||
|
{ }
|
||||||
|
else if builtins.isAttrs overrides.default then
|
||||||
|
{ default = overrides.default; }
|
||||||
|
else if shells-without-default.${overrides.default} or null != null then
|
||||||
|
{ default = shells-without-default.${overrides.default}; }
|
||||||
|
else
|
||||||
|
{ };
|
||||||
|
overrides-without-default = builtins.removeAttrs overrides [ "default" ];
|
||||||
|
shells = shells-without-default // default-shell // overrides-without-default;
|
||||||
|
in
|
||||||
|
shells;
|
||||||
|
};
|
||||||
|
}
|
||||||
201
lib/system/default.nix
Normal file
201
lib/system/default.nix
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) dirOf baseNameOf;
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg fix hasInfix concatMap foldl;
|
||||||
|
|
||||||
|
virtual-systems = import ./virtual-systems.nix;
|
||||||
|
|
||||||
|
user-systems-root = snowfall-lib.fs.get-file "systems";
|
||||||
|
user-modules-root = snowfall-lib.fs.get-file "modules";
|
||||||
|
|
||||||
|
get-inferred-system-name = path:
|
||||||
|
if snowfall-lib.path.has-file-extension "nix" path then
|
||||||
|
snowfall-lib.path.get-parent-directory path
|
||||||
|
else
|
||||||
|
baseNameOf path;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
system = rec {
|
||||||
|
# Check whether a named system is macOS.
|
||||||
|
# Type: String -> Bool
|
||||||
|
# Usage: is-darwin "x86_64-linux"
|
||||||
|
# result: false
|
||||||
|
is-darwin = hasInfix "darwin";
|
||||||
|
|
||||||
|
# Check whether a named system is Linux.
|
||||||
|
# Type: String -> Bool
|
||||||
|
# Usage: is-linux "x86_64-linux"
|
||||||
|
# result: false
|
||||||
|
is-linux = hasInfix "linux";
|
||||||
|
|
||||||
|
# Get the virtual system type of a system target.
|
||||||
|
# Type: String -> String
|
||||||
|
# Usage: get-virtual-system-type "x86_64-iso"
|
||||||
|
# result: "iso"
|
||||||
|
get-virtual-system-type = target:
|
||||||
|
foldl
|
||||||
|
(result: virtual-system:
|
||||||
|
if result == "" && hasInfix virtual-system target then
|
||||||
|
virtual-system
|
||||||
|
else
|
||||||
|
result
|
||||||
|
)
|
||||||
|
""
|
||||||
|
virtual-systems;
|
||||||
|
|
||||||
|
# Get structured data about all systems for a given target.
|
||||||
|
# Type: String -> [Attrs]
|
||||||
|
# Usage: get-target-systems-metadata "x86_64-linux"
|
||||||
|
# result: [ { target = "x86_64-linux"; name = "my-machine"; path = "/systems/x86_64-linux/my-machine"; } ]
|
||||||
|
get-target-systems-metadata = target:
|
||||||
|
let
|
||||||
|
systems = snowfall-lib.fs.get-directories target;
|
||||||
|
existing-systems = builtins.filter (system: builtins.pathExists "${system}/default.nix") systems;
|
||||||
|
create-system-metadata = path: {
|
||||||
|
path = "${path}/default.nix";
|
||||||
|
# We are building flake outputs based on file contents. Nix doesn't like this
|
||||||
|
# so we have to explicitly discard the string's path context to allow us to
|
||||||
|
# use the name as a variable.
|
||||||
|
name = builtins.unsafeDiscardStringContext (builtins.baseNameOf path);
|
||||||
|
# We are building flake outputs based on file contents. Nix doesn't like this
|
||||||
|
# so we have to explicitly discard the string's path context to allow us to
|
||||||
|
# use the name as a variable.
|
||||||
|
target = builtins.unsafeDiscardStringContext (builtins.baseNameOf target);
|
||||||
|
};
|
||||||
|
system-configurations = builtins.map create-system-metadata existing-systems;
|
||||||
|
in
|
||||||
|
system-configurations;
|
||||||
|
|
||||||
|
# Get the system builder for a given target.
|
||||||
|
# Type: String -> Function
|
||||||
|
# Usage: get-system-builder "x86_64-iso"
|
||||||
|
# result: (args: <system>)
|
||||||
|
get-system-builder = target:
|
||||||
|
let
|
||||||
|
virtual-system-type = get-virtual-system-type target;
|
||||||
|
virtual-system-builder = args:
|
||||||
|
assert (assertMsg (user-inputs ? nixos-generators) "In order to create virtual systems, you must include `nixos-generators` as a flake input.");
|
||||||
|
user-inputs.nixos-generators.nixosGenerate
|
||||||
|
(args // {
|
||||||
|
format = virtual-system-type;
|
||||||
|
specialArgs = args.specialArgs // {
|
||||||
|
format = virtual-system-type;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
darwin-system-builder = args:
|
||||||
|
assert (assertMsg (user-inputs ? darwin) "In order to create virtual systems, you must include `darwin` as a flake input.");
|
||||||
|
user-inputs.darwin.lib.darwinSystem ((builtins.removeAttrs args [ "system" ]) // {
|
||||||
|
specialArgs = args.specialArgs // {
|
||||||
|
format = "darwin";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
linux-system-builder = args:
|
||||||
|
core-inputs.nixpkgs.lib.nixosSystem
|
||||||
|
(args // {
|
||||||
|
specialArgs = args.specialArgs // {
|
||||||
|
format = "linux";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
in
|
||||||
|
if virtual-system-type != "" then
|
||||||
|
virtual-system-builder
|
||||||
|
else if is-darwin target then
|
||||||
|
darwin-system-builder
|
||||||
|
else
|
||||||
|
linux-system-builder;
|
||||||
|
|
||||||
|
# Get the flake output attribute for a system target.
|
||||||
|
# Type: String -> String
|
||||||
|
# Usage: get-system-output "aarch64-darwin"
|
||||||
|
# result: "darwinConfigurations"
|
||||||
|
get-system-output = target:
|
||||||
|
let
|
||||||
|
virtual-system-type = get-virtual-system-type target;
|
||||||
|
in
|
||||||
|
if virtual-system-type != "" then
|
||||||
|
"${virtual-system-type}Configurations"
|
||||||
|
else if is-darwin target then
|
||||||
|
"darwinConfigurations"
|
||||||
|
else
|
||||||
|
"nixosConfigurations";
|
||||||
|
|
||||||
|
# Get the resolved (non-virtual) system target.
|
||||||
|
# Type: String -> String
|
||||||
|
# Usage: get-resolved-system-target "x86_64-iso"
|
||||||
|
# result: "x86_64-linux"
|
||||||
|
get-resolved-system-target = target:
|
||||||
|
let
|
||||||
|
virtual-system-type = get-virtual-system-type target;
|
||||||
|
in
|
||||||
|
if virtual-system-type != "" then
|
||||||
|
builtins.replaceStrings [ virtual-system-type ] [ "linux" ] target
|
||||||
|
else
|
||||||
|
target;
|
||||||
|
|
||||||
|
# Create a system.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: create-system { path = ./systems/my-system; }
|
||||||
|
# result: <flake-utils-plus-system-configuration>
|
||||||
|
create-system =
|
||||||
|
{ target ? "x86_64-linux"
|
||||||
|
, system ? get-resolved-system-target target
|
||||||
|
, path
|
||||||
|
, name ? builtins.unsafeDiscardStringContext (get-inferred-system-name path)
|
||||||
|
, modules ? [ ]
|
||||||
|
, specialArgs ? { }
|
||||||
|
, channelName ? "nixpkgs"
|
||||||
|
, builder ? get-system-builder target
|
||||||
|
, output ? get-system-output target
|
||||||
|
, systems ? { }
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
lib = snowfall-lib.internal.system-lib;
|
||||||
|
in
|
||||||
|
# (lib.traceSeqN 1 path)
|
||||||
|
{
|
||||||
|
inherit channelName system builder output;
|
||||||
|
|
||||||
|
modules = [ path ] ++ modules;
|
||||||
|
|
||||||
|
specialArgs = specialArgs // {
|
||||||
|
inherit system name systems lib;
|
||||||
|
|
||||||
|
inputs = snowfall-lib.flake.without-src user-inputs;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Create all available systems.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: create-systems { hosts.my-host.specialArgs.x = true; modules = [ my-shared-module ]; }
|
||||||
|
# result: { my-host = <flake-utils-plus-system-configuration>; }
|
||||||
|
create-systems = systems:
|
||||||
|
let
|
||||||
|
targets = snowfall-lib.fs.get-directories user-systems-root;
|
||||||
|
target-systems-metadata = concatMap get-target-systems-metadata targets;
|
||||||
|
user-modules = snowfall-lib.fs.get-default-nix-files-recursive user-modules-root;
|
||||||
|
create-system' = created-systems: system-metadata:
|
||||||
|
let
|
||||||
|
overrides = systems.hosts.${system-metadata.name} or { };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
${system-metadata.name} = create-system (overrides // system-metadata // {
|
||||||
|
systems = created-systems;
|
||||||
|
modules = user-modules ++ (overrides.modules or [ ]) ++ (systems.modules or [ ]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
created-systems = fix (created-systems:
|
||||||
|
foldl
|
||||||
|
(systems: system-metadata:
|
||||||
|
systems // (create-system' created-systems system-metadata)
|
||||||
|
)
|
||||||
|
{ }
|
||||||
|
target-systems-metadata
|
||||||
|
);
|
||||||
|
in
|
||||||
|
created-systems;
|
||||||
|
};
|
||||||
|
}
|
||||||
34
lib/system/virtual-systems.nix
Normal file
34
lib/system/virtual-systems.nix
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# @NOTE(jakehamilton): The order of these entries matters. We search them
|
||||||
|
# from start to finish and only match based on whether they appear in a
|
||||||
|
# system target. This means that entries like "vm" would match all cases
|
||||||
|
# of "vm-bootloader", "vm-no-gui", and "vmware". To avoid this mismatch,
|
||||||
|
# entries should be ordered from most-specific to least-specific.
|
||||||
|
[
|
||||||
|
"amazon"
|
||||||
|
"azure"
|
||||||
|
"cloudstack"
|
||||||
|
"do"
|
||||||
|
"gce"
|
||||||
|
"hyperv"
|
||||||
|
"install-iso-hyperv"
|
||||||
|
"install-iso"
|
||||||
|
"iso"
|
||||||
|
"kexec"
|
||||||
|
"kexec-bundle"
|
||||||
|
"kubevirt"
|
||||||
|
"lxc-metadata"
|
||||||
|
"lxc"
|
||||||
|
"openstack"
|
||||||
|
"proxmox"
|
||||||
|
"qcow"
|
||||||
|
"raw"
|
||||||
|
"raw-efi"
|
||||||
|
"sd-aarch64-installer"
|
||||||
|
"sd-aarch64"
|
||||||
|
"vagrant-virtualbox"
|
||||||
|
"virtualbox"
|
||||||
|
"vm-bootloader"
|
||||||
|
"vm-nogui"
|
||||||
|
"vmware"
|
||||||
|
"vm"
|
||||||
|
]
|
||||||
50
lib/template/default.nix
Normal file
50
lib/template/default.nix
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{ core-inputs
|
||||||
|
, user-inputs
|
||||||
|
, snowfall-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) baseNameOf;
|
||||||
|
inherit (core-inputs.nixpkgs.lib) assertMsg foldl;
|
||||||
|
|
||||||
|
user-templates-root = snowfall-lib.fs.get-file "templates";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
template = {
|
||||||
|
# Create flake templates.
|
||||||
|
# Type: Attrs -> Attrs
|
||||||
|
# Usage: create-templates { src = ./my-templates; overrides = { inherit another-template; default = "my-template"; }; }
|
||||||
|
# result: { another-template = ...; my-template = ...; default = ...; }
|
||||||
|
create-templates =
|
||||||
|
{ src ? user-templates-root
|
||||||
|
, overrides ? { }
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
user-templates = snowfall-lib.fs.get-directories src;
|
||||||
|
create-template-metadata = template: {
|
||||||
|
name = builtins.unsafeDiscardStringContext (baseNameOf template);
|
||||||
|
path = template;
|
||||||
|
};
|
||||||
|
templates-metadata = builtins.map create-template-metadata user-templates;
|
||||||
|
merge-templates = templates: metadata:
|
||||||
|
templates // {
|
||||||
|
${metadata.name} = (overrides.${metadata.name} or { }) // {
|
||||||
|
inherit (metadata) path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
templates-without-default = foldl merge-templates { } templates-metadata;
|
||||||
|
default-template =
|
||||||
|
if overrides.default or null == null then
|
||||||
|
{ }
|
||||||
|
else if builtins.isAttrs overrides.default then
|
||||||
|
{ default = overrides.default; }
|
||||||
|
else if templates-without-default.${overrides.default} or null != null then
|
||||||
|
{ default = templates-without-default.${overrides.default}; }
|
||||||
|
else
|
||||||
|
{ };
|
||||||
|
overrides-without-default = builtins.removeAttrs overrides [ "default" ];
|
||||||
|
templates = templates-without-default // default-template // overrides-without-default;
|
||||||
|
in
|
||||||
|
templates;
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue