Skip to content

Commit

Permalink
modules/nixpkgs: Make customizable & support multiple evaluations
Browse files Browse the repository at this point in the history
  • Loading branch information
bb010g committed Aug 18, 2023
1 parent 498aa1f commit eb686c9
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 15 deletions.
208 changes: 200 additions & 8 deletions modules/nixpkgs.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
# Nixpkgs module. The only exception to the rule.
#
# Provides a `pkgs` argument in `perSystem`.
# Provides customizable `nixpkgs` and `pkgs` arguments in `perSystem`.
#
# Arguably, this shouldn't be in flake-parts, but in nixpkgs.
# Nixpkgs could define its own module that does this, which would be
Expand All @@ -11,16 +11,208 @@
# will be accepted into flake-parts, because it's against the
# spirit of Flakes.
#
{ config, flake-parts-lib, inputs, lib, options, ... }:
let
inherit (lib)
last
literalExpression
mapAttrs
mdDoc
mkDefault
mkOption
mkOptionDefault
mkOverride
toList
types
;
inherit (flake-parts-lib)
mkPerSystemOption
mkSubmoduleOptions
;
extendSubModules = type: modules:
type.substSubModules (type.getSubModules ++ modules);
getOptionSubOptions = locSuffix: opt:
let
loc = opt.loc ++ locSuffix;
type = extendSubModules opt.type [{ _module.args.name = last loc; }];
in
type.getSubOptions loc;
mkSubmoduleOptionsWithShorthand =
options: mkOption {
type = types.submoduleWith {
modules = [{ inherit options; }];
shorthandOnlyDefinesConfig = true;
};
};
# Shorthand for `types.submoduleWith`.
submoduleWithModules =
{ ... }@attrs:
modules:
types.submoduleWith (attrs // { modules = toList modules; });
rootConfig = config;
rootOptions = options;
in
{
options = {
nixpkgs = {
evals = mkOption {
default = { default = { }; };
description = ''
Configuration for Nixpkgs evaluations of {option}`perSystem.nixpkgs.evals`.
'';
type = types.lazyAttrsOf (submoduleWithModules { } ({ config, name, options, ... }: {
_file = ./nixpkgs.nix;
options = {
input = mkOption {
description = mdDoc ''
Nixpkgs function for evaluation.
'';
default = inputs.nixpkgs or (throw
"flake-parts: The flake does not have a `nixpkgs` input. Please add it, or set `${options.input}` yourself."
);
defaultText = literalExpression ''inputs.nixpkgs'';
type = types.coercedTo types.path import (types.functionTo types.unspecified);
};
settings = mkOption {
default = { };
description = mdDoc ''
Settings argument for the Nixpkgs evaluations of {option}`perSystem.nixpkgs.evals.<name>`.
'';
type = rootOptions.nixpkgs.settings.type;
};
};
config = {
settings = mkDefault rootConfig.nixpkgs.settings;
};
}));
};
settings = mkOption {
default = { };
description = mdDoc ''
Default settings argument for each Nixpkgs evaluations of {option}`nixpkgs.evals`.
'';
# This submodule uses `shorthandOnlyDefinesConfig` because of the top-level `config`
# attribute and to make future upstreaming of this module to Nixpkgs easier.
type = submoduleWithModules { shorthandOnlyDefinesConfig = true; } ({ config, name, options, ... }: {
_file = ./nixpkgs.nix;
freeformType = types.lazyAttrsOf types.raw;
options = {
config = mkOption {
default = { };
description = mdDoc ''
Config for this Nixpkgs evaluation.
'';
type = submoduleWithModules { } {
_file = ./nixpkgs.nix;
freeformType = types.lazyAttrsOf types.raw;
};
};
crossOverlays = mkOption {
default = [ ];
description = mdDoc ''
List of Nixpkgs overlays to apply to target packages only for this Nixpkgs evaluation.
'';
type = types.listOf (types.uniq (types.functionTo (types.functionTo (types.lazyAttrsOf types.unspecified))));
};
overlays = mkOption {
default = [ ];
description = mdDoc ''
List of Nixpkgs overlays for this Nixpkgs evaluation.
'';
type = types.listOf (types.uniq (types.functionTo (types.functionTo (types.lazyAttrsOf types.unspecified))));
};
};
});
};
};
perSystem = mkPerSystemOption ({ config, system, ... }: {
_file = ./nixpkgs.nix;
options = {
nixpkgs = {
evals = mkOption {
default = { };
description = ''
Configuration for Nixpkgs evaluations.
'';
type = types.lazyAttrsOf (submoduleWithModules { } [
({ config, name, options, ... }: {
_file = ./nixpkgs.nix;
options = {
output = mkOption {
default = rootConfig.nixpkgs.evals.${name}.input config.settings;
defaultText = literalExpression
''config.nixpkgs.evals.''${name}.input config.perSystem.nixpkgs.''${name}.settings'';
description = mdDoc ''
Evaluated Nixpkgs.
'';
type = types.raw;
};
settings = mkOption {
default = { };
description = mdDoc ''
Settings argument for the Nixpkgs evaluations of {option}`perSystem.nixpkgs.evals.<name>`.
'';
type = (getOptionSubOptions [ name ] rootOptions.nixpkgs.evals).settings.type;
};
};
config = {
settings = mkDefault rootConfig.nixpkgs.evals.${name}.settings;
};
})
# Separate module, for type merging
({ config, name, options, ... }: {
_file = ./nixpkgs.nix;
options = {
# `mkSubmoduleOptions` can't be used here due to `shorthandOnlyDefinesConfig`.
settings = mkSubmoduleOptionsWithShorthand {
buildPlatform = mkOption {
apply = lib.systems.elaborate;
default = config.settings.hostPlatform;
defaultText = literalExpression ''config.perSystem.nixpkgs.evals.''${name}.hostPlatform'';
description = mdDoc ''
Specifies the platform on which Nixpkgs packages should be built.
By default, Nixpkgs packages are built on the system where they run, but
you can change where it's built. Setting this option will cause NixOS to
be cross-compiled.
For instance, if you're doing distributed multi-platform deployment,
or if you're building for machines, you can set this to match your
development system and/or build farm.
'';
type = types.either types.str types.attrs;
};
hostPlatform = mkOption {
apply = lib.systems.elaborate;
default = system;
defaultText = literalExpression ''system'';
description = mdDoc ''
Specifies the system where packages from this Nixpkgs evaluation will run.
To cross-compile, see also {option}`config.perSystem.nixpkgs.evals.<name>.hostPlatform`.
'';
type = types.either types.str types.attrs;
};
};
};
})
]);
};
};
};
config = {
nixpkgs = {
evals = mapAttrs (name: genericConfig: { }) rootConfig.nixpkgs.evals;
};
};
});
};
config = {
perSystem = { inputs', lib, options, ... }: {
perSystem = { config, nixpkgs, options, ... }: {
_file = ./nixpkgs.nix;
config = {
_module.args.pkgs = lib.mkOptionDefault (
builtins.seq
inputs'.nixpkgs or (throw
"flake-parts: The flake does not have a `nixpkgs` input. Please add it, or set `${options._module.args}.pkgs` yourself."
)
inputs'.nixpkgs.legacyPackages
_module.args.nixpkgs = mkOptionDefault (mapAttrs (name: nixpkgs: nixpkgs.output) config.nixpkgs.evals);
_module.args.pkgs = mkOptionDefault (
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.")
);
};
};
Expand Down
10 changes: 3 additions & 7 deletions template/unfree/flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@

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

outputs = inputs@{ flake-parts, nixpkgs, ... }:
outputs = inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [ "x86_64-linux" "aarch64-darwin" ];
# This sets `pkgs` to a Nixpkgs with the `allowUnfree` option set.
nixpkgs.settings.config.allowUnfree = true;
perSystem = { pkgs, system, ... }: {
# This sets `pkgs` to a nixpkgs with allowUnfree option set.
_module.args.pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
};

packages.default = pkgs.hello-unfree;
};
};
Expand Down

0 comments on commit eb686c9

Please sign in to comment.