diff --git a/default.nix b/default.nix index 2cccff2..c7d0c26 100644 --- a/default.nix +++ b/default.nix @@ -1,10 +1,14 @@ -(import +( + 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; - } + 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 + {src = ./.;} +) +.defaultNix diff --git a/flake.lock b/flake.lock index 09d501f..81a831c 100644 --- a/flake.lock +++ b/flake.lock @@ -54,16 +54,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1677028070, - "narHash": "sha256-sUKqd8HYBrtPxCRXFWvsnQDnwqnw1uIDwu4khcZuL2k=", + "lastModified": 1716181197, + "narHash": "sha256-IXOUlMlt0f5n9BoJ56+CseCLV9aaBDoEygIWV/hnUso=", "owner": "nixos", "repo": "nixpkgs", - "rev": "d3a15cd8dc917f4364ba0b332a1c389dc3177603", + "rev": "461aad7a53142b9f9e2a666c810e86b20f5da76b", "type": "github" }, "original": { "owner": "nixos", - "ref": "release-22.11", + "ref": "release-23.11", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index a1ab023..470cc1b 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "Snowfall Lib"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/release-22.11"; + nixpkgs.url = "github:nixos/nixpkgs/release-23.11"; flake-utils-plus.url = "github:gytis-ivaskevicius/flake-utils-plus"; flake-compat = { @@ -11,75 +11,86 @@ }; }; - outputs = inputs: - let - core-inputs = inputs // { + outputs = inputs: let + core-inputs = + inputs + // { src = ./.; }; - # Create the library, extending the nixpkgs library and merging - # libraries from other inputs to make them available like - # `lib.flake-utils-plus.mkApp`. - # Usage: mkLib { inherit inputs; src = ./.; } - # result: lib - mkLib = import ./snowfall-lib core-inputs; + # 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 ? { }, ... }: - let - lib = mkLib { - inherit inputs src snowfall; - }; - flake-options = builtins.removeAttrs flake-and-lib-options [ "inputs" "src" ]; - in - lib.mkFlake flake-options; + # 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 - { - inherit mkLib mkFlake; + lib.mkFlake flake-options; + in { + inherit mkLib mkFlake; - nixosModules = { - user = ./modules/nixos/user/default.nix; - }; + nixosModules = { + user = ./modules/nixos/user/default.nix; + }; - darwinModules = { - user = ./modules/darwin/user/default.nix; - }; + darwinModules = { + user = ./modules/darwin/user/default.nix; + }; - homeModules = { - user = ./modules/home/user/default.nix; - }; + homeModules = { + user = ./modules/home/user/default.nix; + }; - _snowfall = rec { + formatter = { + x86_64-linux = inputs.nixpkgs.legacyPackages.x86_64-linux.alejandra; + aarch64-linux = inputs.nixpkgs.legacyPackages.aarch64-linux.alejandra; + x86_64-darwin = inputs.nixpkgs.legacyPackages.x86_64-darwin.alejandra; + aarch64-darwin = inputs.nixpkgs.legacyPackages.aarch64-darwin.alejandra; + }; - raw-config = config; + snowfall = rec { + raw-config = config; - config = { - root = ./.; - src = ./.; - namespace = "snowfall"; - lib-dir = "snowfall-lib"; + config = { + root = ./.; + src = ./.; + namespace = "snowfall"; + lib-dir = "snowfall-lib"; - meta = { - name = "snowfall-lib"; - title = "Snowfall Lib"; - }; + meta = { + name = "snowfall-lib"; + title = "Snowfall Lib"; }; + }; - internal-lib = - let - lib = mkLib { - src = ./.; + internal-lib = let + lib = mkLib { + src = ./.; - inputs = inputs // { - self = { }; - }; + inputs = + inputs + // { + self = {}; }; - in - builtins.removeAttrs - lib.snowfall - [ "internal" ]; - }; + }; + in + builtins.removeAttrs + lib.snowfall + ["internal"]; }; + }; } diff --git a/modules/darwin/user/default.nix b/modules/darwin/user/default.nix index 28f0931..a0303d6 100644 --- a/modules/darwin/user/default.nix +++ b/modules/darwin/user/default.nix @@ -1,29 +1,45 @@ -{ pkgs, lib, options, config, inputs, ... }: - -let - inherit (lib) types mkOption mkDefault foldl optionalAttrs; +{ + pkgs, + lib, + options, + config, + inputs, + ... +}: let + inherit + (lib) + types + mkOption + mkDefault + mkRenamedOptionModule + foldl + optionalAttrs + ; cfg = config.snowfallorg; - user-names = builtins.attrNames cfg.user; + user-names = builtins.attrNames cfg.users; - create-system-users = system-users: name: - let - user = cfg.user.${name}; - in - system-users // (optionalAttrs user.create { + create-system-users = system-users: name: let + user = cfg.users.${name}; + in + system-users + // (optionalAttrs user.create { ${name} = { home = mkDefault user.home.path; isHidden = mkDefault false; }; }); -in -{ +in { + imports = [ + (mkRenamedOptionModule ["snowfallorg" "user"] ["snowfallorg" "users"]) + ]; + options.snowfallorg = { - user = mkOption { + users = mkOption { description = "User configuration."; - default = { }; - type = types.attrsOf (types.submodule ({ name, ... }: { + default = {}; + type = types.attrsOf (types.submodule ({name, ...}: { options = { create = mkOption { description = "Whether to create the user automatically."; @@ -46,28 +62,36 @@ in # 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; - }; + 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 = cfg.useUserPackages; + config = { + submoduleSupport.enable = true; + submoduleSupport.externalPackageInstall = cfg.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; }; }; }; @@ -77,6 +101,6 @@ in }; 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 7c7c93a..4f04b62 100644 --- a/modules/home/user/default.nix +++ b/modules/home/user/default.nix @@ -1,25 +1,27 @@ -inputs@{ pkgs, lib, options, config, ... }: - -let +inputs @ { + pkgs, + lib, + options, + config, + ... +}: let inherit (lib) types mkOption mkIf mkDefault; cfg = config.snowfallorg; - # @NOTE(jakehamilton): The module system chokes if it finds `osConfig` named in the module arguments + # NOTE: The module system chokes if it finds `osConfig` named in the module arguments # when being used in standalone home-manager. To remedy this, we have to refer to the arguments set directly. os-user-home = inputs.osConfig.users.users.${cfg.name}.home or null; 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 e8483f1..b19d155 100644 --- a/modules/nixos/user/default.nix +++ b/modules/nixos/user/default.nix @@ -1,19 +1,32 @@ -args@{ pkgs, lib, options, config, ... }: - -let - inherit (lib) types mkOption mkDefault foldl optionalAttrs optional; +args @ { + pkgs, + lib, + options, + config, + ... +}: let + inherit + (lib) + types + mkOption + mkDefault + mkRenamedOptionModule + foldl + optionalAttrs + optional + ; cfg = config.snowfallorg; - inputs = args.inputs or { }; + inputs = args.inputs or {}; - user-names = builtins.attrNames cfg.user; + user-names = builtins.attrNames cfg.users; - create-system-users = system-users: name: - let - user = cfg.user.${name}; - in - system-users // (optionalAttrs user.create { + create-system-users = system-users: name: let + user = cfg.users.${name}; + in + system-users + // (optionalAttrs user.create { ${name} = { isNormalUser = mkDefault true; @@ -25,14 +38,16 @@ let extraGroups = optional user.admin "wheel"; }; }); +in { + imports = [ + (mkRenamedOptionModule ["snowfallorg" "user"] ["snowfallorg" "users"]) + ]; -in -{ options.snowfallorg = { - user = mkOption { + users = mkOption { description = "User configuration."; - default = { }; - type = types.attrsOf (types.submodule ({ name, ... }: { + default = {}; + type = types.attrsOf (types.submodule ({name, ...}: { options = { create = mkOption { description = "Whether to create the user automatically."; @@ -60,32 +75,42 @@ in config = mkOption { # HM-compatible options taken from: # https://github.com/nix-community/home-manager/blob/0ee5ab611dc1fbb5180bd7d88d2aeb7841a4d179/nixos/common.nix#L14 - # @NOTE(jakehamilton): This has been adapted to support documentation generation without + # 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 = cfg.useUserPackages; - - 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 [ ]); + 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 = cfg.useUserPackages; + + 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 []); }; }; }; @@ -95,6 +120,6 @@ in }; 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 ea5dbee..2f7e0bd 100644 --- a/snowfall-lib/attrs/default.nix +++ b/snowfall-lib/attrs/default.nix @@ -1,11 +1,11 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let - inherit (core-inputs.nixpkgs.lib) +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let + inherit + (core-inputs.nixpkgs.lib) assertMsg mapAttrsToList mapAttrs @@ -13,9 +13,9 @@ let foldl recursiveUpdate mergeAttrs - isDerivation; -in -{ + isDerivation + ; +in { attrs = { ## Map and flatten an attribute set into a list. ## 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: @@ -66,19 +66,21 @@ in #@ [Attrs] -> Attrs 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 + ( + 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; + ) + {} + items; }; } diff --git a/snowfall-lib/checks/default.nix b/snowfall-lib/checks/default.nix new file mode 100644 index 0000000..9a59769 --- /dev/null +++ b/snowfall-lib/checks/default.nix @@ -0,0 +1,56 @@ +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let + inherit (core-inputs.flake-utils-plus.lib) filterPackages; + inherit (core-inputs.nixpkgs.lib) assertMsg foldl mapAttrs callPackageWith; + + user-checks-root = snowfall-lib.fs.get-snowfall-file "checks"; +in { + check = { + ## Create flake output packages. + ## Example Usage: + ## ```nix + ## create-checks { inherit channels; src = ./my-checks; overrides = { inherit another-check; }; alias = { default = "another-check"; }; } + ## ``` + ## Result: + ## ```nix + ## { 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; + }; + 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 + filterPackages pkgs.system checks; + }; +} diff --git a/snowfall-lib/default.nix b/snowfall-lib/default.nix index 4b4b70d..aa0d199 100644 --- a/snowfall-lib/default.nix +++ b/snowfall-lib/default.nix @@ -1,37 +1,36 @@ -# @NOTE(jakehamilton): The role of this file is to bootstrap the +# NOTE: The role of this file is to bootstrap the # Snowfall library. There is some duplication shared between this # file and the library itself due to the library needing to pass through # another extended library for its own applications. -core-inputs: -user-options: - -let - 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; + 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` @@ -39,47 +38,47 @@ 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); - # @NOTE(jakehamilton): This root is different to accomodate the creation + # 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 = fix ( + snowfall-lib: let attrs = { inherit snowfall-lib snowfall-config core-inputs user-inputs; }; - libs = builtins.map + 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; @@ -89,24 +88,34 @@ 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 = fix ( + user-lib: let attrs = { inherit (user-options) inputs; snowfall-inputs = core-inputs; - lib = merge-shallow [ base-lib { ${snowfall-config.namespace} = user-lib; } ]; + namespace = snowfall-config.namespace; + lib = merge-shallow [base-lib {${snowfall-config.namespace} = user-lib;}]; }; - libs = builtins.map - (path: callPackageWith attrs path { }) + 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 [ @@ -117,6 +126,5 @@ 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 afd037e..65cbe30 100644 --- a/snowfall-lib/flake/default.nix +++ b/snowfall-lib/flake/default.nix @@ -1,13 +1,11 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let inherit (core-inputs.nixpkgs.lib) assertMsg foldl filterAttrs const; -in -rec { +in rec { flake = rec { ## Remove the `self` attribute from an attribute set. ## Example Usage: @@ -19,7 +17,7 @@ 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: @@ -31,7 +29,7 @@ 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: @@ -57,22 +55,23 @@ rec { #@ Attrs -> Attrs without-snowfall-options = flake-options: builtins.removeAttrs - flake-options - [ - "systems" - "modules" - "overlays" - "packages" - "outputs-builder" - "outputsBuilder" - "packagesPrefix" - "hosts" - "channels-config" - "templates" - "package-namespace" - "alias" - "snowfall" - ]; + flake-options + [ + "systems" + "modules" + "overlays" + "packages" + "outputs-builder" + "outputsBuilder" + "packagesPrefix" + "hosts" + "homes" + "channels-config" + "templates" + "checks" + "alias" + "snowfall" + ]; ## Transform an attribute set of inputs into an attribute set where the values are the inputs' `lib` attribute. Entries without a `lib` attribute are removed. ## Example Usage: @@ -84,80 +83,85 @@ 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 - package-namespace = full-flake-options.package-namespace or 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 { }; + 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 {}; + }; + + 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 {}; }; - 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 { }; + shells = snowfall-lib.shell.create-shells { + inherit channels; + overrides = (full-flake-options.shells or {}) // (user-outputs.devShells or {}); + alias = alias.shells 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 { }; + checks = snowfall-lib.check.create-checks { + inherit channels; + overrides = (full-flake-options.checks or {}) // (user-outputs.checks or {}); + alias = alias.checks 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 package-namespace; - extra-overlays = full-flake-options.extra-exported-overlays or { }; + + outputs = { + inherit packages checks; + + devShells = shells; }; + in + snowfall-lib.attrs.merge-deep [user-outputs outputs]; - 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 package-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 { }; - }; - - outputs = { - inherit packages; - - devShells = shells; - }; - in - snowfall-lib.attrs.merge-deep [ user-outputs outputs ]; - - flake-options = custom-flake-options // { + flake-options = + custom-flake-options + // { inherit hosts templates; inherit (user-inputs) self; @@ -168,29 +172,30 @@ rec { darwinModules = darwin-modules; homeModules = home-modules; - channelsConfig = full-flake-options.channels-config or { }; + channelsConfig = full-flake-options.channels-config or {}; channels.nixpkgs.overlaysBuilder = snowfall-lib.overlay.create-overlays-builder { - inherit package-namespace; - extra-overlays = full-flake-options.overlays or [ ]; + inherit namespace; + extra-overlays = full-flake-options.overlays or []; }; outputsBuilder = outputs-builder; - _snowfall = { + 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 // { - inherit overlays; - }; - in + flake-outputs = + flake-utils-plus-outputs + // { + inherit overlays; + }; + in flake-outputs; } diff --git a/snowfall-lib/fp/default.nix b/snowfall-lib/fp/default.nix index 04dd03c..1f9fdd9 100644 --- a/snowfall-lib/fp/default.nix +++ b/snowfall-lib/fp/default.nix @@ -1,14 +1,12 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let inherit (builtins) baseNameOf dirOf; inherit (core-inputs.nixpkgs.lib) id foldr flip; -in -{ +in { fp = rec { ## Compose two functions. ## Example Usage: diff --git a/snowfall-lib/fs/default.nix b/snowfall-lib/fs/default.nix index 3877408..c91bc1d 100644 --- a/snowfall-lib/fs/default.nix +++ b/snowfall-lib/fs/default.nix @@ -1,17 +1,15 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let inherit (builtins) readDir pathExists; inherit (core-inputs) flake-utils-plus; 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: @@ -38,7 +36,7 @@ in ## "/user-source/systems" ## ``` #@ Path -> Path - get-file = path: "${user-inputs.src}/${path}"; + get-file = path: user-inputs.src + "/${path}"; ## Get a file path relative to the user's snowfall directory. ## Example Usage: @@ -50,7 +48,7 @@ in ## "/user-source/snowfall-dir/systems" ## ``` #@ Path -> Path - get-snowfall-file = path: "${snowfall-config.root}/${path}"; + get-snowfall-file = path: snowfall-config.root + "/${path}"; ## Get a file path relative to the this flake. ## Example Usage: @@ -62,7 +60,7 @@ in ## "/user-source/systems" ## ``` #@ Path -> Path - internal-get-file = path: "${core-inputs.src}/${path}"; + internal-get-file = path: core-inputs.src + "/${path}"; ## Safely read from a directory if it exists. ## Example Usage: @@ -75,10 +73,9 @@ in ## ``` #@ Path -> Attrs safe-read-directory = path: - if pathExists path then - readDir path - else - { }; + if pathExists path + then readDir path + else {}; ## Get directories at a given path. ## Example Usage: @@ -90,11 +87,10 @@ 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. @@ -107,11 +103,10 @@ 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. @@ -124,25 +119,23 @@ 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}"; - 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; + get-files-recursive = path: let + entries = safe-read-directory path; + filtered-entries = + filterAttrs + (name: kind: (is-file-kind kind) || (is-directory-kind kind)) + entries; + map-file = name: kind: let + path' = "${path}/${name}"; in + if is-directory-kind kind + then get-files-recursive path' + else path'; + files = + snowfall-lib.attrs.map-concat-attrs-to-list + map-file + filtered-entries; + in files; ## Get nix files at a given path. @@ -157,8 +150,8 @@ in #@ Path -> [Path] get-nix-files = path: builtins.filter - (snowfall-lib.path.has-file-extension "nix") - (get-files path); + (snowfall-lib.path.has-file-extension "nix") + (get-files path); ## Get nix files at a given path, traversing any directories within. ## Example Usage: @@ -172,8 +165,8 @@ in #@ Path -> [Path] get-nix-files-recursive = path: builtins.filter - (snowfall-lib.path.has-file-extension "nix") - (get-files-recursive path); + (snowfall-lib.path.has-file-extension "nix") + (get-files-recursive path); ## Get nix files at a given path named "default.nix". ## Example Usage: @@ -187,8 +180,8 @@ in #@ Path -> [Path] get-default-nix-files = path: builtins.filter - (name: builtins.baseNameOf name == "default.nix") - (get-files path); + (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: @@ -202,8 +195,8 @@ in #@ Path -> [Path] get-default-nix-files-recursive = path: builtins.filter - (name: builtins.baseNameOf name == "default.nix") - (get-files-recursive path); + (name: builtins.baseNameOf name == "default.nix") + (get-files-recursive path); ## Get nix files at a given path not named "default.nix". ## Example Usage: @@ -217,11 +210,12 @@ in #@ Path -> [Path] get-non-default-nix-files = path: builtins.filter - (name: + ( + name: (snowfall-lib.path.has-file-extension "nix" name) && (builtins.baseNameOf name != "default.nix") - ) - (get-files path); + ) + (get-files path); ## Get nix files at a given path not named "default.nix", traversing any directories within. ## Example Usage: @@ -235,10 +229,11 @@ in #@ Path -> [Path] get-non-default-nix-files-recursive = path: builtins.filter - (name: + ( + name: (snowfall-lib.path.has-file-extension "nix" name) && (builtins.baseNameOf name != "default.nix") - ) - (get-files-recursive path); + ) + (get-files-recursive path); }; } diff --git a/snowfall-lib/home/default.nix b/snowfall-lib/home/default.nix index e8d1844..174d578 100644 --- a/snowfall-lib/home/default.nix +++ b/snowfall-lib/home/default.nix @@ -1,11 +1,11 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let - inherit (core-inputs.nixpkgs.lib) +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let + inherit + (core-inputs.nixpkgs.lib) assertMsg foldl head @@ -23,29 +23,31 @@ let mkAliasDefinitions mkAliasAndWrapDefinitions mkOption - types; + types + hasInfix + hasSuffix + ; 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(jakehamilton): This prevents an error during evaluation if the input does + # NOTE: This prevents an error during evaluation if the input does # not exist. - if user-inputs ? home-manager then + if user-inputs ? home-manager + then snowfall-lib.internal.system-lib.extend - (final: prev: - # @NOTE(jakehamilton): This order is important, this library's extend and other utilities must write - # _over_ the original `system-lib`. + (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 - { }; + else {}; ## Get the user and host from a combined string. ## Example Usage: @@ -57,22 +59,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; - - user = builtins.elemAt name-parts 0; - host = - if builtins.length name-parts > 1 then - builtins.elemAt name-parts 1 - else - ""; - in - { - inherit user host; - }; - + 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; + }; ## Create a home. ## Example Usage: @@ -84,61 +82,67 @@ 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; - - # @NOTE(jakehamilton): 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 + 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; + + # 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 != "") "Snowfall Lib homes must be named with the format: user@system"; - { + 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 name; + inherit name system; inherit (user-metadata) user host; format = "home"; inputs = snowfall-lib.flake.without-src user-inputs; + namespace = snowfall-config.namespace; - # @NOTE(jakehamilton): home-manager has trouble with `pkgs` recursion if it isn't passed in here. + # NOTE: home-manager has trouble with `pkgs` recursion if it isn't passed in here. inherit pkgs lib; }; builder = args: user-inputs.home-manager.lib.homeManagerConfiguration - ((builtins.removeAttrs args [ "system" "specialArgs" ]) // { + ((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; }); @@ -154,23 +158,22 @@ 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: { - 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. - system = builtins.unsafeDiscardStringContext (builtins.baseNameOf target); - }; - 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: { + 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. + system = builtins.unsafeDiscardStringContext (builtins.baseNameOf target); + }; + home-configurations = builtins.map create-home-metadata existing-homes; + in home-configurations; ## Create all available homes. @@ -183,34 +186,36 @@ 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, ... }: (module args) // { + user-home-modules-list = + mapAttrsToList + (module-path: module: args @ {pkgs, ...}: + (module args) + // { _file = "${user-homes-root}/${module-path}/default.nix"; }) - 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 [ ]); - }); - }; + 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 []); + }); + }; - 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. @@ -223,84 +228,95 @@ 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"; - }; - - shared-modules = mapAttrsToList - (module-path: module: { - _file = "${user-modules-root}/home/${module-path}/default.nix"; + create-home-system-modules = users: let + created-users = create-homes users; + user-home-modules = snowfall-lib.module.create-modules { + src = "${user-modules-root}/home"; + }; - config = { - home-manager.sharedModules = [ module ]; - }; - }) - user-home-modules; + shared-modules = builtins.map (module: { + config.home-manager.sharedModules = [module]; + }) (users.modules or []); - snowfall-user-home-module = { - _file = "virtual:snowfallorg/modules/home/user/default.nix"; + shared-user-modules = + mapAttrsToList + (module-path: module: { + _file = "${user-modules-root}/home/${module-path}/default.nix"; config = { - home-manager.sharedModules = [ - ../../modules/home/user/default.nix - ]; + home-manager.sharedModules = [module]; }; + }) + user-home-modules; + + 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.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; - - lib = home-lib; - - inputs = snowfall-lib.flake.without-src user-inputs; - }; - }; + extra-special-args-module = args @ { + config, + pkgs, + system ? pkgs.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; + + 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 [ ]; - user-name = created-user.specialArgs.user; - in - args@{ config - , options - , pkgs - , host ? "" - , ... - }: - let - host-matches = created-user.specialArgs.host == host; - - # @NOTE(jakehamilton): To conform to the config structure of home-manager, we have to + system-modules = + builtins.map + ( + name: let + created-user = created-users.${name}; + user-module = head created-user.modules; + other-modules = users.users.${name}.modules or []; + user-name = created-user.specialArgs.user; + in + args @ { + config, + options, + pkgs, + host ? "", + system ? pkgs.system, + ... + }: let + host-matches = + (created-user.specialArgs.host == host) + || (created-user.specialArgs.host == "" && created-user.specialArgs.system == 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 { } + 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; } @@ -308,43 +324,56 @@ in (builtins.trace '' ============= Snowfall Lib: - Option value for `snowfallorg.user.${user-name}` was not detected to be merged. + 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 ============= '') - user-option; - in - { + user-option; + + home-config = mkAliasAndWrapDefinitions wrap-user-options options.snowfallorg.users; + in { _file = "virtual:snowfallorg/home/user/${name}"; config = mkIf host-matches { # Initialize user information. - snowfallorg.user.${user-name}.home.config = { + snowfallorg.users.${user-name}.home.config = { snowfallorg.user = { - enable = true; + 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"]; }; home-manager = { - users.${user-name} = mkAliasAndWrapDefinitions wrap-user-options options.snowfallorg.user; - - # sharedModules = other-modules ++ optional config.snowfallorg.user.${user-name}.home.enable wrapped-user-module; - sharedModules = other-modules ++ optional config.snowfallorg.user.${user-name}.home.enable user-module; + 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 + ) + (builtins.attrNames created-users); + in [ extra-special-args-module snowfall-user-home-module ] - ++ (users.modules or [ ]) ++ shared-modules + ++ shared-user-modules ++ system-modules; }; } diff --git a/snowfall-lib/home/nix-registry-module.nix b/snowfall-lib/home/nix-registry-module.nix index c15f9e2..200da73 100644 --- a/snowfall-lib/home/nix-registry-module.nix +++ b/snowfall-lib/home/nix-registry-module.nix @@ -1,8 +1,12 @@ # This code is adapted from flake-utils-plus: # https://github.com/gytis-ivaskevicius/flake-utils-plus/blob/2bf0f91643c2e5ae38c1b26893ac2927ac9bd82a/lib/options.nix -{ lib, config, user-inputs, core-inputs, ... }: - { + lib, + config, + 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 e61eb73..be5503c 100644 --- a/snowfall-lib/internal/default.nix +++ b/snowfall-lib/internal/default.nix @@ -1,11 +1,10 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let - inherit (core-inputs.nixpkgs.lib) assertMsg fix fold filterAttrs callPackageWith; +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: 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); @@ -17,35 +16,44 @@ let core-inputs-libs user-inputs-libs snowfall-top-level-lib - { snowfall = snowfall-lib; } + {snowfall = snowfall-lib;} ]; - user-lib-root = snowfall-lib.fs.get-file "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 = fix ( + 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 - { internal = user-lib; } + {internal = user-lib;} ]; }; - libs = builtins.map - (path: callPackageWith attrs path { }) + 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 7b12e45..62408ad 100644 --- a/snowfall-lib/module/default.nix +++ b/snowfall-lib/module/default.nix @@ -1,16 +1,14 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let inherit (builtins) baseNameOf; - inherit (core-inputs.nixpkgs.lib) assertMsg foldl mapAttrs hasPrefix; + inherit (core-inputs.nixpkgs.lib) foldl mapAttrs hasPrefix isFunction; user-modules-root = snowfall-lib.fs.get-snowfall-file "modules"; -in -{ +in { module = { ## Create flake output modules. ## Example Usage: @@ -22,65 +20,66 @@ 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 [ 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(jakehamilton): 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.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"; + 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 [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.system; + target = args.target or system; - # 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 { }; + 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; - pkgs = user-inputs.self.pkgs.${system}.nixpkgs; + lib = snowfall-lib.internal.system-lib; + pkgs = user-inputs.self.pkgs.${system}.nixpkgs; - inputs = snowfall-lib.flake.without-src user-inputs; - }; - user-module = import metadata.path modified-args; - 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 + 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 f1fd589..0aa19e9 100644 --- a/snowfall-lib/overlay/default.nix +++ b/snowfall-lib/overlay/default.nix @@ -1,190 +1,197 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: 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: ## ```nix - ## create-overlays { src = ./my-overlays; package-namespace = "my-packages"; } + ## create-overlays { src = ./my-overlays; namespace = "my-packages"; } ## ``` ## Result: ## ```nix ## (channels: [ ... ]) ## ``` #@ Attrs -> Attrs -> [(a -> b -> c)] - create-overlays-builder = - { src ? user-overlays-root - , package-namespace ? "internal" - , extra-overlays ? [ ] - }: channels: - let - user-overlays = snowfall-lib.fs.get-default-nix-files-recursive src; - create-overlay = overlay: import overlay (user-inputs // { inherit channels; }); - user-packages-overlay = final: prev: - let - user-packages = snowfall-lib.package.create-packages { - pkgs = final; - channels = channels; - }; - in - { - ${package-namespace} = - (prev.${package-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; + 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). ## ## Example Usage: ## ```nix - ## create-overlays { src = ./my-overlays; packages-src = ./my-packages; package-namespace = "my-namespace"; extra-overlays = {}; } + ## create-overlays { src = ./my-overlays; packages-src = ./my-packages; namespace = "my-namespace"; extra-overlays = {}; } ## ``` ## Result: ## ```nix ## { default = final: prev: ...; some-overlay = final: prev: ...; } ## ``` #@ Attrs -> Attrs - create-overlays = - { src ? user-overlays-root - , packages-src ? user-packages-root - , package-namespace ? null - , extra-overlays ? { } - }: - let - fake-pkgs = { - callPackage = x: x; - isFakePkgs = true; - lib = { }; - system = "fake-system"; - }; + 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; + user-overlays = snowfall-lib.fs.get-default-nix-files-recursive src; - channel-systems = user-inputs.self.pkgs; + 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}; - }; - in - if package-namespace == null then - user-packages - else - { - ${package-namespace} = - (prev.${package-namespace} or { }) - // user-packages; - }; + 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-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 (user-inputs // { inherit channels; }); - packages = user-packages-overlay final prev; - prev-with-packages = - if package-namespace == null then - prev // packages - else - prev // { - ${package-namespace} = - (prev.${package-namespace} or { }) - // packages.${package-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; } + 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 - outputs; - fake-overlay-result = overlay fake-pkgs fake-pkgs; + prev + // { + ${namespace} = + (prev.${namespace} or {}) + // packages.${namespace}; + }; + user-overlay-packages = + user-overlay + final + prev-with-packages; + outputs = + user-overlay-packages; in - if fake-overlay-result.__dontExport or false == true then - overlays + 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 // { + 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 { - channels = channel-systems.${prev.system}; - }; - in - if package-namespace == null then - { ${name} = packages.${name}; } - else - { - ${package-namespace} = - (prev.${package-namespace} or { }) - // { ${name} = packages.${name}; }; - }; - in - package-overlays // - { - "package/${name}" = overlay; + 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; + 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; + 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; + 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; + merged-results = + snowfall-lib.attrs.merge-shallow-packages + (package-overlays-results ++ overlays-results); in + merged-results; + in package-overlays // overlays - // { default = default-overlay; } + // {default = default-overlay;} // extra-overlays; }; } - diff --git a/snowfall-lib/package/default.nix b/snowfall-lib/package/default.nix index 3fea3b5..585708f 100644 --- a/snowfall-lib/package/default.nix +++ b/snowfall-lib/package/default.nix @@ -1,16 +1,14 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let inherit (core-inputs.flake-utils-plus.lib) filterPackages allSystems; 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: @@ -22,51 +20,54 @@ in ## { another-package = ...; my-package = ...; default = ...; } ## ``` #@ Attrs -> Attrs - create-packages = - { channels - , src ? user-packages-root - , pkgs ? channels.nixpkgs - , overrides ? { } - , alias ? { } - , package-namespace ? "internal" - }: - let - user-packages = snowfall-lib.fs.get-default-nix-files-recursive src; - create-package-metadata = package: - let - namespaced-packages = { - ${package-namespace} = packages-without-aliases; - }; - extra-inputs = pkgs // namespaced-packages // { - inherit channels; - lib = snowfall-lib.internal.system-lib; - pkgs = pkgs // namespaced-packages; - inputs = snowfall-lib.flake.without-snowfall-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; - }; + 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 {}) + // { + 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.system packages; }; } diff --git a/snowfall-lib/path/default.nix b/snowfall-lib/path/default.nix index d09173e..7d35455 100644 --- a/snowfall-lib/path/default.nix +++ b/snowfall-lib/path/default.nix @@ -1,16 +1,14 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: 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: @@ -22,12 +20,10 @@ 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: @@ -39,10 +35,9 @@ 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. @@ -56,13 +51,12 @@ in ## ``` #@ String -> String get-file-extension = file: - if has-any-file-extension file then - let - match = builtins.match file-name-regex (toString file); - in + 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: @@ -75,10 +69,9 @@ in ## ``` #@ String -> String -> Bool has-file-extension = extension: file: - if has-any-file-extension file then - extension == get-file-extension file - else - false; + if has-any-file-extension file + then extension == get-file-extension file + else false; ## Get the parent directory for a given path. ## Example Usage: @@ -102,13 +95,11 @@ 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 c1cb6a7..20668dc 100644 --- a/snowfall-lib/shell/default.nix +++ b/snowfall-lib/shell/default.nix @@ -1,16 +1,14 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let inherit (core-inputs.flake-utils-plus.lib) filterPackages; 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: @@ -22,36 +20,37 @@ 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; - }; - 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; + 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; }; - 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 + 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 filterPackages pkgs.system shells; }; } diff --git a/snowfall-lib/system/default.nix b/snowfall-lib/system/default.nix index 5e3e345..95b9e9f 100644 --- a/snowfall-lib/system/default.nix +++ b/snowfall-lib/system/default.nix @@ -1,10 +1,9 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: let inherit (builtins) dirOf baseNameOf; inherit (core-inputs.nixpkgs.lib) assertMsg fix hasInfix concatMap foldl optionals singleton; @@ -12,8 +11,7 @@ let 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: @@ -26,10 +24,9 @@ in ## ``` #@ 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; + 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: @@ -80,14 +77,14 @@ in #@ String -> String get-virtual-system-type = target: foldl - (result: virtual-system: - if result == "" && hasInfix virtual-system target then - virtual-system - else - result - ) - "" - virtual-systems; + ( + result: virtual-system: + if result == "" && hasInfix virtual-system target + then virtual-system + else result + ) + "" + virtual-systems; ## Get structured data about all systems for a given target. ## Example Usage: @@ -99,23 +96,22 @@ 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. @@ -128,49 +124,62 @@ 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."; + 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 // { + (args + // { format = virtual-system-type; - specialArgs = args.specialArgs // { - format = virtual-system-type; - }; - modules = args.modules ++ [ - ../../modules/nixos/user/default.nix - ]; + 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."; + 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 - ]; + ((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 // { + linux-system-builder = args: + core-inputs.nixpkgs.lib.nixosSystem + (args + // { + specialArgs = + args.specialArgs + // { format = "linux"; }; - 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; + }); + 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: @@ -182,16 +191,14 @@ 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: @@ -203,14 +210,12 @@ 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: @@ -222,42 +227,42 @@ 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 // { + 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: @@ -269,50 +274,52 @@ 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: + 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: system-metadata: systems // (create-system' created-systems system-metadata) - ) - { } - target-systems-metadata - ); - in + ) + {} + target-systems-metadata + ); + in created-systems; }; } diff --git a/snowfall-lib/system/virtual-systems.nix b/snowfall-lib/system/virtual-systems.nix index b7dac48..6690c08 100644 --- a/snowfall-lib/system/virtual-systems.nix +++ b/snowfall-lib/system/virtual-systems.nix @@ -1,4 +1,4 @@ -# @NOTE(jakehamilton): The order of these entries matters. We search them +# NOTE: The order of these entries matters. We search them # from start to finish and only match based on whether they appear in a # system target. This means that entries like "vm" would match all cases # of "vm-bootloader", "vm-no-gui", and "vmware". To avoid this mismatch, @@ -10,8 +10,8 @@ "docker" "do" "gce" - "hyperv" "install-iso-hyperv" + "hyperv" "install-iso" "iso" "kexec" diff --git a/snowfall-lib/template/default.nix b/snowfall-lib/template/default.nix index 40099e7..59b2144 100644 --- a/snowfall-lib/template/default.nix +++ b/snowfall-lib/template/default.nix @@ -1,16 +1,14 @@ -{ core-inputs -, user-inputs -, snowfall-lib -, snowfall-config -}: - -let +{ + core-inputs, + user-inputs, + snowfall-lib, + snowfall-config, +}: 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. ## @@ -24,28 +22,33 @@ 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: { - name = builtins.unsafeDiscardStringContext (baseNameOf template); - path = template; - }; - templates-metadata = builtins.map create-template-metadata user-templates; - merge-templates = templates: metadata: - templates // { - ${metadata.name} = (overrides.${metadata.name} or { }) // { + create-templates = { + src ? user-templates-root, + overrides ? {}, + alias ? {}, + }: let + user-templates = snowfall-lib.fs.get-directories src; + create-template-metadata = template: { + name = builtins.unsafeDiscardStringContext (baseNameOf template); + path = template; + }; + templates-metadata = builtins.map create-template-metadata user-templates; + merge-templates = templates: metadata: + templates + // { + ${metadata.name} = + (builtins.trace "name: ${metadata.name}") + (builtins.trace "path: ${metadata.path}") + (overrides.${metadata.name} or {}) + // { inherit (metadata) path; }; - }; - templates-without-aliases = foldl merge-templates { } templates-metadata; - aliased-templates = mapAttrs (name: value: templates-without-aliases.${value}) alias; - templates = templates-without-aliases // aliased-templates // overrides; - in + }; + 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; }; }