From f3c79bef3bc3f70318740be30653cc65ff25a1c4 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Sun, 16 Oct 2022 16:07:14 -0400 Subject: [PATCH 1/2] Add option for defining flake-parts modules for downstream flakes. --- ChangeLog.md | 9 +++++++- flake.nix | 1 + lib.nix | 26 +++++++++++++++++++++++ modules/flakeModules.nix | 45 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 modules/flakeModules.nix diff --git a/ChangeLog.md b/ChangeLog.md index 79f5b959..02182ef4 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 dd038a82..3a3949e8 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 4a5bf63c..a0ac17ae 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 00000000..b1d3aff2 --- /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; + } + ]; + }; + }; + }; +} From 3c60ce7d7e89eead49c5892ce6d51fe9ddb6435a Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Tue, 18 Oct 2022 11:52:13 -0400 Subject: [PATCH 2/2] Add lib.defaultModule for extracting the default flakeModule --- lib.nix | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib.nix b/lib.nix index a0ac17ae..085454c3 100644 --- a/lib.nix +++ b/lib.nix @@ -22,6 +22,12 @@ let submoduleWith ; + # Polyfill isFlake until Nix with https://github.com/NixOS/nix/pull/7207 is common + isFlake = maybeFlake: + if maybeFlake ? _type + then maybeFlake._type == "flake" + else maybeFlake ? inputs && maybeFlake ? outputs && maybeFlake ? sourceInfo; + # Polyfill functionTo to make sure it has type merging. # Remove 2022-12 functionTo = @@ -118,6 +124,17 @@ let } ); + # Function to extract the default flakeModule from + # what may be a flake, returning the argument unmodified + # if it's not a flake. + # + # Useful to map over an 'imports' list to make it less + # verbose in the common case. + defaultModule = maybeFlake: + if isFlake maybeFlake + then maybeFlake.flakeModules.default or maybeFlake + else maybeFlake; + mkFlake = args: module: (flake-parts-lib.evalFlakeModule args module).config.flake;