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
mkAliasOptionModule mkDerivedConfig doRename;
inherit (self.options) isOption mkEnableOption mkSinkUndeclaredOptions
mergeDefaultOption mergeOneOption mergeEqualOption getValues
getFiles optionAttrSetToDocList optionAttrSetToDocList'
mergeDefaultOption mergeOneOption mergeEqualOption mergeUniqueOption
getValues getFiles
optionAttrSetToDocList optionAttrSetToDocList'
scrubOptionValue literalExpression literalExample literalDocBook
showOption showFiles unknownModule mkOption;
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 throw "Cannot merge definitions of `${showOption loc}'. Definition values:${showDefs defs}";
mergeOneOption = loc: defs:
if defs == [] then abort "This case should never happen."
else if length defs != 1 then
throw "The unique option `${showOption loc}' is defined multiple times. Definition values:${showDefs defs}"
else (head defs).value;
mergeOneOption = mergeUniqueOption { message = ""; };
mergeUniqueOption = { message }: loc: defs:
if length defs == 1
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. */
mergeEqualOption = loc: defs:

View file

@ -32,7 +32,6 @@ let
last
length
tail
unique
;
inherit (lib.attrsets)
attrNames
@ -48,6 +47,7 @@ let
mergeDefaultOption
mergeEqualOption
mergeOneOption
mergeUniqueOption
showFiles
showOption
;
@ -470,6 +470,18 @@ rec {
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 ...
nullOr = elemType: mkOptionType rec {
name = "nullOr";
@ -599,6 +611,7 @@ rec {
# A value from a set of allowed ones.
enum = values:
let
inherit (lib.lists) unique;
show = v:
if builtins.isString v then ''"${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
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`*
: Type *`t1`* or type *`t2`*, e.g. `with types; either int str`.

View file

@ -496,6 +496,22 @@
</para>
</listitem>
</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>
<term>
<literal>types.either</literal>

View file

@ -109,9 +109,7 @@ let
utillinux = pkgs.util-linux;
kernelParams = config.boot.kernelParams;
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";
installBootLoader = config.system.build.installBootLoader;
activationScript = config.system.activationScripts.script;
dryActivationScript = config.system.dryActivationScript;
nixosLabel = config.system.nixos.label;
@ -135,25 +133,27 @@ let
pkgs.replaceDependency { inherit oldDependency newDependency drv; }
) 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
{
imports = [
../build.nix
(mkRemovedOptionModule [ "nesting" "clone" ] "Use `specialisation.«name» = { inheritParentConfig = true; configuration = { ... }; }` instead.")
(mkRemovedOptionModule [ "nesting" "children" ] "Use `specialisation.«name».configuration = { ... }` instead.")
];
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 {
default = {};
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 {
type = types.bool;
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);
}];
};
};
};
}