about summary refs log tree commit diff
path: root/nixos/doc/manual/from_md/development/option-def.section.xml
blob: 3c1a979e70f33c2392f7487a47503051fee7c74a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-option-definitions">
  <title>Option Definitions</title>
  <para>
    Option definitions are generally straight-forward bindings of values
    to option names, like
  </para>
  <programlisting language="bash">
config = {
  services.httpd.enable = true;
};
</programlisting>
  <para>
    However, sometimes you need to wrap an option definition or set of
    option definitions in a <emphasis>property</emphasis> to achieve
    certain effects:
  </para>
  <section xml:id="sec-option-definitions-delaying-conditionals">
    <title>Delaying Conditionals</title>
    <para>
      If a set of option definitions is conditional on the value of
      another option, you may need to use <literal>mkIf</literal>.
      Consider, for instance:
    </para>
    <programlisting language="bash">
config = if config.services.httpd.enable then {
  environment.systemPackages = [ ... ];
  ...
} else {};
</programlisting>
    <para>
      This definition will cause Nix to fail with an <quote>infinite
      recursion</quote> error. Why? Because the value of
      <literal>config.services.httpd.enable</literal> depends on the
      value being constructed here. After all, you could also write the
      clearly circular and contradictory:
    </para>
    <programlisting language="bash">
config = if config.services.httpd.enable then {
  services.httpd.enable = false;
} else {
  services.httpd.enable = true;
};
</programlisting>
    <para>
      The solution is to write:
    </para>
    <programlisting language="bash">
config = mkIf config.services.httpd.enable {
  environment.systemPackages = [ ... ];
  ...
};
</programlisting>
    <para>
      The special function <literal>mkIf</literal> causes the evaluation
      of the conditional to be <quote>pushed down</quote> into the
      individual definitions, as if you had written:
    </para>
    <programlisting language="bash">
config = {
  environment.systemPackages = if config.services.httpd.enable then [ ... ] else [];
  ...
};
</programlisting>
  </section>
  <section xml:id="sec-option-definitions-setting-priorities">
    <title>Setting Priorities</title>
    <para>
      A module can override the definitions of an option in other
      modules by setting an <emphasis>override priority</emphasis>. All
      option definitions that do not have the lowest priority value are
      discarded. By default, option definitions have priority 100 and
      option defaults have priority 1500. You can specify an explicit
      priority by using <literal>mkOverride</literal>, e.g.
    </para>
    <programlisting language="bash">
services.openssh.enable = mkOverride 10 false;
</programlisting>
    <para>
      This definition causes all other definitions with priorities above
      10 to be discarded. The function <literal>mkForce</literal> is
      equal to <literal>mkOverride 50</literal>, and
      <literal>mkDefault</literal> is equal to
      <literal>mkOverride 1000</literal>.
    </para>
  </section>
  <section xml:id="sec-option-definitions-ordering">
    <title>Ordering Definitions</title>
    <para>
      It is also possible to influence the order in which the
      definitions for an option are merged by setting an <emphasis>order
      priority</emphasis> with <literal>mkOrder</literal>. The default
      order priority is 1000. The functions <literal>mkBefore</literal>
      and <literal>mkAfter</literal> are equal to
      <literal>mkOrder 500</literal> and
      <literal>mkOrder 1500</literal>, respectively. As an example,
    </para>
    <programlisting language="bash">
hardware.firmware = mkBefore [ myFirmware ];
</programlisting>
    <para>
      This definition ensures that <literal>myFirmware</literal> comes
      before other unordered definitions in the final list value of
      <literal>hardware.firmware</literal>.
    </para>
    <para>
      Note that this is different from
      <link linkend="sec-option-definitions-setting-priorities">override
      priorities</link>: setting an order does not affect whether the
      definition is included or not.
    </para>
  </section>
  <section xml:id="sec-option-definitions-merging">
    <title>Merging Configurations</title>
    <para>
      In conjunction with <literal>mkIf</literal>, it is sometimes
      useful for a module to return multiple sets of option definitions,
      to be merged together as if they were declared in separate
      modules. This can be done using <literal>mkMerge</literal>:
    </para>
    <programlisting language="bash">
config = mkMerge
  [ # Unconditional stuff.
    { environment.systemPackages = [ ... ];
    }
    # Conditional stuff.
    (mkIf config.services.bla.enable {
      environment.systemPackages = [ ... ];
    })
  ];
</programlisting>
  </section>
</section>