Merge pull request #156503 from hercules-ci/nixos-add-system.build-options

nixos: Add `system.build.`{`toplevel`,`installBootLoader`}, improve error message
This commit is contained in:
Robert Hensing 2022-01-25 14:13:24 +01:00 committed by GitHub
commit 8919495cac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 112 additions and 20 deletions

View File

@ -122,8 +122,9 @@ let
mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule
mkAliasOptionModule mkDerivedConfig doRename; mkAliasOptionModule mkDerivedConfig doRename;
inherit (self.options) isOption mkEnableOption mkSinkUndeclaredOptions inherit (self.options) isOption mkEnableOption mkSinkUndeclaredOptions
mergeDefaultOption mergeOneOption mergeEqualOption getValues mergeDefaultOption mergeOneOption mergeEqualOption mergeUniqueOption
getFiles optionAttrSetToDocList optionAttrSetToDocList' getValues getFiles
optionAttrSetToDocList optionAttrSetToDocList'
scrubOptionValue literalExpression literalExample literalDocBook scrubOptionValue literalExpression literalExample literalDocBook
showOption showFiles unknownModule mkOption; showOption showFiles unknownModule mkOption;
inherit (self.types) isType setType defaultTypeMerge defaultFunctor inherit (self.types) isType setType defaultTypeMerge defaultFunctor

View File

