Skip to content

Commit d695f1a

Browse files
committed
modules/nixpkgs: Make customizable & support multiple evaluations
1 parent 498aa1f commit d695f1a

File tree

2 files changed

+205
-15
lines changed

2 files changed

+205
-15
lines changed

modules/nixpkgs.nix

+202-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# Nixpkgs module. The only exception to the rule.
33
#
4-
# Provides a `pkgs` argument in `perSystem`.
4+
# Provides customizable `nixpkgs` and `pkgs` arguments in `perSystem`.
55
#
66
# Arguably, this shouldn't be in flake-parts, but in nixpkgs.
77
# Nixpkgs could define its own module that does this, which would be
@@ -11,16 +11,210 @@
1111
# will be accepted into flake-parts, because it's against the
1212
# spirit of Flakes.
1313
#
14+
{ config, flake-parts-lib, inputs, lib, options, ... }:
15+
let
16+
inherit (lib)
17+
last
18+
literalExpression
19+
mapAttrs
20+
mdDoc
21+
mkDefault
22+
mkOption
23+
mkOptionDefault
24+
mkOverride
25+
toList
26+
types
27+
;
28+
inherit (flake-parts-lib)
29+
mkPerSystemOption
30+
mkSubmoduleOptions
31+
;
32+
extendSubModules = type: modules:
33+
type.substSubModules (type.getSubModules ++ modules);
34+
getOptionSubOptions = locSuffix: opt:
35+
let
36+
loc = opt.loc ++ locSuffix;
37+
type = extendSubModules opt.type [{ _module.args.name = last loc; }];
38+
in
39+
type.getSubOptions loc;
40+
mkSubmoduleOptionsWithShorthand =
41+
options: mkOption {
42+
type = types.submoduleWith {
43+
modules = [{ inherit options; }];
44+
shorthandOnlyDefinesConfig = true;
45+
};
46+
};
47+
# Shorthand for `types.submoduleWith`.
48+
submoduleWithModules =
49+
{ ... }@attrs:
50+
modules:
51+
types.submoduleWith (attrs // { modules = toList modules; });
52+
rootConfig = config;
53+
rootOptions = options;
54+
in
1455
{
56+
options = {
57+
nixpkgs = {
58+
evals = mkOption {
59+
default = { default = { }; };
60+
description = ''
61+
Configuration for Nixpkgs evaluations of {option}`perSystem.nixpkgs.evals`.
62+
'';
63+
type = types.lazyAttrsOf (submoduleWithModules { } ({ config, name, options, ... }: {
64+
_file = ./nixpkgs.nix;
65+
options = {
66+
input = mkOption {
67+
description = mdDoc ''
68+
Nixpkgs function for evaluation.
69+
'';
70+
default = inputs.nixpkgs or (throw
71+
"flake-parts: The flake does not have a `nixpkgs` input. Please add it, or set `${options.input}` yourself."
72+
);
73+
defaultText = literalExpression ''inputs.nixpkgs'';
74+
type = types.coercedTo types.path import (types.functionTo types.unspecified);
75+
};
76+
settings = mkOption {
77+
default = { };
78+
description = mdDoc ''
79+
Settings argument for the Nixpkgs evaluations of {option}`perSystem.nixpkgs.evals.<name>`.
80+
'';
81+
type = rootOptions.nixpkgs.settings.type;
82+
};
83+
};
84+
config = {
85+
settings = mkDefault rootConfig.nixpkgs.settings;
86+
};
87+
}));
88+
};
89+
settings = mkOption {
90+
default = { };
91+
description = mdDoc ''
92+
Default settings argument for each Nixpkgs evaluations of {option}`nixpkgs.evals`.
93+
'';
94+
# This submodule uses `shorthandOnlyDefinesConfig` because of the top-level `config`
95+
# attribute and to make future upstreaming of this module to Nixpkgs easier.
96+
type = submoduleWithModules { shorthandOnlyDefinesConfig = true; } ({ config, name, options, ... }: {
97+
_file = ./nixpkgs.nix;
98+
freeformType = types.lazyAttrsOf types.raw;
99+
options = {
100+
config = mkOption {
101+
default = { };
102+
description = mdDoc ''
103+
Config for this Nixpkgs evaluation.
104+
'';
105+
type = submoduleWithModules { } {
106+
_file = ./nixpkgs.nix;
107+
freeformType = types.lazyAttrsOf types.raw;
108+
};
109+
};
110+
crossOverlays = mkOption {
111+
default = [ ];
112+
description = mdDoc ''
113+
List of Nixpkgs overlays to apply to target packages only for this Nixpkgs evaluation.
114+
'';
115+
type = types.listOf (types.uniq (types.functionTo (types.functionTo (types.lazyAttrsOf types.unspecified))));
116+
};
117+
overlays = mkOption {
118+
default = [ ];
119+
description = mdDoc ''
120+
List of Nixpkgs overlays for this Nixpkgs evaluation.
121+
'';
122+
type = types.listOf (types.uniq (types.functionTo (types.functionTo (types.lazyAttrsOf types.unspecified))));
123+
};
124+
};
125+
});
126+
};
127+
};
128+
perSystem = mkPerSystemOption ({ config, system, ... }: {
129+
_file = ./nixpkgs.nix;
130+
options = {
131+
nixpkgs = {
132+
evals = mkOption {
133+
default = { };
134+
description = ''
135+
Configuration for Nixpkgs evaluations.
136+
'';
137+
type = types.lazyAttrsOf (submoduleWithModules { } [
138+
({ config, name, options, ... }: {
139+
_file = ./nixpkgs.nix;
140+
options = {
141+
output = mkOption {
142+
default = rootConfig.nixpkgs.evals.${name}.input config.settings;
143+
defaultText = literalExpression
144+
''config.nixpkgs.evals.''${name}.input config.perSystem.nixpkgs.''${name}.settings'';
145+
description = mdDoc ''
146+
Evaluated Nixpkgs.
147+
'';
148+
type = types.raw;
149+
};
150+
settings = mkOption {
151+
default = { };
152+
description = mdDoc ''
153+
Settings argument for the Nixpkgs evaluations of {option}`perSystem.nixpkgs.evals.<name>`.
154+
'';
155+
type = (getOptionSubOptions [ name ] rootOptions.nixpkgs.evals).settings.type;
156+
};
157+
};
158+
config = {
159+
settings = mkDefault rootConfig.nixpkgs.evals.${name}.settings;
160+
};
161+
})
162+
# Separate module, for type merging
163+
({ config, name, options, ... }: {
164+
_file = ./nixpkgs.nix;
165+
options = {
166+
# `mkSubmoduleOptions` can't be used here due to `shorthandOnlyDefinesConfig`.
167+
settings = mkSubmoduleOptionsWithShorthand {
168+
localSystem = mkOption {
169+
apply = lib.systems.elaborate;
170+
default = config.settings.crossSystem;
171+
defaultText = literalExpression ''config.perSystem.nixpkgs.evals.''${name}.crossSystem'';
172+
description = mdDoc ''
173+
Specifies the platform on which Nixpkgs packages should be built.
174+
Also known as `buildPlatform`.
175+
By default, Nixpkgs packages are built on the system where they run, but
176+
you can change where it's built. Setting this option will cause NixOS to
177+
be cross-compiled.
178+
179+
For instance, if you're doing distributed multi-platform deployment,
180+
or if you're building for machines, you can set this to match your
181+
development system and/or build farm.
182+
'';
183+
type = types.either types.str types.attrs;
184+
};
185+
crossSystem = mkOption {
186+
apply = lib.systems.elaborate;
187+
default = system;
188+
defaultText = literalExpression ''system'';
189+
description = mdDoc ''
190+
Specifies the system where packages from this Nixpkgs evaluation will run.
191+
Also known as `hostPlatform`.
192+
193+
To cross-compile, see also {option}`config.perSystem.nixpkgs.evals.<name>.localSystem`.
194+
'';
195+
type = types.either types.str types.attrs;
196+
};
197+
};
198+
};
199+
})
200+
]);
201+
};
202+
};
203+
};
204+
config = {
205+
nixpkgs = {
206+
evals = mapAttrs (name: genericConfig: { }) rootConfig.nixpkgs.evals;
207+
};
208+
};
209+
});
210+
};
15211
config = {
16-
perSystem = { inputs', lib, options, ... }: {
212+
perSystem = { config, nixpkgs, options, ... }: {
213+
_file = ./nixpkgs.nix;
17214
config = {
18-
_module.args.pkgs = lib.mkOptionDefault (
19-
builtins.seq
20-
inputs'.nixpkgs or (throw
21-
"flake-parts: The flake does not have a `nixpkgs` input. Please add it, or set `${options._module.args}.pkgs` yourself."
22-
)
23-
inputs'.nixpkgs.legacyPackages
215+
_module.args.nixpkgs = mkOptionDefault (mapAttrs (name: nixpkgs: nixpkgs.output) config.nixpkgs.evals);
216+
_module.args.pkgs = mkOptionDefault (
217+
nixpkgs.default or (throw "flake-parts: The `perSystem` argument `nixpkgs` does not have a default attribute. Please configure `${options._module.args}.nixpkgs.default`, or set `${options._module.args}.nixpkgs` or `${options._module.args}.pkgs` yourself.")
24218
);
25219
};
26220
};

template/unfree/flake.nix

+3-7
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,12 @@
33

44
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
55

6-
outputs = inputs@{ flake-parts, nixpkgs, ... }:
6+
outputs = inputs@{ flake-parts, ... }:
77
flake-parts.lib.mkFlake { inherit inputs; } {
88
systems = [ "x86_64-linux" "aarch64-darwin" ];
9+
# This sets `pkgs` to a Nixpkgs with the `allowUnfree` option set.
10+
nixpkgs.settings.config.allowUnfree = true;
911
perSystem = { pkgs, system, ... }: {
10-
# This sets `pkgs` to a nixpkgs with allowUnfree option set.
11-
_module.args.pkgs = import nixpkgs {
12-
inherit system;
13-
config.allowUnfree = true;
14-
};
15-
1612
packages.default = pkgs.hello-unfree;
1713
};
1814
};

0 commit comments

Comments
 (0)