1{
2 config,
3 lib,
4 pkgs,
5 extendModules,
6 noUserModules,
7 ...
8}:
9
10let
11 inherit (lib)
12 concatStringsSep
13 escapeShellArg
14 hasInfix
15 mapAttrs
16 mapAttrsToList
17 mkOption
18 types
19 ;
20
21 # This attribute is responsible for creating boot entries for
22 # child configuration. They are only (directly) accessible
23 # when the parent configuration is boot default. For example,
24 # you can provide an easy way to boot the same configuration
25 # as you use, but with another kernel
26 # !!! fix this
27 children = mapAttrs (
28 childName: childConfig: childConfig.configuration.system.build.toplevel
29 ) config.specialisation;
30
31in
32{
33 options = {
34 isSpecialisation = mkOption {
35 type = lib.types.bool;
36 internal = true;
37 default = false;
38 description = "Whether this system is a specialisation of another.";
39 };
40
41 specialisation = mkOption {
42 default = { };
43 example = lib.literalExpression "{ fewJobsManyCores.configuration = { nix.settings = { core = 0; max-jobs = 1; }; }; }";
44 description = ''
45 Additional configurations to build. If
46 `inheritParentConfig` is true, the system
47 will be based on the overall system configuration.
48
49 To switch to a specialised configuration
50 (e.g. `fewJobsManyCores`) at runtime, run:
51
52 ```
53 sudo /run/current-system/specialisation/fewJobsManyCores/bin/switch-to-configuration test
54 ```
55 '';
56 type = types.attrsOf (
57 types.submodule (
58 local@{ ... }:
59 let
60 extend = if local.config.inheritParentConfig then extendModules else noUserModules.extendModules;
61 in
62 {
63 options.inheritParentConfig = mkOption {
64 type = types.bool;
65 default = true;
66 description = "Include the entire system's configuration. Set to false to make a completely differently configured system.";
67 };
68
69 options.configuration = mkOption {
70 default = { };
71 description = ''
72 Arbitrary NixOS configuration.
73
74 Anything you can add to a normal NixOS configuration, you can add
75 here, including imports and config values, although nested
76 specialisations will be ignored.
77 '';
78 visible = "shallow";
79 inherit (extend { modules = [ ./no-clone.nix ]; }) type;
80 };
81 }
82 )
83 );
84 };
85
86 };
87
88 config = {
89 assertions = mapAttrsToList (name: _: {
90 assertion = !hasInfix "/" name;
91 message = ''
92 Specialisation names must not contain forward slashes.
93 Invalid specialisation name: ${name}
94 '';
95 }) config.specialisation;
96
97 system.systemBuilderCommands = ''
98 mkdir $out/specialisation
99 ${concatStringsSep "\n" (
100 mapAttrsToList (name: path: "ln -s ${path} $out/specialisation/${escapeShellArg name}") children
101 )}
102 '';
103 };
104
105 # uses extendModules to generate a type
106 meta.buildDocsInSandbox = false;
107}