diff --git a/default.nix b/default.nix index c7d0c26..6466507 100644 --- a/default.nix +++ b/default.nix @@ -1,14 +1,9 @@ -( - 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 +(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 diff --git a/flake.nix b/flake.nix index fe0a4f2..2ba5b26 100644 --- a/flake.nix +++ b/flake.nix @@ -11,89 +11,92 @@ }; }; - outputs = { - self, - ... - } @ inputs: let - core-inputs = - inputs - // { - src = self; - }; - - # 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 ./snowfall-lib core-inputs; - - # A convenience wrapper to create the library and then call `lib.mkFlake`. - # Usage: mkFlake { inherit inputs; src = ./.; ... } - # result: - mkFlake = flake-and-lib-options @ { - inputs, - src, - snowfall ? {}, + outputs = + { + self, ... - }: let - lib = mkLib { - inherit inputs src snowfall; - }; - flake-options = builtins.removeAttrs flake-and-lib-options ["inputs" "src"]; - in - lib.mkFlake flake-options; - in { - inherit mkLib mkFlake; - - nixosModules = { - user = ./modules/nixos/user/default.nix; - }; - - darwinModules = { - user = ./modules/darwin/user/default.nix; - }; - - homeModules = { - user = ./modules/home/user/default.nix; - }; - - formatter = { - x86_64-linux = inputs.nixpkgs.legacyPackages.x86_64-linux.nixfmt-tree; - aarch64-linux = inputs.nixpkgs.legacyPackages.aarch64-linux.nixfmt-tree; - x86_64-darwin = inputs.nixpkgs.legacyPackages.x86_64-darwin.nixfmt-tree; - aarch64-darwin = inputs.nixpkgs.legacyPackages.aarch64-darwin.nixfmt-tree; - }; - - snowfall = rec { - raw-config = config; - - config = { - root = self; + }@inputs: + let + core-inputs = inputs // { src = self; - namespace = "snowfall"; - lib-dir = "snowfall-lib"; - - meta = { - name = "snowfall-lib"; - title = "Snowfall Lib"; - }; }; - internal-lib = let - lib = mkLib { - src = self; + # 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 ./snowfall-lib core-inputs; - inputs = - inputs - // { - self = {}; - }; + # A convenience wrapper to create the library and then call `lib.mkFlake`. + # Usage: mkFlake { inherit inputs; src = ./.; ... } + # result: + mkFlake = + flake-and-lib-options@{ + inputs, + src, + snowfall ? { }, + ... + }: + let + lib = mkLib { + inherit inputs src snowfall; + }; + flake-options = builtins.removeAttrs flake-and-lib-options [ + "inputs" + "src" + ]; + in + lib.mkFlake flake-options; + in + { + inherit mkLib mkFlake; + + nixosModules = { + user = ./modules/nixos/user/default.nix; + }; + + darwinModules = { + user = ./modules/darwin/user/default.nix; + }; + + homeModules = { + user = ./modules/home/user/default.nix; + }; + + formatter = { + x86_64-linux = inputs.nixpkgs.legacyPackages.x86_64-linux.nixfmt-tree; + aarch64-linux = inputs.nixpkgs.legacyPackages.aarch64-linux.nixfmt-tree; + x86_64-darwin = inputs.nixpkgs.legacyPackages.x86_64-darwin.nixfmt-tree; + aarch64-darwin = inputs.nixpkgs.legacyPackages.aarch64-darwin.nixfmt-tree; + }; + + snowfall = rec { + raw-config = config; + + config = { + root = self; + src = self; + namespace = "snowfall"; + lib-dir = "snowfall-lib"; + + meta = { + name = "snowfall-lib"; + title = "Snowfall Lib"; + }; }; - in - builtins.removeAttrs - lib.snowfall - ["internal"]; + + internal-lib = + let + lib = mkLib { + src = self; + + inputs = inputs // { + self = { }; + }; + }; + in + builtins.removeAttrs lib.snowfall [ "internal" ]; + }; }; - }; } diff --git a/modules/darwin/user/default.nix b/modules/darwin/user/default.nix index dd9daa0..72f95db 100644 --- a/modules/darwin/user/default.nix +++ b/modules/darwin/user/default.nix @@ -5,9 +5,9 @@ config, inputs, ... -}: let - inherit - (lib) +}: +let + inherit (lib) types mkOption mkDefault @@ -20,9 +20,11 @@ user-names = builtins.attrNames cfg.users; - create-system-users = system-users: name: let - user = cfg.users.${name}; - in + create-system-users = + system-users: name: + let + user = cfg.users.${name}; + in system-users // (optionalAttrs user.create { ${name} = { @@ -30,77 +32,84 @@ isHidden = mkDefault false; }; }); -in { +in +{ imports = [ - (mkRenamedOptionModule ["snowfallorg" "user"] ["snowfallorg" "users"]) + (mkRenamedOptionModule [ "snowfallorg" "user" ] [ "snowfallorg" "users" ]) ]; options.snowfallorg = { users = mkOption { description = "User configuration."; - default = {}; - type = types.attrsOf (types.submodule ({name, ...}: { - options = { - create = mkOption { - description = "Whether to create the user automatically."; - type = types.bool; - default = true; - }; + default = { }; + type = types.attrsOf ( + types.submodule ( + { name, ... }: + { + options = { + create = mkOption { + description = "Whether to create the user automatically."; + type = types.bool; + default = true; + }; - home = { - enable = mkOption { - type = types.bool; - default = true; - }; + home = { + enable = mkOption { + type = types.bool; + default = true; + }; - path = mkOption { - type = types.str; - default = "/Users/${name}"; - }; + path = mkOption { + type = types.str; + default = "/Users/${name}"; + }; - config = mkOption { - # HM-compatible options taken from: - # https://github.com/nix-community/home-manager/blob/0ee5ab611dc1fbb5180bd7d88d2aeb7841a4d179/nixos/common.nix#L14 - type = types.submoduleWith { - specialArgs = - { - osConfig = config; - modulesPath = "${inputs.home-manager}/modules"; - } - // config.home-manager.extraSpecialArgs; - modules = - [ - ({ - lib, - modulesPath, - ... - }: { - imports = import "${modulesPath}/modules.nix" { - inherit pkgs lib; - useNixpkgsModule = !config.home-manager.useGlobalPkgs; - }; + config = mkOption { + # HM-compatible options taken from: + # https://github.com/nix-community/home-manager/blob/0ee5ab611dc1fbb5180bd7d88d2aeb7841a4d179/nixos/common.nix#L14 + type = types.submoduleWith { + specialArgs = { + osConfig = config; + modulesPath = "${inputs.home-manager}/modules"; + } + // config.home-manager.extraSpecialArgs; + modules = [ + ( + { + lib, + modulesPath, + ... + }: + { + imports = import "${modulesPath}/modules.nix" { + inherit pkgs lib; + useNixpkgsModule = !config.home-manager.useGlobalPkgs; + }; - config = { - submoduleSupport.enable = true; - submoduleSupport.externalPackageInstall = config.home-manager.useUserPackages; + config = { + submoduleSupport.enable = true; + submoduleSupport.externalPackageInstall = config.home-manager.useUserPackages; - home.username = config.users.users.${name}.name; - home.homeDirectory = config.users.users.${name}.home; + home.username = config.users.users.${name}.name; + home.homeDirectory = config.users.users.${name}.home; - nix.package = config.nix.package; - }; - }) - ] - ++ config.home-manager.sharedModules; + nix.package = config.nix.package; + }; + } + ) + ] + ++ config.home-manager.sharedModules; + }; + }; }; }; - }; - }; - })); + } + ) + ); }; }; config = { - users.users = foldl create-system-users {} user-names; + users.users = foldl create-system-users { } user-names; }; } diff --git a/modules/home/user/default.nix b/modules/home/user/default.nix index 49332fd..e0cf299 100644 --- a/modules/home/user/default.nix +++ b/modules/home/user/default.nix @@ -1,11 +1,17 @@ -inputs @ { +inputs@{ pkgs, lib, options, config, ... -}: let - inherit (lib) types mkOption mkIf mkDefault; +}: +let + inherit (lib) + types + mkOption + mkIf + mkDefault + ; cfg = config.snowfallorg; @@ -16,12 +22,14 @@ inputs @ { has-user-name = (cfg.user.name or null) != null; default-home-directory = - if (os-user-home != null) - then os-user-home - else if pkgs.stdenv.isDarwin - then "/Users/${cfg.user.name}" - else "/home/${cfg.user.name}"; -in { + if (os-user-home != null) then + os-user-home + else if pkgs.stdenv.isDarwin then + "/Users/${cfg.user.name}" + else + "/home/${cfg.user.name}"; +in +{ options.snowfallorg = { user = { enable = mkOption { diff --git a/modules/nixos/user/default.nix b/modules/nixos/user/default.nix index bfb8863..3174dcc 100644 --- a/modules/nixos/user/default.nix +++ b/modules/nixos/user/default.nix @@ -1,12 +1,12 @@ -args @ { +args@{ pkgs, lib, options, config, ... -}: let - inherit - (lib) +}: +let + inherit (lib) types mkOption mkDefault @@ -18,13 +18,15 @@ args @ { cfg = config.snowfallorg; - inputs = args.inputs or {}; + inputs = args.inputs or { }; user-names = builtins.attrNames cfg.users; - create-system-users = system-users: name: let - user = cfg.users.${name}; - in + create-system-users = + system-users: name: + let + user = cfg.users.${name}; + in system-users // (optionalAttrs user.create { ${name} = { @@ -38,88 +40,95 @@ args @ { extraGroups = optional user.admin "wheel"; }; }); -in { +in +{ imports = [ - (mkRenamedOptionModule ["snowfallorg" "user"] ["snowfallorg" "users"]) + (mkRenamedOptionModule [ "snowfallorg" "user" ] [ "snowfallorg" "users" ]) ]; options.snowfallorg = { users = mkOption { description = "User configuration."; - default = {}; - type = types.attrsOf (types.submodule ({name, ...}: { - options = { - create = mkOption { - description = "Whether to create the user automatically."; - type = types.bool; - default = true; - }; + default = { }; + type = types.attrsOf ( + types.submodule ( + { name, ... }: + { + options = { + create = mkOption { + description = "Whether to create the user automatically."; + type = types.bool; + default = true; + }; - admin = mkOption { - description = "Whether the user should be added to the wheel group."; - type = types.bool; - default = true; - }; + admin = mkOption { + description = "Whether the user should be added to the wheel group."; + type = types.bool; + default = true; + }; - home = { - enable = mkOption { - type = types.bool; - default = true; - }; + home = { + enable = mkOption { + type = types.bool; + default = true; + }; - path = mkOption { - type = types.str; - default = "/home/${name}"; - }; + path = mkOption { + type = types.str; + default = "/home/${name}"; + }; - config = mkOption { - # HM-compatible options taken from: - # https://github.com/nix-community/home-manager/blob/0ee5ab611dc1fbb5180bd7d88d2aeb7841a4d179/nixos/common.nix#L14 - # NOTE: This has been adapted to support documentation generation without - # having home-manager options fully declared. - type = types.submoduleWith { - specialArgs = - { - osConfig = config; - modulesPath = "${inputs.home-manager or "/"}/modules"; - } - // (config.home-manager.extraSpecialArgs or {}); - modules = - [ - ({ - lib, - modulesPath, - ... - }: - if inputs ? home-manager - then { - imports = import "${modulesPath}/modules.nix" { - inherit pkgs lib; - useNixpkgsModule = !(config.home-manager.useGlobalPkgs or false); - }; + config = mkOption { + # HM-compatible options taken from: + # https://github.com/nix-community/home-manager/blob/0ee5ab611dc1fbb5180bd7d88d2aeb7841a4d179/nixos/common.nix#L14 + # NOTE: This has been adapted to support documentation generation without + # having home-manager options fully declared. + type = types.submoduleWith { + specialArgs = { + osConfig = config; + modulesPath = "${inputs.home-manager or "/"}/modules"; + } + // (config.home-manager.extraSpecialArgs or { }); + modules = [ + ( + { + lib, + modulesPath, + ... + }: + if inputs ? home-manager then + { + imports = import "${modulesPath}/modules.nix" { + inherit pkgs lib; + useNixpkgsModule = !(config.home-manager.useGlobalPkgs or false); + }; - config = { - submoduleSupport.enable = true; - submoduleSupport.externalPackageInstall = config.home-manager.useUserPackages; + config = { + submoduleSupport.enable = true; + submoduleSupport.externalPackageInstall = config.home-manager.useUserPackages; - home.username = config.users.users.${name}.name; - home.homeDirectory = config.users.users.${name}.home; + home.username = config.users.users.${name}.name; + home.homeDirectory = config.users.users.${name}.home; - nix.package = config.nix.package; - }; - } - else {}) - ] - ++ (config.home-manager.sharedModules or []); + nix.package = config.nix.package; + }; + } + else + { } + ) + ] + ++ (config.home-manager.sharedModules or [ ]); + }; + }; }; }; - }; - }; - })); + } + ) + ); }; }; config = { - users.users = foldl create-system-users {} user-names; + users.users = foldl create-system-users { } user-names; }; } diff --git a/snowfall-lib/attrs/default.nix b/snowfall-lib/attrs/default.nix index 2f7e0bd..8c91ed2 100644 --- a/snowfall-lib/attrs/default.nix +++ b/snowfall-lib/attrs/default.nix @@ -3,9 +3,9 @@ user-inputs, snowfall-lib, snowfall-config, -}: let - inherit - (core-inputs.nixpkgs.lib) +}: +let + inherit (core-inputs.nixpkgs.lib) assertMsg mapAttrsToList mapAttrs @@ -15,7 +15,8 @@ mergeAttrs isDerivation ; -in { +in +{ attrs = { ## Map and flatten an attribute set into a list. ## Example Usage: @@ -27,8 +28,7 @@ in { ## [ "x" 1 "y" 2 ] ## ``` #@ (a -> b -> [c]) -> Attrs -> [c] - map-concat-attrs-to-list = f: attrs: - flatten (mapAttrsToList f attrs); + map-concat-attrs-to-list = f: attrs: flatten (mapAttrsToList f attrs); ## Recursively merge a list of attribute sets. ## Example Usage: @@ -40,7 +40,7 @@ in { ## { x = 2; } ## ``` #@ [Attrs] -> Attrs - merge-deep = foldl recursiveUpdate {}; + merge-deep = foldl recursiveUpdate { }; ## Merge the root of a list of attribute sets. ## Example Usage: @@ -52,7 +52,7 @@ in { ## { x = 2; } ## ``` #@ [Attrs] -> Attrs - merge-shallow = foldl mergeAttrs {}; + merge-shallow = foldl mergeAttrs { }; ## Merge shallow for packages, but allow one deeper layer of attribute sets. ## Example Usage: @@ -64,23 +64,20 @@ in { ## { vim = ...; some.value = false; } ## ``` #@ [Attrs] -> Attrs - merge-shallow-packages = items: - foldl - ( + merge-shallow-packages = + items: + foldl ( result: item: - result - // (mapAttrs - ( - name: value: - if isDerivation value - then value - else if builtins.isAttrs value - then (result.${name} or {}) // value - else value - ) - item) - ) - {} - items; + result + // (mapAttrs ( + name: value: + if isDerivation value then + value + else if builtins.isAttrs value then + (result.${name} or { }) // value + else + value + ) item) + ) { } items; }; } diff --git a/snowfall-lib/checks/default.nix b/snowfall-lib/checks/default.nix index cf6e844..000c486 100644 --- a/snowfall-lib/checks/default.nix +++ b/snowfall-lib/checks/default.nix @@ -3,12 +3,19 @@ user-inputs, snowfall-lib, snowfall-config, -}: let +}: +let inherit (core-inputs.flake-utils-plus.lib) filterPackages; - inherit (core-inputs.nixpkgs.lib) assertMsg foldl mapAttrs callPackageWith; + inherit (core-inputs.nixpkgs.lib) + assertMsg + foldl + mapAttrs + callPackageWith + ; user-checks-root = snowfall-lib.fs.get-snowfall-file "checks"; -in { +in +{ check = { ## Create flake output packages. ## Example Usage: @@ -20,37 +27,41 @@ in { ## { another-check = ...; my-check = ...; default = ...; } ## ``` #@ Attrs -> Attrs - create-checks = { - channels, - src ? user-checks-root, - pkgs ? channels.nixpkgs, - overrides ? {}, - alias ? {}, - }: let - user-checks = snowfall-lib.fs.get-default-nix-files-recursive src; - create-check-metadata = check: let - extra-inputs = - pkgs - // { - inherit channels; - lib = snowfall-lib.internal.system-lib; - inputs = snowfall-lib.flake.without-src user-inputs; - namespace = snowfall-config.namespace; + create-checks = + { + channels, + src ? user-checks-root, + pkgs ? channels.nixpkgs, + overrides ? { }, + alias ? { }, + }: + let + user-checks = snowfall-lib.fs.get-default-nix-files-recursive src; + create-check-metadata = + check: + let + extra-inputs = pkgs // { + inherit channels; + lib = snowfall-lib.internal.system-lib; + inputs = snowfall-lib.flake.without-src user-inputs; + namespace = snowfall-config.namespace; + }; + in + { + name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory check); + drv = callPackageWith extra-inputs check { }; }; - in { - name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory check); - drv = callPackageWith extra-inputs check {}; - }; - checks-metadata = builtins.map create-check-metadata user-checks; - merge-checks = checks: metadata: - checks - // { - ${metadata.name} = metadata.drv; - }; - checks-without-aliases = foldl merge-checks {} checks-metadata; - aliased-checks = mapAttrs (name: value: checks-without-aliases.${value}) alias; - checks = checks-without-aliases // aliased-checks // overrides; - in + checks-metadata = builtins.map create-check-metadata user-checks; + merge-checks = + checks: metadata: + checks + // { + ${metadata.name} = metadata.drv; + }; + checks-without-aliases = foldl merge-checks { } checks-metadata; + aliased-checks = mapAttrs (name: value: checks-without-aliases.${value}) alias; + checks = checks-without-aliases // aliased-checks // overrides; + in filterPackages pkgs.stdenv.hostPlatform.system checks; }; } diff --git a/snowfall-lib/default.nix b/snowfall-lib/default.nix index aa0d199..78061f7 100644 --- a/snowfall-lib/default.nix +++ b/snowfall-lib/default.nix @@ -2,35 +2,45 @@ # 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 - raw-snowfall-config = user-options.snowfall or {}; - snowfall-config = - raw-snowfall-config - // { - src = user-options.src; - root = raw-snowfall-config.root or user-options.src; - namespace = raw-snowfall-config.namespace or "internal"; - meta = { - name = raw-snowfall-config.meta.name or null; - title = raw-snowfall-config.meta.title or null; - }; +core-inputs: user-options: +let + raw-snowfall-config = user-options.snowfall or { }; + snowfall-config = raw-snowfall-config // { + src = user-options.src; + root = raw-snowfall-config.root or user-options.src; + namespace = raw-snowfall-config.namespace or "internal"; + meta = { + name = raw-snowfall-config.meta.name or null; + title = raw-snowfall-config.meta.title or null; }; + }; - user-inputs = user-options.inputs // {src = user-options.src;}; + user-inputs = user-options.inputs // { + src = user-options.src; + }; - inherit (core-inputs.nixpkgs.lib) assertMsg fix filterAttrs mergeAttrs fold recursiveUpdate callPackageWith isFunction; + inherit (core-inputs.nixpkgs.lib) + assertMsg + fix + filterAttrs + mergeAttrs + fold + recursiveUpdate + callPackageWith + isFunction + ; # 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-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 {}; + 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` @@ -38,22 +48,20 @@ core-inputs: user-options: let # 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 + 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"]; + 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); @@ -61,24 +69,28 @@ core-inputs: user-options: let # NOTE: This root is different to accommodate the creation # of a fake user-lib in order to run documentation on this flake. snowfall-lib-root = "${core-inputs.src}/snowfall-lib"; - snowfall-lib-dirs = let - files = builtins.readDir snowfall-lib-root; - dirs = filterAttrs (name: kind: kind == "directory") files; - names = builtins.attrNames dirs; - in + 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 + snowfall-lib: + let attrs = { - inherit snowfall-lib snowfall-config core-inputs user-inputs; + inherit + snowfall-lib + snowfall-config + core-inputs + user-inputs + ; }; - libs = - builtins.map - (dir: import "${snowfall-lib-root}/${dir}" attrs) - snowfall-lib-dirs; + libs = builtins.map (dir: import "${snowfall-lib-root}/${dir}" attrs) snowfall-lib-dirs; in - merge-deep libs + merge-deep libs ); snowfall-top-level-lib = filterAttrs (name: value: !builtins.isAttrs value) snowfall-lib; @@ -88,34 +100,37 @@ core-inputs: user-options: let core-inputs-libs user-inputs-libs snowfall-top-level-lib - {snowfall = snowfall-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 + user-lib: + let attrs = { inherit (user-options) inputs; snowfall-inputs = core-inputs; namespace = snowfall-config.namespace; - lib = merge-shallow [base-lib {${snowfall-config.namespace} = user-lib;}]; + lib = merge-shallow [ + base-lib + { ${snowfall-config.namespace} = user-lib; } + ]; }; - libs = - builtins.map - ( - path: let - imported-module = import path; - in - if isFunction imported-module - then callPackageWith attrs path {} - # the only difference is that there is no `override` and `overrideDerivation` on returned value - else imported-module - ) - user-lib-modules; + libs = builtins.map ( + path: + let + imported-module = import path; + in + if isFunction imported-module then + callPackageWith attrs path { } + # the only difference is that there is no `override` and `overrideDerivation` on returned value + else + imported-module + ) user-lib-modules; in - merge-deep libs + merge-deep libs ); lib = merge-deep [ @@ -126,5 +141,6 @@ core-inputs: user-options: let 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 +assert (assertMsg user-inputs-has-self "Missing attribute `self` for mkLib."); +assert (assertMsg user-inputs-has-src "Missing attribute `src` for mkLib."); +lib diff --git a/snowfall-lib/flake/default.nix b/snowfall-lib/flake/default.nix index b0c7a21..465891d 100644 --- a/snowfall-lib/flake/default.nix +++ b/snowfall-lib/flake/default.nix @@ -3,9 +3,22 @@ user-inputs, snowfall-lib, snowfall-config, -}: let - inherit (core-inputs.nixpkgs.lib) assertMsg foldl filterAttrs const mapAttrs mapAttrs' hasSuffix removeSuffix nameValuePair traceVal; -in rec { +}: +let + inherit (core-inputs.nixpkgs.lib) + assertMsg + foldl + filterAttrs + const + mapAttrs + mapAttrs' + hasSuffix + removeSuffix + nameValuePair + traceVal + ; +in +rec { flake = rec { ## Remove the `self` attribute from an attribute set. ## Example Usage: @@ -17,7 +30,7 @@ in rec { ## { x = true; } ## ``` #@ Attrs -> Attrs - without-self = flake-inputs: builtins.removeAttrs flake-inputs ["self"]; + without-self = flake-inputs: builtins.removeAttrs flake-inputs [ "self" ]; ## Remove the `src` attribute from an attribute set. ## Example Usage: @@ -29,7 +42,7 @@ in rec { ## { x = true; } ## ``` #@ Attrs -> Attrs - without-src = flake-inputs: builtins.removeAttrs flake-inputs ["src"]; + without-src = flake-inputs: builtins.removeAttrs flake-inputs [ "src" ]; ## Remove the `src` and `self` attributes from an attribute set. ## Example Usage: @@ -53,10 +66,9 @@ in rec { ## { x = true; } ## ``` #@ Attrs -> Attrs - without-snowfall-options = flake-options: - builtins.removeAttrs - flake-options - [ + without-snowfall-options = + flake-options: + builtins.removeAttrs flake-options [ "systems" "modules" "overlays" @@ -83,86 +95,91 @@ in rec { ## { x = nixpkgs.lib; } ## ``` #@ Attrs -> Attrs - 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 + 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 - namespace = snowfall-config.namespace or "internal"; - custom-flake-options = flake.without-snowfall-options full-flake-options; - alias = full-flake-options.alias or {}; - homes = snowfall-lib.home.create-homes (full-flake-options.homes or {}); - systems = snowfall-lib.system.create-systems { - systems = full-flake-options.systems or {}; - homes = full-flake-options.homes or {}; - }; - hosts = snowfall-lib.attrs.merge-shallow [(full-flake-options.systems.hosts or {}) systems homes]; - templates = snowfall-lib.template.create-templates { - overrides = full-flake-options.templates or {}; - alias = alias.templates or {}; - }; - nixos-modules = snowfall-lib.module.create-modules { - src = snowfall-lib.fs.get-snowfall-file "modules/nixos"; - overrides = full-flake-options.modules.nixos or {}; - alias = alias.modules.nixos or {}; - }; - darwin-modules = snowfall-lib.module.create-modules { - src = snowfall-lib.fs.get-snowfall-file "modules/darwin"; - overrides = full-flake-options.modules.darwin or {}; - alias = alias.modules.darwin or {}; - }; - home-modules = snowfall-lib.module.create-modules { - src = snowfall-lib.fs.get-snowfall-file "modules/home"; - overrides = full-flake-options.modules.home or {}; - alias = alias.modules.home or {}; - }; - overlays = snowfall-lib.overlay.create-overlays { - inherit namespace; - extra-overlays = full-flake-options.extra-exported-overlays or {}; - }; - channels = full-flake-options.channels 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 namespace; - overrides = (full-flake-options.packages or {}) // (user-outputs.packages or {}); - alias = alias.packages or {}; + mkFlake = + full-flake-options: + let + namespace = snowfall-config.namespace or "internal"; + custom-flake-options = flake.without-snowfall-options full-flake-options; + alias = full-flake-options.alias or { }; + homes = snowfall-lib.home.create-homes (full-flake-options.homes or { }); + systems = snowfall-lib.system.create-systems { + systems = full-flake-options.systems or { }; + homes = full-flake-options.homes or { }; }; - shells = snowfall-lib.shell.create-shells { - inherit channels; - overrides = (full-flake-options.shells or {}) // (user-outputs.devShells or {}); - alias = alias.shells or {}; + hosts = snowfall-lib.attrs.merge-shallow [ + (full-flake-options.systems.hosts or { }) + systems + homes + ]; + templates = snowfall-lib.template.create-templates { + overrides = full-flake-options.templates or { }; + alias = alias.templates or { }; }; - checks = snowfall-lib.check.create-checks { - inherit channels; - overrides = (full-flake-options.checks or {}) // (user-outputs.checks or {}); - alias = alias.checks or {}; + nixos-modules = snowfall-lib.module.create-modules { + src = snowfall-lib.fs.get-snowfall-file "modules/nixos"; + overrides = full-flake-options.modules.nixos or { }; + alias = alias.modules.nixos or { }; }; - - outputs = { - inherit packages checks; - - devShells = shells; + darwin-modules = snowfall-lib.module.create-modules { + src = snowfall-lib.fs.get-snowfall-file "modules/darwin"; + overrides = full-flake-options.modules.darwin or { }; + alias = alias.modules.darwin or { }; }; - in - snowfall-lib.attrs.merge-deep [user-outputs outputs]; + home-modules = snowfall-lib.module.create-modules { + src = snowfall-lib.fs.get-snowfall-file "modules/home"; + overrides = full-flake-options.modules.home or { }; + alias = alias.modules.home or { }; + }; + overlays = snowfall-lib.overlay.create-overlays { + inherit namespace; + extra-overlays = full-flake-options.extra-exported-overlays or { }; + }; + channels = full-flake-options.channels or { }; - flake-options = - custom-flake-options - // { + 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 namespace; + overrides = (full-flake-options.packages or { }) // (user-outputs.packages or { }); + alias = alias.packages or { }; + }; + shells = snowfall-lib.shell.create-shells { + inherit channels; + overrides = (full-flake-options.shells or { }) // (user-outputs.devShells or { }); + alias = alias.shells or { }; + }; + checks = snowfall-lib.check.create-checks { + inherit channels; + overrides = (full-flake-options.checks or { }) // (user-outputs.checks or { }); + alias = alias.checks or { }; + }; + + outputs = { + inherit packages checks; + + devShells = shells; + }; + in + snowfall-lib.attrs.merge-deep [ + user-outputs + outputs + ]; + + flake-options = custom-flake-options // { inherit hosts templates; inherit (user-inputs) self; @@ -173,41 +190,34 @@ in rec { darwinModules = darwin-modules; homeModules = home-modules; - channelsConfig = - full-flake-options.channels-config - or full-flake-options.channelsConfig - or {}; + channelsConfig = full-flake-options.channels-config or full-flake-options.channelsConfig or { }; - channels = - mapAttrs - (channel: config: - config - // { - overlaysBuilder = snowfall-lib.overlay.create-overlays-builder { - inherit namespace; - extra-overlays = full-flake-options.overlays or []; - }; - }) - ({nixpkgs = {};} // channels); + channels = mapAttrs ( + channel: config: + config + // { + overlaysBuilder = snowfall-lib.overlay.create-overlays-builder { + inherit namespace; + extra-overlays = full-flake-options.overlays or [ ]; + }; + } + ) ({ nixpkgs = { }; } // channels); outputsBuilder = outputs-builder; snowfall = { config = snowfall-config; - raw-config = full-flake-options.snowfall or {}; + raw-config = full-flake-options.snowfall or { }; user-lib = snowfall-lib.internal.user-lib; }; }; - flake-utils-plus-outputs = - core-inputs.flake-utils-plus.lib.mkFlake flake-options; + flake-utils-plus-outputs = core-inputs.flake-utils-plus.lib.mkFlake flake-options; - flake-outputs = - flake-utils-plus-outputs - // { + flake-outputs = flake-utils-plus-outputs // { inherit overlays; }; - in + in flake-outputs // { packages = @@ -215,23 +225,23 @@ in rec { // (builtins.listToAttrs ( builtins.map (system: { name = system; - value = - flake-outputs.packages.${system} - // { - homeConfigurations = let + value = flake-outputs.packages.${system} // { + homeConfigurations = + let homeNames = filterAttrs (_: home: home.system == system) homes; - homeConfigurations = mapAttrs (home-name: _: flake-outputs.homeConfigurations.${home-name}) homeNames; - renamedHomeConfigurations = - mapAttrs' ( - name: value: - if hasSuffix "@${system}" name - then nameValuePair (removeSuffix "@${system}" name) value - else nameValuePair name value - ) - homeConfigurations; + homeConfigurations = mapAttrs ( + home-name: _: flake-outputs.homeConfigurations.${home-name} + ) homeNames; + renamedHomeConfigurations = mapAttrs' ( + name: value: + if hasSuffix "@${system}" name then + nameValuePair (removeSuffix "@${system}" name) value + else + nameValuePair name value + ) homeConfigurations; in - renamedHomeConfigurations; - }; + renamedHomeConfigurations; + }; }) (builtins.attrNames flake-outputs.pkgs) )); }; diff --git a/snowfall-lib/fp/default.nix b/snowfall-lib/fp/default.nix index 1f9fdd9..ad91584 100644 --- a/snowfall-lib/fp/default.nix +++ b/snowfall-lib/fp/default.nix @@ -3,10 +3,12 @@ user-inputs, snowfall-lib, snowfall-config, -}: let +}: +let inherit (builtins) baseNameOf dirOf; inherit (core-inputs.nixpkgs.lib) id foldr flip; -in { +in +{ fp = rec { ## Compose two functions. ## Example Usage: @@ -18,7 +20,9 @@ in { ## (x: add-two (add-one x)) ## ``` #@ (b -> c) -> (a -> b) -> a -> c - compose = f: g: x: f (g x); + compose = + f: g: x: + f (g x); ## Compose many functions. ## Example Usage: diff --git a/snowfall-lib/fs/default.nix b/snowfall-lib/fs/default.nix index bb1f082..73c2a6e 100644 --- a/snowfall-lib/fs/default.nix +++ b/snowfall-lib/fs/default.nix @@ -3,13 +3,20 @@ user-inputs, snowfall-lib, snowfall-config, -}: let +}: +let inherit (builtins) readDir pathExists; inherit (core-inputs) flake-utils-plus; - inherit (core-inputs.nixpkgs.lib) assertMsg filterAttrs mapAttrsToList flatten; + inherit (core-inputs.nixpkgs.lib) + assertMsg + filterAttrs + mapAttrsToList + flatten + ; file-name-regex = "(.*)\\.(.*)$"; -in { +in +{ fs = rec { ## Matchers for file kinds. These are often used with `readDir`. ## Example Usage: @@ -72,10 +79,7 @@ in { ## { "my-file.txt" = "regular"; } ## ``` #@ Path -> Attrs - safe-read-directory = path: - if pathExists path - then readDir path - else {}; + safe-read-directory = path: if pathExists path then readDir path else { }; ## Get directories at a given path. ## Example Usage: @@ -87,10 +91,12 @@ in { ## [ "./something/a-directory" ] ## ``` #@ Path -> [Path] - get-directories = path: let - entries = safe-read-directory path; - filtered-entries = filterAttrs (name: kind: is-directory-kind kind) entries; - in + 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. @@ -103,10 +109,12 @@ in { ## [ "./something/a-file" ] ## ``` #@ Path -> [Path] - get-files = path: let - entries = safe-read-directory path; - filtered-entries = filterAttrs (name: kind: is-file-kind kind) entries; - in + 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. @@ -119,23 +127,21 @@ in { ## [ "./something/some-directory/a-file" ] ## ``` #@ Path -> [Path] - 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}"; + 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 - 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. @@ -148,10 +154,7 @@ in { ## [ "./something/a.nix" ] ## ``` #@ Path -> [Path] - get-nix-files = path: - builtins.filter - (snowfall-lib.path.has-file-extension "nix") - (get-files path); + 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. ## Example Usage: @@ -163,10 +166,8 @@ in { ## [ "./something/a.nix" ] ## ``` #@ Path -> [Path] - get-nix-files-recursive = path: - builtins.filter - (snowfall-lib.path.has-file-extension "nix") - (get-files-recursive path); + 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". ## Example Usage: @@ -178,10 +179,8 @@ in { ## [ "./something/default.nix" ] ## ``` #@ Path -> [Path] - get-default-nix-files = path: - builtins.filter - (name: builtins.baseNameOf name == "default.nix") - (get-files path); + 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. ## Example Usage: @@ -193,10 +192,8 @@ in { ## [ "./something/some-directory/default.nix" ] ## ``` #@ Path -> [Path] - get-default-nix-files-recursive = path: - builtins.filter - (name: builtins.baseNameOf name == "default.nix") - (get-files-recursive path); + 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". ## Example Usage: @@ -208,14 +205,12 @@ in { ## [ "./something/a.nix" ] ## ``` #@ Path -> [Path] - get-non-default-nix-files = path: - builtins.filter - ( + 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); + (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. ## Example Usage: @@ -227,13 +222,11 @@ in { ## [ "./something/some-directory/a.nix" ] ## ``` #@ Path -> [Path] - get-non-default-nix-files-recursive = path: - builtins.filter - ( + 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); + (snowfall-lib.path.has-file-extension "nix" name) && (builtins.baseNameOf name != "default.nix") + ) (get-files-recursive path); }; } diff --git a/snowfall-lib/home/default.nix b/snowfall-lib/home/default.nix index b5fa11d..41617fa 100644 --- a/snowfall-lib/home/default.nix +++ b/snowfall-lib/home/default.nix @@ -3,9 +3,9 @@ user-inputs, snowfall-lib, snowfall-config, -}: let - inherit - (core-inputs.nixpkgs.lib) +}: +let + inherit (core-inputs.nixpkgs.lib) assertMsg foldl head @@ -30,24 +30,26 @@ user-homes-root = snowfall-lib.fs.get-snowfall-file "homes"; user-modules-root = snowfall-lib.fs.get-snowfall-file "modules"; -in { +in +{ home = rec { # Modules in home-manager expect `hm` to be available directly on `lib` itself. home-lib = # NOTE: This prevents an error during evaluation if the input does # not exist. - if user-inputs ? home-manager - then - snowfall-lib.internal.system-lib.extend - (final: prev: + if user-inputs ? home-manager then + snowfall-lib.internal.system-lib.extend ( + final: prev: # NOTE: This order is important, this library's extend and other utilities must write # _over_ the original `system-lib`. - snowfall-lib.internal.system-lib - // prev - // { - hm = snowfall-lib.internal.system-lib.home-manager.hm; - }) - else {}; + snowfall-lib.internal.system-lib + // prev + // { + hm = snowfall-lib.internal.system-lib.home-manager.hm; + } + ) + else + { }; ## Get the user and host from a combined string. ## Example Usage: @@ -59,18 +61,18 @@ in { ## { user = "myuser"; host = "myhost"; } ## ``` #@ String -> Attrs - split-user-and-host = target: let - raw-name-parts = builtins.split "@" target; - name-parts = builtins.filter builtins.isString raw-name-parts; + split-user-and-host = + target: + let + raw-name-parts = builtins.split "@" target; + name-parts = builtins.filter builtins.isString raw-name-parts; - user = builtins.elemAt name-parts 0; - host = - if builtins.length name-parts > 1 - then builtins.elemAt name-parts 1 - else ""; - in { - inherit user host; - }; + user = builtins.elemAt name-parts 0; + host = if builtins.length name-parts > 1 then builtins.elemAt name-parts 1 else ""; + in + { + inherit user host; + }; ## Create a home. ## Example Usage: @@ -82,36 +84,40 @@ in { ## ## ``` #@ Attrs -> Attrs - create-home = { - path, - name ? builtins.unsafeDiscardStringContext (snowfall-lib.system.get-inferred-system-name path), - modules ? [], - specialArgs ? {}, - channelName ? "nixpkgs", - system ? "x86_64-linux", - }: let - user-metadata = split-user-and-host name; - unique-name = - if user-metadata.host == "" - then "${user-metadata.user}@${system}" - else name; + create-home = + { + path, + name ? builtins.unsafeDiscardStringContext (snowfall-lib.system.get-inferred-system-name path), + modules ? [ ], + specialArgs ? { }, + channelName ? "nixpkgs", + system ? "x86_64-linux", + }: + let + user-metadata = split-user-and-host name; + unique-name = if user-metadata.host == "" then "${user-metadata.user}@${system}" else name; - # NOTE: home-manager has trouble with `pkgs` recursion if it isn't passed in here. - pkgs = user-inputs.self.pkgs.${system}.${channelName} // {lib = home-lib;}; - lib = home-lib; - in - assert assertMsg (user-inputs ? home-manager) "In order to create home-manager configurations, you must include `home-manager` as a flake input."; - assert assertMsg ((user-metadata.host != "") || !(hasInfix "@" name)) "Snowfall Lib homes must be named with the format: user@system"; { + # NOTE: home-manager has trouble with `pkgs` recursion if it isn't passed in here. + pkgs = user-inputs.self.pkgs.${system}.${channelName} // { + lib = home-lib; + }; + lib = home-lib; + in + assert assertMsg (user-inputs ? home-manager) + "In order to create home-manager configurations, you must include `home-manager` as a flake input."; + assert assertMsg ( + (user-metadata.host != "") || !(hasInfix "@" name) + ) "Snowfall Lib homes must be named with the format: user@system"; + { inherit channelName system; output = "homeConfigurations"; - modules = - [ - path - ../../modules/home/user/default.nix - ] - ++ modules; + modules = [ + path + ../../modules/home/user/default.nix + ] + ++ modules; specialArgs = { inherit system; @@ -127,30 +133,37 @@ in { inherit pkgs lib; }; - builder = args: - user-inputs.home-manager.lib.homeManagerConfiguration - ((builtins.removeAttrs args ["system" "specialArgs"]) + builder = + args: + user-inputs.home-manager.lib.homeManagerConfiguration ( + (builtins.removeAttrs args [ + "system" + "specialArgs" + ]) // { inherit pkgs lib; - modules = - args.modules - ++ [ - (module-args: - import ./nix-registry-module.nix (module-args - // { - inherit user-inputs core-inputs; - })) - { - snowfallorg.user = { - name = mkDefault user-metadata.user; - enable = mkDefault true; - }; - } - ]; + modules = args.modules ++ [ + ( + module-args: + import ./nix-registry-module.nix ( + module-args + // { + inherit user-inputs core-inputs; + } + ) + ) + { + snowfallorg.user = { + name = mkDefault user-metadata.user; + enable = mkDefault true; + }; + } + ]; extraSpecialArgs = specialArgs // args.specialArgs; - }); + } + ); }; ## Get structured data about all homes for a given target. @@ -163,28 +176,30 @@ in { ## [ { system = "x86_64-linux"; name = "my-home"; path = "/homes/x86_64-linux/my-home";} ] ## ``` #@ String -> [Attrs] - get-target-homes-metadata = target: let - homes = snowfall-lib.fs.get-directories target; - existing-homes = builtins.filter (home: builtins.pathExists "${home}/default.nix") homes; - create-home-metadata = path: let - # 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. - basename = 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. - system = builtins.unsafeDiscardStringContext (builtins.baseNameOf target); - name = - if !(hasInfix "@" basename) - then "${basename}@${system}" - else basename; - in { - path = "${path}/default.nix"; - inherit name system; - }; - home-configurations = builtins.map create-home-metadata existing-homes; - in + get-target-homes-metadata = + target: + let + homes = snowfall-lib.fs.get-directories target; + existing-homes = builtins.filter (home: builtins.pathExists "${home}/default.nix") homes; + create-home-metadata = + path: + let + # 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. + basename = 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. + system = builtins.unsafeDiscardStringContext (builtins.baseNameOf target); + name = if !(hasInfix "@" basename) then "${basename}@${system}" else basename; + in + { + path = "${path}/default.nix"; + inherit name system; + }; + home-configurations = builtins.map create-home-metadata existing-homes; + in home-configurations; ## Create all available homes. @@ -197,36 +212,45 @@ in { ## { "my-user@my-system" = ; } ## ``` #@ Attrs -> Attrs - create-homes = homes: let - targets = snowfall-lib.fs.get-directories user-homes-root; - target-homes-metadata = concatMap get-target-homes-metadata targets; + create-homes = + homes: + let + targets = snowfall-lib.fs.get-directories user-homes-root; + target-homes-metadata = concatMap get-target-homes-metadata targets; - user-home-modules = snowfall-lib.module.create-modules { - src = "${user-modules-root}/home"; - }; + user-home-modules = snowfall-lib.module.create-modules { + src = "${user-modules-root}/home"; + }; - user-home-modules-list = - mapAttrsToList - (module-path: module: args @ {pkgs, ...}: + user-home-modules-list = mapAttrsToList ( + module-path: module: + args@{ pkgs, ... }: (module args) // { _file = "${user-homes-root}/${module-path}/default.nix"; - }) - user-home-modules; + } + ) user-home-modules; - create-home' = home-metadata: let - inherit (home-metadata) name; - overrides = homes.users.${name} or {}; - in { - "${name}" = create-home (overrides - // home-metadata - // { - modules = user-home-modules-list ++ (homes.users.${name}.modules or []) ++ (homes.modules or []); - }); - }; + create-home' = + home-metadata: + let + inherit (home-metadata) name; + overrides = homes.users.${name} or { }; + in + { + "${name}" = create-home ( + overrides + // home-metadata + // { + modules = user-home-modules-list ++ (homes.users.${name}.modules or [ ]) ++ (homes.modules or [ ]); + } + ); + }; - created-homes = foldl (homes: home-metadata: homes // (create-home' home-metadata)) {} target-homes-metadata; - in + created-homes = foldl ( + homes: home-metadata: homes // (create-home' home-metadata) + ) { } target-homes-metadata; + in created-homes; ## Create system modules for home-manager integration. @@ -239,147 +263,163 @@ in { ## [Module] ## ``` #@ Attrs -> [Module] - create-home-system-modules = users: let - created-users = create-homes users; - user-home-modules = snowfall-lib.module.create-modules { - src = "${user-modules-root}/home"; - }; + create-home-system-modules = + users: + let + created-users = create-homes users; + user-home-modules = snowfall-lib.module.create-modules { + src = "${user-modules-root}/home"; + }; - shared-modules = builtins.map (module: { - config.home-manager.sharedModules = [module]; - }) (users.modules or []); + shared-modules = builtins.map (module: { + config.home-manager.sharedModules = [ module ]; + }) (users.modules or [ ]); - shared-user-modules = - mapAttrsToList - (module-path: module: { + shared-user-modules = mapAttrsToList (module-path: module: { _file = "${user-modules-root}/home/${module-path}/default.nix"; config = { - home-manager.sharedModules = [module]; + home-manager.sharedModules = [ module ]; }; - }) - user-home-modules; + }) user-home-modules; - snowfall-user-home-module = { - _file = "virtual:snowfallorg/modules/home/user/default.nix"; + snowfall-user-home-module = { + _file = "virtual:snowfallorg/modules/home/user/default.nix"; - config = { - home-manager.sharedModules = [ - ../../modules/home/user/default.nix - ]; - }; - }; - - extra-special-args-module = args @ { - config, - pkgs, - system ? pkgs.stdenv.hostPlatform.system, - target ? system, - format ? "home", - host ? "", - virtual ? (snowfall-lib.system.is-virtual target), - systems ? {}, - ... - }: { - _file = "virtual:snowfallorg/home/extra-special-args"; - - config = { - home-manager.extraSpecialArgs = { - inherit system target format virtual systems host; - inherit (snowfall-config) namespace; - - lib = home-lib; - - inputs = snowfall-lib.flake.without-src user-inputs; + config = { + home-manager.sharedModules = [ + ../../modules/home/user/default.nix + ]; }; }; - }; - system-modules = - builtins.map - ( - name: let + extra-special-args-module = + args@{ + config, + pkgs, + system ? pkgs.stdenv.hostPlatform.system, + target ? system, + format ? "home", + host ? "", + virtual ? (snowfall-lib.system.is-virtual target), + systems ? { }, + ... + }: + { + _file = "virtual:snowfallorg/home/extra-special-args"; + + config = { + home-manager.extraSpecialArgs = { + inherit + system + target + format + virtual + systems + host + ; + inherit (snowfall-config) namespace; + + lib = home-lib; + + inputs = snowfall-lib.flake.without-src user-inputs; + }; + }; + }; + + system-modules = builtins.map ( + name: + let created-user = created-users.${name}; user-module = head created-user.modules; - other-modules = users.users.${name}.modules or []; + other-modules = users.users.${name}.modules or [ ]; user-name = created-user.specialArgs.user; in - args @ { - config, - options, - pkgs, - host ? "", - system ? pkgs.stdenv.hostPlatform.system, - ... - }: let - host-matches = - (name == "${user-name}@${host}") - || (name == "${user-name}@${system}"); + args@{ + config, + options, + pkgs, + host ? "", + system ? pkgs.stdenv.hostPlatform.system, + ... + }: + let + host-matches = (name == "${user-name}@${host}") || (name == "${user-name}@${system}"); - # NOTE: To conform to the config structure of home-manager, we have to - # remap the options coming from `snowfallorg.user..home.config` since `mkAliasDefinitions` - # does not let us target options within a submodule. - wrap-user-options = user-option: - if (user-option ? "_type") && user-option._type == "merge" - then - user-option - // { - contents = - builtins.map - ( - merge-entry: - merge-entry.${user-name}.home.config or {} - ) - user-option.contents; - } - else - (builtins.trace '' - ============= - Snowfall Lib: - Option value for `snowfallorg.users.${user-name}` was not detected to be merged. + # NOTE: To conform to the config structure of home-manager, we have to + # remap the options coming from `snowfallorg.user..home.config` since `mkAliasDefinitions` + # does not let us target options within a submodule. + wrap-user-options = + user-option: + if (user-option ? "_type") && user-option._type == "merge" then + user-option + // { + contents = builtins.map ( + merge-entry: merge-entry.${user-name}.home.config or { } + ) user-option.contents; + } + else + (builtins.trace '' + ============= + Snowfall Lib: + Option value for `snowfallorg.users.${user-name}` was not detected to be merged. - Please report the issue on GitHub with a link to your configuration so we can debug the problem: - https://github.com/snowfallorg/lib/issues/new - ============= - '') + Please report the issue on GitHub with a link to your configuration so we can debug the problem: + https://github.com/snowfallorg/lib/issues/new + ============= + '') user-option; - home-config = mkAliasAndWrapDefinitions wrap-user-options options.snowfallorg.users; - in { - _file = "virtual:snowfallorg/home/user/${name}"; + home-config = mkAliasAndWrapDefinitions wrap-user-options options.snowfallorg.users; + in + { + _file = "virtual:snowfallorg/home/user/${name}"; - config = mkIf host-matches { - # Initialize user information. - snowfallorg.users.${user-name}.home.config = { - snowfallorg.user = { - enable = mkDefault true; - name = mkDefault user-name; - }; - - # NOTE: specialArgs are not propagated by Home-Manager without this. - # However, not all specialArgs values can be set when using `_module.args`. - _module.args = builtins.removeAttrs ((users.users.${name}.specialArgs or {}) - // { - namespace = snowfall-config.namespace; - }) - ["options" "config" "lib" "pkgs" "specialArgs" "host"]; + config = mkIf host-matches { + # Initialize user information. + snowfallorg.users.${user-name}.home.config = { + snowfallorg.user = { + enable = mkDefault true; + name = mkDefault user-name; }; - home-manager = { - users.${user-name} = mkIf config.snowfallorg.users.${user-name}.home.enable ({pkgs, ...}: { - imports = (home-config.imports or []) ++ other-modules ++ [user-module]; - config = builtins.removeAttrs home-config ["imports"]; - }); - - # NOTE: Without this home-manager will instead create its own package set which won't contain the same config and - # user-defined packages/overlays as the flake's nixpkgs channel. - useGlobalPkgs = mkDefault true; - }; + # NOTE: specialArgs are not propagated by Home-Manager without this. + # However, not all specialArgs values can be set when using `_module.args`. + _module.args = + builtins.removeAttrs + ( + (users.users.${name}.specialArgs or { }) + // { + namespace = snowfall-config.namespace; + } + ) + [ + "options" + "config" + "lib" + "pkgs" + "specialArgs" + "host" + ]; }; - } - ) - (builtins.attrNames created-users); - in + + home-manager = { + users.${user-name} = mkIf config.snowfallorg.users.${user-name}.home.enable ( + { pkgs, ... }: + { + imports = (home-config.imports or [ ]) ++ other-modules ++ [ user-module ]; + config = builtins.removeAttrs home-config [ "imports" ]; + } + ); + + # NOTE: Without this home-manager will instead create its own package set which won't contain the same config and + # user-defined packages/overlays as the flake's nixpkgs channel. + useGlobalPkgs = mkDefault true; + }; + }; + } + ) (builtins.attrNames created-users); + in [ extra-special-args-module snowfall-user-home-module diff --git a/snowfall-lib/home/nix-registry-module.nix b/snowfall-lib/home/nix-registry-module.nix index 200da73..6e7626f 100644 --- a/snowfall-lib/home/nix-registry-module.nix +++ b/snowfall-lib/home/nix-registry-module.nix @@ -6,7 +6,8 @@ user-inputs, core-inputs, ... -}: { +}: +{ disabledModules = [ # The module from flake-utils-plus only works on NixOS and nix-darwin. For home-manager # to build, this module needs to be disabled. diff --git a/snowfall-lib/internal/default.nix b/snowfall-lib/internal/default.nix index 66d415e..6542dbd 100644 --- a/snowfall-lib/internal/default.nix +++ b/snowfall-lib/internal/default.nix @@ -3,8 +3,14 @@ user-inputs, snowfall-lib, snowfall-config, -}: let - inherit (core-inputs.nixpkgs.lib) fix filterAttrs callPackageWith isFunction; +}: +let + inherit (core-inputs.nixpkgs.lib) + fix + filterAttrs + callPackageWith + isFunction + ; 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); @@ -16,44 +22,45 @@ core-inputs-libs user-inputs-libs snowfall-top-level-lib - {snowfall = snowfall-lib;} + { snowfall = snowfall-lib; } ]; user-lib-root = snowfall-lib.fs.get-snowfall-file "lib"; user-lib-modules = snowfall-lib.fs.get-default-nix-files-recursive user-lib-root; user-lib = fix ( - user-lib: let + user-lib: + let attrs = { inputs = snowfall-lib.flake.without-snowfall-inputs user-inputs; snowfall-inputs = core-inputs; namespace = snowfall-config.namespace; lib = snowfall-lib.attrs.merge-shallow [ base-lib - {"${snowfall-config.namespace}" = user-lib;} + { "${snowfall-config.namespace}" = user-lib; } ]; }; - libs = - builtins.map - ( - path: let - imported-module = import path; - in - if isFunction imported-module - then callPackageWith attrs path {} - # the only difference is that there is no `override` and `overrideDerivation` on returned value - else imported-module - ) - user-lib-modules; + libs = builtins.map ( + path: + let + imported-module = import path; + in + if isFunction imported-module then + callPackageWith attrs path { } + # the only difference is that there is no `override` and `overrideDerivation` on returned value + else + imported-module + ) user-lib-modules; in - snowfall-lib.attrs.merge-deep libs + snowfall-lib.attrs.merge-deep libs ); system-lib = snowfall-lib.attrs.merge-shallow [ base-lib - {"${snowfall-config.namespace}" = user-lib;} + { "${snowfall-config.namespace}" = user-lib; } ]; -in { +in +{ internal = { inherit system-lib user-lib; }; diff --git a/snowfall-lib/module/default.nix b/snowfall-lib/module/default.nix index 3bf0392..b002c1a 100644 --- a/snowfall-lib/module/default.nix +++ b/snowfall-lib/module/default.nix @@ -3,12 +3,22 @@ user-inputs, snowfall-lib, snowfall-config, -}: let +}: +let inherit (builtins) baseNameOf; - inherit (core-inputs.nixpkgs.lib) foldl mapAttrs hasPrefix hasSuffix isFunction splitString tail; + inherit (core-inputs.nixpkgs.lib) + foldl + mapAttrs + hasPrefix + hasSuffix + isFunction + splitString + tail + ; user-modules-root = snowfall-lib.fs.get-snowfall-file "modules"; -in { +in +{ module = { ## Create flake output modules. ## Example Usage: @@ -20,65 +30,75 @@ in { ## { another-module = ...; my-module = ...; default = ...; } ## ``` #@ Attrs -> Attrs - create-modules = { - src ? "${user-modules-root}/nixos", - overrides ? {}, - alias ? {}, - }: let - user-modules = snowfall-lib.fs.get-default-nix-files-recursive src; - create-module-metadata = module: { - name = let - path-name = builtins.replaceStrings [(builtins.toString src) "/default.nix"] ["" ""] (builtins.unsafeDiscardStringContext module); - in - if hasPrefix "/" path-name - then builtins.substring 1 ((builtins.stringLength path-name) - 1) path-name - else path-name; - path = module; - }; - modules-metadata = builtins.map create-module-metadata user-modules; - merge-modules = modules: metadata: - modules - // { - # NOTE: home-manager *requires* modules to specify named arguments or it will not - # pass values in. For this reason we must specify things like `pkgs` as a named attribute. - ${metadata.name} = args @ {pkgs, ...}: let - system = args.system or args.pkgs.stdenv.hostPlatform.system; - target = args.target or system; - - format = let - virtual-system-type = snowfall-lib.system.get-virtual-system-type target; + create-modules = + { + src ? "${user-modules-root}/nixos", + overrides ? { }, + alias ? { }, + }: + let + user-modules = snowfall-lib.fs.get-default-nix-files-recursive src; + create-module-metadata = module: { + name = + let + path-name = builtins.replaceStrings [ (builtins.toString src) "/default.nix" ] [ "" "" ] ( + builtins.unsafeDiscardStringContext module + ); in - if virtual-system-type != "" - then virtual-system-type - else if snowfall-lib.system.is-darwin target - then "darwin" - else "linux"; - - # Replicates the specialArgs from Snowfall Lib's system builder. - modified-args = - args - // { - inherit system target format; - virtual = args.virtual or (snowfall-lib.system.get-virtual-system-type target != ""); - systems = args.systems or {}; - - lib = snowfall-lib.internal.system-lib; - - inputs = snowfall-lib.flake.without-src user-inputs; - namespace = snowfall-config.namespace; - }; - imported-user-module = import metadata.path; - user-module = - if isFunction imported-user-module - then imported-user-module modified-args - else imported-user-module; - in - user-module // {_file = metadata.path;}; + if hasPrefix "/" path-name then + builtins.substring 1 ((builtins.stringLength path-name) - 1) path-name + else + path-name; + path = module; }; - modules-without-aliases = foldl merge-modules {} modules-metadata; - aliased-modules = mapAttrs (name: value: modules-without-aliases.${value}) alias; - modules = modules-without-aliases // aliased-modules // overrides; - in + modules-metadata = builtins.map create-module-metadata user-modules; + merge-modules = + modules: metadata: + modules + // { + # NOTE: home-manager *requires* modules to specify named arguments or it will not + # pass values in. For this reason we must specify things like `pkgs` as a named attribute. + ${metadata.name} = + args@{ pkgs, ... }: + let + system = args.system or args.pkgs.stdenv.hostPlatform.system; + target = args.target or system; + + format = + let + virtual-system-type = snowfall-lib.system.get-virtual-system-type target; + in + if virtual-system-type != "" then + virtual-system-type + else if snowfall-lib.system.is-darwin target then + "darwin" + else + "linux"; + + # Replicates the specialArgs from Snowfall Lib's system builder. + modified-args = args // { + inherit system target format; + virtual = args.virtual or (snowfall-lib.system.get-virtual-system-type target != ""); + systems = args.systems or { }; + + lib = snowfall-lib.internal.system-lib; + + inputs = snowfall-lib.flake.without-src user-inputs; + namespace = snowfall-config.namespace; + }; + imported-user-module = import metadata.path; + user-module = + if isFunction imported-user-module then + imported-user-module modified-args + else + imported-user-module; + in + user-module // { _file = metadata.path; }; + }; + modules-without-aliases = foldl merge-modules { } modules-metadata; + aliased-modules = mapAttrs (name: value: modules-without-aliases.${value}) alias; + modules = modules-without-aliases // aliased-modules // overrides; + in modules; }; } diff --git a/snowfall-lib/overlay/default.nix b/snowfall-lib/overlay/default.nix index 25c0dcb..8d01cc6 100644 --- a/snowfall-lib/overlay/default.nix +++ b/snowfall-lib/overlay/default.nix @@ -3,12 +3,14 @@ user-inputs, snowfall-lib, snowfall-config, -}: let +}: +let inherit (core-inputs.nixpkgs.lib) assertMsg foldl concatStringsSep; user-overlays-root = snowfall-lib.fs.get-snowfall-file "overlays"; user-packages-root = snowfall-lib.fs.get-snowfall-file "packages"; -in { +in +{ overlay = { ## Create a flake-utils-plus overlays builder. ## Example Usage: @@ -20,36 +22,44 @@ in { ## (channels: [ ... ]) ## ``` #@ Attrs -> Attrs -> [(a -> b -> c)] - create-overlays-builder = { - src ? user-overlays-root, - namespace ? snowfall-config.namespace, - extra-overlays ? [], - }: channels: let - user-overlays = snowfall-lib.fs.get-default-nix-files-recursive src; - create-overlay = overlay: - import overlay ( - # Deprecated: Use `inputs.*` instead of referencing the input name directly. - user-inputs - // { - inherit channels; - inherit (snowfall-config) namespace; - inputs = user-inputs; - lib = snowfall-lib.internal.system-lib; - } - ); - user-packages-overlay = final: prev: let - user-packages = snowfall-lib.package.create-packages { - pkgs = final; - inherit channels namespace; - }; - in { - ${namespace} = - (prev.${namespace} or {}) - // user-packages; - }; - overlays = - [user-packages-overlay] ++ extra-overlays ++ (builtins.map create-overlay user-overlays); - in + create-overlays-builder = + { + src ? user-overlays-root, + namespace ? snowfall-config.namespace, + extra-overlays ? [ ], + }: + channels: + let + user-overlays = snowfall-lib.fs.get-default-nix-files-recursive src; + create-overlay = + overlay: + import overlay ( + # Deprecated: Use `inputs.*` instead of referencing the input name directly. + user-inputs + // { + inherit channels; + inherit (snowfall-config) namespace; + inputs = user-inputs; + lib = snowfall-lib.internal.system-lib; + } + ); + user-packages-overlay = + final: prev: + let + user-packages = snowfall-lib.package.create-packages { + pkgs = final; + inherit channels namespace; + }; + in + { + ${namespace} = (prev.${namespace} or { }) // user-packages; + }; + overlays = [ + user-packages-overlay + ] + ++ extra-overlays + ++ (builtins.map create-overlay user-overlays); + in overlays; ## Create exported overlays from the user flake. Adapted [from flake-utils-plus](https://github.com/gytis-ivaskevicius/flake-utils-plus/blob/2bf0f91643c2e5ae38c1b26893ac2927ac9bd82a/lib/exportOverlays.nix). @@ -63,136 +73,133 @@ in { ## { default = final: prev: ...; some-overlay = final: prev: ...; } ## ``` #@ Attrs -> Attrs - create-overlays = { - src ? user-overlays-root, - packages-src ? user-packages-root, - namespace ? snowfall-config.namespace, - extra-overlays ? {}, - }: let - fake-pkgs = { - callPackage = x: x; - isFakePkgs = true; - lib = {}; - system = "fake-system"; - }; - - user-overlays = snowfall-lib.fs.get-default-nix-files-recursive src; - - channel-systems = user-inputs.self.pkgs; - - user-packages-overlay = final: prev: let - user-packages = snowfall-lib.package.create-packages { - pkgs = final; - channels = channel-systems.${prev.system}; - inherit namespace; - }; - in - if namespace == null - then user-packages - else { - ${namespace} = - (prev.${namespace} or {}) - // user-packages; + create-overlays = + { + src ? user-overlays-root, + packages-src ? user-packages-root, + namespace ? snowfall-config.namespace, + extra-overlays ? { }, + }: + let + fake-pkgs = { + callPackage = x: x; + isFakePkgs = true; + lib = { }; + system = "fake-system"; }; - create-overlay = ( - overlays: file: let - name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory file); - overlay = final: prev: let - channels = channel-systems.${prev.system}; - user-overlay = import file ( - # Deprecated: Use `inputs.*` instead of referencing the input name directly. - user-inputs - // { - inherit channels namespace; - inputs = user-inputs; - lib = snowfall-lib.internal.system-lib; - } - ); - packages = user-packages-overlay final prev; - prev-with-packages = - if namespace == null - then prev // packages - else - prev - // { - ${namespace} = - (prev.${namespace} or {}) - // packages.${namespace}; - }; - user-overlay-packages = - user-overlay - final - prev-with-packages; - outputs = - user-overlay-packages; + user-overlays = snowfall-lib.fs.get-default-nix-files-recursive src; + + channel-systems = user-inputs.self.pkgs; + + user-packages-overlay = + final: prev: + let + user-packages = snowfall-lib.package.create-packages { + pkgs = final; + channels = channel-systems.${prev.system}; + inherit namespace; + }; in - if user-overlay-packages.__dontExport or false == true - then outputs // {__dontExport = true;} - else outputs; - fake-overlay-result = overlay fake-pkgs fake-pkgs; - in - if fake-overlay-result.__dontExport or false == true - then overlays + if namespace == null then + user-packages + else + { + ${namespace} = (prev.${namespace} or { }) // user-packages; + }; + + create-overlay = ( + overlays: file: + let + name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory file); + overlay = + final: prev: + let + channels = channel-systems.${prev.system}; + user-overlay = import file ( + # Deprecated: Use `inputs.*` instead of referencing the input name directly. + user-inputs + // { + inherit channels namespace; + inputs = user-inputs; + lib = snowfall-lib.internal.system-lib; + } + ); + packages = user-packages-overlay final prev; + prev-with-packages = + if namespace == null then + prev // packages + else + prev + // { + ${namespace} = (prev.${namespace} or { }) // packages.${namespace}; + }; + user-overlay-packages = user-overlay final prev-with-packages; + outputs = user-overlay-packages; + in + if user-overlay-packages.__dontExport or false == true then + outputs // { __dontExport = true; } + else + outputs; + fake-overlay-result = overlay fake-pkgs fake-pkgs; + in + if fake-overlay-result.__dontExport or false == true then + overlays else overlays // { ${name} = overlay; } - ); + ); - overlays = - foldl - create-overlay - {} - user-overlays; + overlays = foldl create-overlay { } user-overlays; - user-packages = snowfall-lib.fs.get-default-nix-files-recursive packages-src; + user-packages = snowfall-lib.fs.get-default-nix-files-recursive packages-src; - create-package-overlay = package-overlays: file: let - name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory file); - overlay = final: prev: let - channels = channel-systems.${prev.system}; - packages = snowfall-lib.package.create-packages { - inherit namespace; - channels = channel-systems.${prev.system}; - }; - in - if namespace == null - then {${name} = packages.${name};} - else { - ${namespace} = - (prev.${namespace} or {}) - // {${name} = packages.${name};}; + create-package-overlay = + package-overlays: file: + let + name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory file); + overlay = + final: prev: + let + channels = channel-systems.${prev.system}; + packages = snowfall-lib.package.create-packages { + inherit namespace; + channels = channel-systems.${prev.system}; + }; + in + if namespace == null then + { ${name} = packages.${name}; } + else + { + ${namespace} = (prev.${namespace} or { }) // { + ${name} = packages.${name}; + }; + }; + in + package-overlays + // { + "package/${name}" = overlay; }; + + package-overlays = foldl create-package-overlay { } user-packages; + + default-overlay = + final: prev: + let + overlays-list = builtins.attrValues overlays; + package-overlays-list = builtins.attrValues package-overlays; + + overlays-results = builtins.map (overlay: overlay final prev) overlays-list; + package-overlays-results = builtins.map (overlay: overlay final prev) package-overlays-list; + + merged-results = snowfall-lib.attrs.merge-shallow-packages ( + package-overlays-results ++ overlays-results + ); + in + merged-results; in - package-overlays - // { - "package/${name}" = overlay; - }; - - package-overlays = - foldl - create-package-overlay - {} - user-packages; - - default-overlay = final: prev: let - overlays-list = builtins.attrValues overlays; - package-overlays-list = builtins.attrValues package-overlays; - - overlays-results = builtins.map (overlay: overlay final prev) overlays-list; - package-overlays-results = builtins.map (overlay: overlay final prev) package-overlays-list; - - merged-results = - snowfall-lib.attrs.merge-shallow-packages - (package-overlays-results ++ overlays-results); - in - merged-results; - in - package-overlays - // overlays - // {default = default-overlay;} - // extra-overlays; + package-overlays // overlays // { default = default-overlay; } // extra-overlays; }; } diff --git a/snowfall-lib/package/default.nix b/snowfall-lib/package/default.nix index a0d8871..7743dd0 100644 --- a/snowfall-lib/package/default.nix +++ b/snowfall-lib/package/default.nix @@ -3,12 +3,20 @@ user-inputs, snowfall-lib, snowfall-config, -}: let +}: +let inherit (core-inputs.flake-utils-plus.lib) filterPackages allSystems; - inherit (core-inputs.nixpkgs.lib) assertMsg foldl mapAttrs filterAttrs callPackageWith; + inherit (core-inputs.nixpkgs.lib) + assertMsg + foldl + mapAttrs + filterAttrs + callPackageWith + ; user-packages-root = snowfall-lib.fs.get-snowfall-file "packages"; -in { +in +{ package = rec { ## Create flake output packages. ## Example Usage: @@ -20,54 +28,59 @@ in { ## { another-package = ...; my-package = ...; default = ...; } ## ``` #@ Attrs -> Attrs - create-packages = { - channels, - src ? user-packages-root, - pkgs ? channels.nixpkgs, - overrides ? {}, - alias ? {}, - namespace ? snowfall-config.namespace, - }: let - user-packages = snowfall-lib.fs.get-default-nix-files-recursive src; - create-package-metadata = package: let - namespaced-packages = { - ${namespace} = packages-without-aliases; - }; - extra-inputs = - pkgs - // namespaced-packages - // { - inherit channels namespace; - lib = snowfall-lib.internal.system-lib; - pkgs = pkgs // namespaced-packages; - inputs = user-inputs; - }; - in { - name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory package); - drv = let - pkg = callPackageWith extra-inputs package {}; - in - pkg - // { - meta = - (pkg.meta or {}) + create-packages = + { + channels, + src ? user-packages-root, + pkgs ? channels.nixpkgs, + overrides ? { }, + alias ? { }, + namespace ? snowfall-config.namespace, + }: + let + user-packages = snowfall-lib.fs.get-default-nix-files-recursive src; + create-package-metadata = + package: + let + namespaced-packages = { + ${namespace} = packages-without-aliases; + }; + extra-inputs = + pkgs + // namespaced-packages // { - snowfall = { - path = package; + inherit channels namespace; + lib = snowfall-lib.internal.system-lib; + pkgs = pkgs // namespaced-packages; + inputs = user-inputs; + }; + in + { + name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory package); + drv = + let + pkg = callPackageWith extra-inputs package { }; + in + pkg + // { + meta = (pkg.meta or { }) // { + snowfall = { + path = package; + }; }; }; }; - }; - packages-metadata = builtins.map create-package-metadata user-packages; - merge-packages = packages: metadata: - packages - // { - ${metadata.name} = metadata.drv; - }; - packages-without-aliases = foldl merge-packages {} packages-metadata; - aliased-packages = mapAttrs (name: value: packages-without-aliases.${value}) alias; - packages = packages-without-aliases // aliased-packages // overrides; - in + packages-metadata = builtins.map create-package-metadata user-packages; + merge-packages = + packages: metadata: + packages + // { + ${metadata.name} = metadata.drv; + }; + packages-without-aliases = foldl merge-packages { } packages-metadata; + aliased-packages = mapAttrs (name: value: packages-without-aliases.${value}) alias; + packages = packages-without-aliases // aliased-packages // overrides; + in filterPackages pkgs.stdenv.hostPlatform.system packages; }; } diff --git a/snowfall-lib/path/default.nix b/snowfall-lib/path/default.nix index 7d35455..484e28d 100644 --- a/snowfall-lib/path/default.nix +++ b/snowfall-lib/path/default.nix @@ -3,12 +3,19 @@ user-inputs, snowfall-lib, snowfall-config, -}: let - inherit (builtins) toString baseNameOf dirOf concatStringsSep; +}: +let + inherit (builtins) + toString + baseNameOf + dirOf + concatStringsSep + ; inherit (core-inputs.nixpkgs.lib) assertMsg last init; file-name-regex = "(.*)\\.(.*)$"; -in { +in +{ path = rec { ## Split a file name and its extension. ## Example Usage: @@ -20,10 +27,15 @@ in { ## [ "my-file" "md" ] ## ``` #@ String -> [String] - 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; + 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. ## Example Usage: @@ -35,9 +47,11 @@ in { ## true ## ``` #@ String -> Bool - has-any-file-extension = file: let - match = builtins.match file-name-regex (toString file); - in + 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. @@ -50,13 +64,15 @@ in { ## "txt" ## ``` #@ String -> String - get-file-extension = file: - if has-any-file-extension file - then let - match = builtins.match file-name-regex (toString file); - in + get-file-extension = + file: + if has-any-file-extension file then + let + match = builtins.match file-name-regex (toString file); + in last match - else ""; + else + ""; ## Check if a file name has a specific file extension. ## Example Usage: @@ -68,10 +84,9 @@ in { ## true ## ``` #@ String -> String -> Bool - has-file-extension = extension: file: - if has-any-file-extension file - then extension == get-file-extension file - else false; + 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. ## Example Usage: @@ -95,11 +110,14 @@ in { ## "my-file" ## ``` #@ Path -> String - 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; + 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; }; } diff --git a/snowfall-lib/shell/default.nix b/snowfall-lib/shell/default.nix index 02ee0a5..c4772e2 100644 --- a/snowfall-lib/shell/default.nix +++ b/snowfall-lib/shell/default.nix @@ -3,12 +3,19 @@ user-inputs, snowfall-lib, snowfall-config, -}: let +}: +let inherit (core-inputs.flake-utils-plus.lib) filterPackages; - inherit (core-inputs.nixpkgs.lib) assertMsg foldl mapAttrs callPackageWith; + inherit (core-inputs.nixpkgs.lib) + assertMsg + foldl + mapAttrs + callPackageWith + ; user-shells-root = snowfall-lib.fs.get-snowfall-file "shells"; -in { +in +{ shell = { ## Create flake output packages. ## Example Usage: @@ -20,37 +27,41 @@ in { ## { another-shell = ...; my-shell = ...; default = ...; } ## ``` #@ Attrs -> Attrs - create-shells = { - channels, - src ? user-shells-root, - pkgs ? channels.nixpkgs, - overrides ? {}, - alias ? {}, - }: let - user-shells = snowfall-lib.fs.get-default-nix-files-recursive src; - create-shell-metadata = shell: let - extra-inputs = - pkgs - // { - inherit channels; - lib = snowfall-lib.internal.system-lib; - inputs = snowfall-lib.flake.without-src user-inputs; - namespace = snowfall-config.namespace; + create-shells = + { + channels, + src ? user-shells-root, + pkgs ? channels.nixpkgs, + overrides ? { }, + alias ? { }, + }: + let + user-shells = snowfall-lib.fs.get-default-nix-files-recursive src; + create-shell-metadata = + shell: + let + extra-inputs = pkgs // { + inherit channels; + lib = snowfall-lib.internal.system-lib; + inputs = snowfall-lib.flake.without-src user-inputs; + namespace = snowfall-config.namespace; + }; + in + { + name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory shell); + drv = callPackageWith extra-inputs shell { }; }; - in { - name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory shell); - drv = callPackageWith extra-inputs shell {}; - }; - shells-metadata = builtins.map create-shell-metadata user-shells; - merge-shells = shells: metadata: - shells - // { - ${metadata.name} = metadata.drv; - }; - shells-without-aliases = foldl merge-shells {} shells-metadata; - aliased-shells = mapAttrs (name: value: shells-without-aliases.${value}) alias; - shells = shells-without-aliases // aliased-shells // overrides; - in + shells-metadata = builtins.map create-shell-metadata user-shells; + merge-shells = + shells: metadata: + shells + // { + ${metadata.name} = metadata.drv; + }; + shells-without-aliases = foldl merge-shells { } shells-metadata; + aliased-shells = mapAttrs (name: value: shells-without-aliases.${value}) alias; + shells = shells-without-aliases // aliased-shells // overrides; + in filterPackages pkgs.stdenv.hostPlatform.system shells; }; } diff --git a/snowfall-lib/system/default.nix b/snowfall-lib/system/default.nix index 95b9e9f..69531bc 100644 --- a/snowfall-lib/system/default.nix +++ b/snowfall-lib/system/default.nix @@ -3,15 +3,25 @@ user-inputs, snowfall-lib, snowfall-config, -}: let +}: +let inherit (builtins) dirOf baseNameOf; - inherit (core-inputs.nixpkgs.lib) assertMsg fix hasInfix concatMap foldl optionals singleton; + inherit (core-inputs.nixpkgs.lib) + assertMsg + fix + hasInfix + concatMap + foldl + optionals + singleton + ; virtual-systems = import ./virtual-systems.nix; user-systems-root = snowfall-lib.fs.get-snowfall-file "systems"; user-modules-root = snowfall-lib.fs.get-snowfall-file "modules"; -in { +in +{ system = rec { ## Get the name of a system based on its file path. ## Example Usage: @@ -23,10 +33,12 @@ in { ## "my-system" ## ``` #@ Path -> String - 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; + 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; ## Check whether a named system is macOS. ## Example Usage: @@ -62,8 +74,7 @@ in { ## true ## ``` #@ String -> Bool - is-virtual = target: - (get-virtual-system-type target) != ""; + is-virtual = target: (get-virtual-system-type target) != ""; ## Get the virtual system type of a system target. ## Example Usage: @@ -75,16 +86,12 @@ in { ## "iso" ## ``` #@ String -> String - get-virtual-system-type = target: - foldl - ( + get-virtual-system-type = + target: + foldl ( result: virtual-system: - if result == "" && hasInfix virtual-system target - then virtual-system - else result - ) - "" - virtual-systems; + if result == "" && hasInfix virtual-system target then virtual-system else result + ) "" virtual-systems; ## Get structured data about all systems for a given target. ## Example Usage: @@ -96,22 +103,24 @@ in { ## [ { target = "x86_64-linux"; name = "my-machine"; path = "/systems/x86_64-linux/my-machine"; } ] ## ``` #@ String -> [Attrs] - 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 + 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. @@ -124,62 +133,66 @@ in { ## (args: ) ## ``` #@ String -> Function - 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 + 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; - }; - modules = - args.modules - ++ [ - ../../modules/nixos/user/default.nix - ]; - }); - 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" "modules"]) - // { - specialArgs = - args.specialArgs - // { - format = "darwin"; - }; - modules = - args.modules - ++ [ - ../../modules/darwin/user/default.nix - ]; - }); - linux-system-builder = args: - core-inputs.nixpkgs.lib.nixosSystem - (args - // { - specialArgs = - args.specialArgs - // { - format = "linux"; + specialArgs = args.specialArgs // { + format = virtual-system-type; }; - modules = - args.modules - ++ [ + modules = args.modules ++ [ ../../modules/nixos/user/default.nix ]; - }); - in - if virtual-system-type != "" - then virtual-system-builder - else if is-darwin target - then darwin-system-builder - else linux-system-builder; + } + ); + 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" + "modules" + ]) + // { + specialArgs = args.specialArgs // { + format = "darwin"; + }; + modules = args.modules ++ [ + ../../modules/darwin/user/default.nix + ]; + } + ); + linux-system-builder = + args: + core-inputs.nixpkgs.lib.nixosSystem ( + args + // { + specialArgs = args.specialArgs // { + format = "linux"; + }; + modules = args.modules ++ [ + ../../modules/nixos/user/default.nix + ]; + } + ); + 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. ## Example Usage: @@ -191,14 +204,17 @@ in { ## "darwinConfigurations" ## ``` #@ String -> String - 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-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. ## Example Usage: @@ -210,12 +226,15 @@ in { ## "x86_64-linux" ## ``` #@ String -> String - 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; + 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. ## Example Usage: @@ -227,42 +246,54 @@ in { ## ## ``` #@ Attrs -> Attrs - 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 ? {}, - homes ? {}, - }: let - lib = snowfall-lib.internal.system-lib; - home-system-modules = snowfall-lib.home.create-home-system-modules homes; - home-manager-module = - if is-darwin system - then user-inputs.home-manager.darwinModules.home-manager - else user-inputs.home-manager.nixosModules.home-manager; - home-manager-modules = [home-manager-module] ++ home-system-modules; - in { - inherit channelName system builder output; + 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 ? { }, + homes ? { }, + }: + let + lib = snowfall-lib.internal.system-lib; + home-system-modules = snowfall-lib.home.create-home-system-modules homes; + home-manager-module = + if is-darwin system then + user-inputs.home-manager.darwinModules.home-manager + else + user-inputs.home-manager.nixosModules.home-manager; + home-manager-modules = [ home-manager-module ] ++ home-system-modules; + in + { + inherit + channelName + system + builder + output + ; - modules = [path] ++ modules ++ (optionals (user-inputs ? home-manager) home-manager-modules); + modules = [ path ] ++ modules ++ (optionals (user-inputs ? home-manager) home-manager-modules); - specialArgs = - specialArgs - // { - inherit target system systems lib; + specialArgs = specialArgs // { + inherit + target + system + systems + lib + ; host = name; virtual = (get-virtual-system-type target) != ""; inputs = snowfall-lib.flake.without-src user-inputs; namespace = snowfall-config.namespace; }; - }; + }; ## Create all available systems. ## Example Usage: @@ -274,52 +305,49 @@ in { ## { my-host = ; } ## ``` #@ Attrs -> Attrs - create-systems = { - systems ? {}, - homes ? {}, - }: let - targets = snowfall-lib.fs.get-directories user-systems-root; - target-systems-metadata = concatMap get-target-systems-metadata targets; - user-nixos-modules = snowfall-lib.module.create-modules { - src = "${user-modules-root}/nixos"; - }; - user-darwin-modules = snowfall-lib.module.create-modules { - src = "${user-modules-root}/darwin"; - }; - nixos-modules = systems.modules.nixos or []; - darwin-modules = systems.modules.darwin or []; + create-systems = + { + systems ? { }, + homes ? { }, + }: + let + targets = snowfall-lib.fs.get-directories user-systems-root; + target-systems-metadata = concatMap get-target-systems-metadata targets; + user-nixos-modules = snowfall-lib.module.create-modules { + src = "${user-modules-root}/nixos"; + }; + user-darwin-modules = snowfall-lib.module.create-modules { + src = "${user-modules-root}/darwin"; + }; + nixos-modules = systems.modules.nixos or [ ]; + darwin-modules = systems.modules.darwin or [ ]; - create-system' = created-systems: system-metadata: let - overrides = systems.hosts.${system-metadata.name} or {}; - user-modules = - if is-darwin system-metadata.target - then user-darwin-modules - else user-nixos-modules; - user-modules-list = builtins.attrValues user-modules; - system-modules = - if is-darwin system-metadata.target - then darwin-modules - else nixos-modules; - in { - ${system-metadata.name} = create-system (overrides - // system-metadata - // { - systems = created-systems; - modules = user-modules-list ++ (overrides.modules or []) ++ system-modules; - inherit homes; - }); - }; - created-systems = fix ( - created-systems: - foldl - ( - systems: system-metadata: - systems // (create-system' created-systems system-metadata) - ) - {} - target-systems-metadata - ); - in + create-system' = + created-systems: system-metadata: + let + overrides = systems.hosts.${system-metadata.name} or { }; + user-modules = if is-darwin system-metadata.target then user-darwin-modules else user-nixos-modules; + user-modules-list = builtins.attrValues user-modules; + system-modules = if is-darwin system-metadata.target then darwin-modules else nixos-modules; + in + { + ${system-metadata.name} = create-system ( + overrides + // system-metadata + // { + systems = created-systems; + modules = user-modules-list ++ (overrides.modules or [ ]) ++ system-modules; + inherit homes; + } + ); + }; + created-systems = fix ( + created-systems: + foldl ( + systems: system-metadata: systems // (create-system' created-systems system-metadata) + ) { } target-systems-metadata + ); + in created-systems; }; } diff --git a/snowfall-lib/template/default.nix b/snowfall-lib/template/default.nix index 91c5ef2..8ef21a5 100644 --- a/snowfall-lib/template/default.nix +++ b/snowfall-lib/template/default.nix @@ -3,12 +3,14 @@ user-inputs, snowfall-lib, snowfall-config, -}: let +}: +let inherit (builtins) baseNameOf; inherit (core-inputs.nixpkgs.lib) assertMsg foldl mapAttrs; user-templates-root = snowfall-lib.fs.get-snowfall-file "templates"; -in { +in +{ template = { ## Create flake templates. ## @@ -22,43 +24,42 @@ in { ## { another-template = ...; my-template = ...; default = ...; } ## ``` #@ Attrs -> Attrs - create-templates = { - src ? user-templates-root, - overrides ? {}, - alias ? {}, - }: let - user-templates = snowfall-lib.fs.get-directories src; - create-template-metadata = template: let - flake-file = template + "/flake.nix"; - has-flake = builtins.pathExists flake-file; - flake-attrs = - if has-flake - then import flake-file - else {}; - description = flake-attrs.description or null; - in - { - name = builtins.unsafeDiscardStringContext (baseNameOf template); - path = template; - } - // ( - if description != null - then {inherit description;} - else {} + create-templates = + { + src ? user-templates-root, + overrides ? { }, + alias ? { }, + }: + let + user-templates = snowfall-lib.fs.get-directories src; + create-template-metadata = + template: + let + flake-file = template + "/flake.nix"; + has-flake = builtins.pathExists flake-file; + flake-attrs = if has-flake then import flake-file else { }; + description = flake-attrs.description or null; + in + { + name = builtins.unsafeDiscardStringContext (baseNameOf template); + path = template; + } + // (if description != null then { inherit description; } else { }); + templates-metadata = builtins.map create-template-metadata user-templates; + merge-templates = + templates: metadata: + templates + // { + ${metadata.name} = + (overrides.${metadata.name} or { }) // (builtins.removeAttrs metadata [ "name" ]); + }; + templates-without-aliases = foldl merge-templates { } templates-metadata; + aliased-templates = mapAttrs (name: value: templates-without-aliases.${value}) alias; + unused-overrides = builtins.removeAttrs overrides ( + builtins.map (metadata: metadata.name) templates-metadata ); - templates-metadata = builtins.map create-template-metadata user-templates; - merge-templates = templates: metadata: - templates - // { - ${metadata.name} = - (overrides.${metadata.name} or {}) - // (builtins.removeAttrs metadata ["name"]); - }; - templates-without-aliases = foldl merge-templates {} templates-metadata; - aliased-templates = mapAttrs (name: value: templates-without-aliases.${value}) alias; - unused-overrides = builtins.removeAttrs overrides (builtins.map (metadata: metadata.name) templates-metadata); - templates = templates-without-aliases // aliased-templates // unused-overrides; - in + templates = templates-without-aliases // aliased-templates // unused-overrides; + in templates; }; }