diff --git a/ChangeLog.md b/ChangeLog.md index 79f5b95..02182ef 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,10 @@ +# 2022-12-25 + + - Added a new `flake.flakeModules` option so a flake can expose a module + to be used in a downstream flake's flake-parts usage. `.flakeModule` is + now an alias for `.flakeModules.default`. + + Option only available if `flake-parts.flakeModules.flakeModules` is imported. # 2022-12-17 @@ -30,7 +37,7 @@ - The `nixpkgs` input has been renamed to `nixpkgs-lib` to signify that the only dependency is on the `lib` attribute, which can be provided by either the `nixpkgs?dir=lib` subflake or by the `nixpkgs` flake itself. - + - The templates now use the default, _fixed_ `nixpkgs?dir=lib` dependency instead of a _following_ `nixpkgs` dependency. diff --git a/flake.nix b/flake.nix index dd038a8..3a3949e 100644 --- a/flake.nix +++ b/flake.nix @@ -7,6 +7,7 @@ outputs = { self, nixpkgs-lib, ... }: { lib = import ./lib.nix { inherit (nixpkgs-lib) lib; }; + flakeModules.flakeModules = ./modules/flakeModules.nix; templates = { default = { path = ./template/default; diff --git a/lib.nix b/lib.nix index 4a5bf63..a0ac17a 100644 --- a/lib.nix +++ b/lib.nix @@ -10,7 +10,13 @@ let throwIf types warnIf + getAttrFromPath + setAttrByPath + attrByPath + optionalAttrs ; + inherit (lib.modules) + mkAliasAndWrapDefsWithPriority; inherit (lib.types) path submoduleWith @@ -165,6 +171,26 @@ let transposition.${name} = { }; }; }; + + # Needed pending https://github.com/NixOS/nixpkgs/pull/198450 + mkAliasOptionModule = from: to: { config, options, ... }: + let + fromOpt = getAttrFromPath from options; + toOf = attrByPath to + (abort "Renaming error: option `${showOption to}' does not exist."); + toType = let opt = attrByPath to { } options; in opt.type or (types.submodule { }); + in + { + options = setAttrByPath from (mkOption + { + visible = true; + description = lib.mdDoc "Alias of {option}`${showOption to}`."; + apply = x: (toOf config); + } // optionalAttrs (toType != null) { + type = toType; + }); + config = (mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt); + }; }; in diff --git a/modules/flakeModules.nix b/modules/flakeModules.nix new file mode 100644 index 0000000..b1d3aff --- /dev/null +++ b/modules/flakeModules.nix @@ -0,0 +1,45 @@ +{ config, self, lib, flake-parts-lib, ... }: +let + inherit (lib) + filterAttrs + mapAttrs + mkOption + optionalAttrs + types + ; + inherit (flake-parts-lib) + mkAliasOptionModule + ; + + flakeModulesOption = mkOption { + type = types.lazyAttrsOf types.deferredModule; + default = { }; + apply = mapAttrs (k: v: { + _file = "${toString self.outPath}/flake.nix#flakeModules.${k}"; + imports = [ v ]; + }); + description = '' + flake-parts modules for use by other flakes. + + If the flake defines only one module, it should be flakeModules.default. + + You can not use this option in defining the flake's own `imports`. Instead, you can + put the module in question into its own file and reference it both in `imports` and + export it with this option. + ''; + }; +in +{ + options = { + flake = mkOption { + type = types.submoduleWith { + modules = [ + (mkAliasOptionModule [ "flakeModule" ] [ "flakeModules" "default" ]) + { + options.flakeModules = flakeModulesOption; + } + ]; + }; + }; + }; +}