@ -172,11 +172,13 @@ rec {
else if all isInt list && all (x: x == head list) list then head list else if all isInt list && all (x: x == head list) list then head list
else throw "Cannot merge definitions of `${showOption loc}'. Definition values:${showDefs defs}"; else throw "Cannot merge definitions of `${showOption loc}'. Definition values:${showDefs defs}";
mergeOneOption = loc: defs: mergeOneOption = mergeUniqueOption { message = ""; };
if defs == [] then abort "This case should never happen."
else if length defs != 1 then mergeUniqueOption = { message }: loc: defs:
throw "The unique option `${showOption loc}' is defined multiple times. Definition values:${showDefs defs}" if length defs == 1
else (head defs).value; then (head defs).value
else assert length defs > 1;
throw "The option `${showOption loc}' is defined multiple times.\n${message}\nDefinition values:${showDefs defs}";
/* "Merge" option definitions by checking that they all have the same value. */ /* "Merge" option definitions by checking that they all have the same value. */
mergeEqualOption = loc: defs: mergeEqualOption = loc: defs:

View File

@ -32,7 +32,6 @@ let
last last
length length
tail tail
unique
; ;
inherit (lib.attrsets) inherit (lib.attrsets)
attrNames attrNames
@ -48,6 +47,7 @@ let
mergeDefaultOption mergeDefaultOption
mergeEqualOption mergeEqualOption
mergeOneOption mergeOneOption
mergeUniqueOption
showFiles showFiles
showOption showOption
; ;
@ -470,6 +470,18 @@ rec {
nestedTypes.elemType = elemType; nestedTypes.elemType = elemType;
}; };
unique = { message }: type: mkOptionType rec {
name = "unique";
inherit (type) description check;
merge = mergeUniqueOption { inherit message; };
emptyValue = type.emptyValue;
getSubOptions = type.getSubOptions;
getSubModules = type.getSubModules;
substSubModules = m: uniq (type.substSubModules m);
functor = (defaultFunctor name) // { wrapped = type; };
nestedTypes.elemType = type;
};
# Null or value of ... # Null or value of ...
nullOr = elemType: mkOptionType rec { nullOr = elemType: mkOptionType rec {
name = "nullOr"; name = "nullOr";
@ -599,6 +611,7 @@ rec {
# A value from a set of allowed ones. # A value from a set of allowed ones.
enum = values: enum = values:
let let
inherit (lib.lists) unique;
show = v: show = v:
if builtins.isString v then ''"${v}"'' if builtins.isString v then ''"${v}"''
else if builtins.isInt v then builtins.toString v else if builtins.isInt v then builtins.toString v

View File

@ -250,6 +250,12 @@ Composed types are types that take a type as parameter. `listOf
: Ensures that type *`t`* cannot be merged. It is used to ensure option : Ensures that type *`t`* cannot be merged. It is used to ensure option
definitions are declared only once. definitions are declared only once.
`types.unique` `{ message = m }` *`t`*
: Ensures that type *`t`* cannot be merged. Prints the message *`m`*, after
the line `The option <option path> is defined multiple times.` and before
a list of definition locations.
`types.either` *`t1 t2`* `types.either` *`t1 t2`*
: Type *`t1`* or type *`t2`*, e.g. `with types; either int str`. : Type *`t1`* or type *`t2`*, e.g. `with types; either int str`.

View File

@ -496,6 +496,22 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<literal>types.unique</literal>
<literal>{ message = m }</literal>
<emphasis><literal>t</literal></emphasis>
</term>
<listitem>
<para>
Ensures that type <emphasis><literal>t</literal></emphasis>
cannot be merged. Prints the message
<emphasis><literal>m</literal></emphasis>, after the line
<literal>The option &lt;option path&gt; is defined multiple times.</literal>
and before a list of definition locations.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<literal>types.either</literal> <literal>types.either</literal>

View File

@ -109,9 +109,7 @@ let
utillinux = pkgs.util-linux; utillinux = pkgs.util-linux;
kernelParams = config.boot.kernelParams; kernelParams = config.boot.kernelParams;
installBootLoader = installBootLoader = config.system.build.installBootLoader;
config.system.build.installBootLoader
or "echo 'Warning: do not know how to make this configuration bootable; please enable a boot loader.' 1>&2; true";
activationScript = config.system.activationScripts.script; activationScript = config.system.activationScripts.script;
dryActivationScript = config.system.dryActivationScript; dryActivationScript = config.system.dryActivationScript;
nixosLabel = config.system.nixos.label; nixosLabel = config.system.nixos.label;
@ -135,25 +133,27 @@ let
pkgs.replaceDependency { inherit oldDependency newDependency drv; } pkgs.replaceDependency { inherit oldDependency newDependency drv; }
) baseSystemAssertWarn config.system.replaceRuntimeDependencies; ) baseSystemAssertWarn config.system.replaceRuntimeDependencies;
/* Workaround until https://github.com/NixOS/nixpkgs/pull/156533
Call can be replaced by argument when that's merged.
*/
tmpFixupSubmoduleBoundary = subopts:
lib.mkOption {
type = lib.types.submoduleWith {
modules = [ { options = subopts; } ];
};
};
in in
{ {
imports = [ imports = [
../build.nix
(mkRemovedOptionModule [ "nesting" "clone" ] "Use `specialisation.«name» = { inheritParentConfig = true; configuration = { ... }; }` instead.") (mkRemovedOptionModule [ "nesting" "clone" ] "Use `specialisation.«name» = { inheritParentConfig = true; configuration = { ... }; }` instead.")
(mkRemovedOptionModule [ "nesting" "children" ] "Use `specialisation.«name».configuration = { ... }` instead.") (mkRemovedOptionModule [ "nesting" "children" ] "Use `specialisation.«name».configuration = { ... }` instead.")
]; ];
options = { options = {
system.build = mkOption {
internal = true;
default = {};
type = with types; lazyAttrsOf (uniq unspecified);
description = ''
Attribute set of derivations used to setup the system.
'';
};
specialisation = mkOption { specialisation = mkOption {
default = {}; default = {};
example = lib.literalExpression "{ fewJobsManyCores.configuration = { nix.buildCores = 0; nix.maxJobs = 1; }; }"; example = lib.literalExpression "{ fewJobsManyCores.configuration = { nix.buildCores = 0; nix.maxJobs = 1; }; }";
@ -224,6 +224,39 @@ in
''; '';
}; };
system.build = tmpFixupSubmoduleBoundary {
installBootLoader = mkOption {
internal = true;
# "; true" => make the `$out` argument from switch-to-configuration.pl
# go to `true` instead of `echo`, hiding the useless path
# from the log.
default = "echo 'Warning: do not know how to make this configuration bootable; please enable a boot loader.' 1>&2; true";
description = ''
A program that writes a bootloader installation script to the path passed in the first command line argument.
See <literal>nixos/modules/system/activation/switch-to-configuration.pl</literal>.
'';
type = types.unique {
message = ''
Only one bootloader can be enabled at a time. This requirement has not
been checked until NixOS 22.05. Earlier versions defaulted to the last
definition. Change your configuration to enable only one bootloader.
'';
} (types.either types.str types.package);
};
toplevel = mkOption {
type = types.package;
readOnly = true;
description = ''
This option contains the store path that typically represents a NixOS system.
You can read this path in a custom deployment tool for example.
'';
};
};
system.copySystemConfiguration = mkOption { system.copySystemConfiguration = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;

View File

@ -0,0 +1,21 @@
{ lib, ... }:
let
inherit (lib) mkOption types;
in
{
options = {
system.build = mkOption {
default = {};
description = ''
Attribute set of derivations used to set up the system.
'';
type = types.submoduleWith {
modules = [{
freeformType = with types; lazyAttrsOf (uniq unspecified);
}];
};
};
};
}