Author: NicolasPierron
Date: Sun May 1 10:24:37 2011
New Revision: 27070
URL: https://svn.nixos.org/websvn/nix/?rev=27070&sc=1
Log:
Manual: Clarify NixOS modules.
Modified:
nixos/trunk/doc/manual/development.xml
Modified: nixos/trunk/doc/manual/development.xml
==============================================================================
--- nixos/trunk/doc/manual/development.xml Sun May 1 10:24:28 2011
(r27069)
+++ nixos/trunk/doc/manual/development.xml Sun May 1 10:24:37 2011
(r27070)
@@ -7,42 +7,209 @@
NixOS.</para>
+<!--===============================================================-->
+
<section>
<title>Extending NixOS</title>
-<para>A unique syntax is used to express all system, hardware, computer and
- service configurations. This syntax helps for reading and writing new
- configuration files. It is coming with some extra strategies defined in
- NixPkgs which are used to merge and evaluate all configuration files.</para>
+<para>NixOS is based on a modular system for declarative configuration.
+ This system combines multiple <emphasis>modules</emphasis> to produce one
+ configuration. One of the module which compose your computer
+ configuration is <filename>/etc/nixos/configuration.nix</filename>. Other
+ modules are available under NixOS <filename>modules</filename>
+ directory</para>
+
+<para>A module is a file which handles one specific part of the
+ configuration. This part of the configuration could correspond to an
+ hardware, a service, network settings, or preferences. A module
+ configuration does not have to handle everything from scratch, it can base
+ its configuration on other configurations provided by other modules. Thus
+ a module can <emphasis>define</emphasis> options to setup its
+ configuration, and it can also <emphasis>declare</emphasis> options to be
+ fed by other modules.</para>
+
+<!-- module syntax -->
+
+<para xml:id="para-module-syn">A module is a file which contains a Nix
+ expression. This expression should be either an expression which gets
+ evaluated into an attribute set or a function which returns an attribute
+ set.</para>
+
+<para>When the expression is a function, it should expect only one argument
+ which is an attribute set containing an attribute
+ named <varname>config</varname> and another attribute
+ named <varname>pkgs</varname>. The <varname>config</varname> attribute
+ contains the result of the merge of all modules. This attribute is
+ evaluated lazily, such as any Nix expression. For more details on how
+ options are merged, see the details in <xref linkend="para-opt-decl"/>.
+ The <varname>pkgs</varname> attribute
+ contains <emphasis>nixpkgs</emphasis> attribute set of packages. This
+ attribute is necessary for declaring options.</para>
+
+<example xml:id='module-syntax'><title>Usual module content</title>
+<programlisting>
+{config, pkgs, ...}: <co xml:id='module-syntax-1' />
+
+{
+ imports = [
+ <co xml:id='module-syntax-2' />
+ ];
+
+ options = {
+ <co xml:id='module-syntax-3' />
+ };
+
+ config = {
+ <co xml:id='module-syntax-4' />
+ };
+}</programlisting>
+</example>
+
+<para><xref linkend='module-syntax' /> Illustrates
+ a <emphasis>module</emphasis> skeleton.
+
+<calloutlist>
+ <callout arearefs='module-syntax-1'>
+ <para>This line makes the current Nix expression a function. This
+ line can be omitted if there is no reference to <varname>pkgs</varname>
+ and <varname>config</varname> inside the module.</para>
+ </callout>
+
+ <callout arearefs='module-syntax-2'>
+ <para>This list is used to enumerate path to other modules which are
+ declaring options used by the current module. In NixOS, default modules
+ are listed in the file <filename>modules/module-list.nix</filename>.
+ The default modules don't need to be added in the import list.</para>
+ </callout>
+
+ <callout arearefs='module-syntax-3'>
+ <para>This attribute set contains an attribute set of <emphasis>option
+ declaration</emphasis>.</para>
+ </callout>
+
+ <callout arearefs='module-syntax-4'>
+ <para>This attribute set contains an attribute set of <emphasis>option
+ definitions</emphasis>. If the module does not have any imported
+ modules or any option declarations, then this attribute set can be used
+ in place of its parent attribute set. This is a common case for simple
+ modules such
+ as <filename>/etc/nixos/configuration.nix</filename>.</para>
+ </callout>
+</calloutlist>
+
+</para>
+
+<!-- option definitions -->
- <para>A configuration file is the same as your own computer
- configuration.</para>
+<para xml:id="para-opt-def">A module defines a configuration which would be
+ interpreted by other modules. To define a configuration, a module needs
+ to provide option definitions. An option definition is a simple
+ attribute assignment.</para>
+
+<para>Option definitions are made in a declarative manner. Without
+ properties, options will always be defined with the same value. To
+ introduce more flexibility in the system, option definitions are guarded
+ by <emphasis>properties</emphasis>.</para>
+
+<para>Properties are means to introduce conditional values inside option
+ definitions. This conditional values can be distinguished in two
+ categories. The condition which are local to the current configuration
+ and conditions which are dependent on others configurations. Local
+ properties are <varname>mkIf</varname>, <varname>mkAlways</varname>
+ and <varname>mkAssert</varname>. Global properties
+ are <varname>mkOverride</varname>, <varname>mkDefault</varname>
+ and <varname>mkOrder</varname>.</para>
+
+<para><varname>mkIf</varname> is used to remove the option definitions which
+ are below it if the condition is evaluated to
+ false. <varname>mkAssert</varname> expects the condition to be evaluated
+ to true otherwise it raises an error message. <varname>mkAlways</varname>
+ is used to ignore all the <varname>mkIf</varname>
+ and <varname>mkAssert</varname> which have been made
+ previously. <varname>mkAlways</varname> and <varname>mkAssert</varname>
+ are often used together to set an option value and to ensure that it has
+ not been masked by another one.</para>
+
+<para><varname>mkOverride</varname> is used to mask previous definitions if
+ the current value has a lower mask number. The mask value is 100 (default)
+ for any option definition which does not use this property.
+ Thus, <varname>mkDefault</varname> is just a short-cut with a higher mask
+ (1000) than the default mask value. This means that a module can set an
+ option definition as a preference, and still let another module defining
+ it with a different value without using any property.</para>
+
+<para><varname>mkOrder</varname> is used to sort definitions based on the
+ rank number. The rank number will sort all options definitions before
+ giving the sorted list of option definition to the merge function defined
+ in the option declaration. A lower rank will move the definition to the
+ beginning and a higher rank will move the option toward the end. The
+ default rank is 100.</para>
+
+<!-- option declarations -->
+
+<para xml:id="para-opt-decl">A module may declare options which are used by
+ other module to change the configuration provided by the current module.
+ Changes to the option definitions are made with properties which are using
+ values extracted from the result of the merge of all modules
+ (the <varname>config</varname> argument).</para>
+
+<para>The <varname>config</varname> argument reproduce the same hierarchy of
+ all options declared in all modules. For each option, the result of the
+ option is available, it is either the default value or the merge of all
+ definitions of the option.</para>
+
+<para>Options are declared with the
+ function <varname>pkgs.lib.mkOption</varname>. This function expects an
+ attribute set which at least provides a description. A default value, an
+ example, a type, a merge function and a post-process function can be
+ added.</para>
+
+<para>Types are used to provide a merge strategy for options and to ensure
+ the type of each option definitions. They are defined
+ in <varname>pkgs.lib.types</varname>.</para>
+
+<para>The merge function expects a list of option definitions and merge
+ them to obtain one result of the same type.</para>
+
+<para>The post-process function (named <varname>apply</varname>) takes the
+ result of the merge or of the default value, and produce an output which
+ could have a different type than the type expected by the option.</para>
-<example xml:id='conf-syntax'><title>Usual configuration file</title>
+<!-- end -->
+
+<example xml:id='locate-example'><title>Locate Module Example</title>
<programlisting>
-{config, modulesPath, pkgs, ...}: <co xml:id='conf-syntax-1' />
+{config, pkgs, ...}:
-let
- inherit (pkgs.lib) mkOption mkIf mkThenElse types; <co
xml:id='conf-syntax-2' />
+with pkgs.lib;
- cfg = config.services.locate; <co xml:id='conf-syntax-4' />
+let
+ cfg = config.services.locate;
locatedb = "/var/cache/locatedb";
logfile = "/var/log/updatedb";
- cmd = "root updatedb --localuser=nobody --output=${locatedb} > ${logfile}";
+ cmd =''root updatedb --localuser=nobody --output=${locatedb} > ${logfile}'';
+
+ mkCheck = x:
+ mkIf cfg.enable (
+ mkAssert config.services.cron.enable ''
+ The cron daemon is not enabled, required by services.locate.enable.
+ ''
+ x
+ )
in
{
- imports = [ <co xml:id='conf-syntax-6' />
- (modulesPath + /services/scheduling/cron.nix)
+ imports = [
+ /etc/nixos/nixos/modules/services/scheduling/cron.nix
];
- options = { <co xml:id='conf-syntax-3' />
+ options = {
services.locate = {
enable = mkOption {
default = false;
example = true;
- type = types.bool;
+ type = with types; bool;
description = ''
If enabled, NixOS will periodically update the database of
files used by the <command>locate</command> command.
@@ -51,7 +218,7 @@
period = mkOption {
default = "15 02 * * *";
- type = types.uniq type.string;
+ type = with types; uniq string;
description = ''
This option defines (in the format used by cron) when the
locate database is updated.
@@ -61,164 +228,29 @@
};
};
- config = mkIf cfg.enable { <co xml:id='conf-syntax-5' />
+ config = mkCheck {
services.cron = {
- systemCronJobs = mkThenElse { <co xml:id='conf-syntax-7' />
- thenPart = "${cfg.period} root ${cmd}";
- elsePart = "";
- };
+ enable = mkAlways cfg.enable;
+ systemCronJobs = "${cfg.period} root ${cmd}";
};
};
}</programlisting>
</example>
-<para><xref linkend='conf-syntax' /> shows the <emphasis>configuration
- file</emphasis> for the locate service which uses cron to update the
- database at some dates which can be defined by the user. This nix
- expression is coming
- from <filename>upstart-jobs/cron/locate.nix</filename>. It shows a simple
- example of a service that can be either distributed on many computer that
- are using the same configuration or to shared with the community. This
- file is divided in two with the interface and the implementation. Both
- the interface and the implementation declare a <emphasis>configuration
- set</emphasis>.
-
-<calloutlist>
-
- <callout arearefs='conf-syntax-1'>
+<para><xref linkend='locate-example' /> illustrates a module which handles
+ the regular update of the database which index all files on the file
+ system. This modules has option definitions to rely on the cron service
+ to run the command at predefined dates. In addition, this modules
+ provides option declarations to enable the indexing and to use different
+ period of time to run the indexing. Properties are used to prevent
+ ambiguous definitions of option (enable locate service and disable cron
+ services) and to ensure that no options would be defined if the locate
+ service is not enabled.</para>
- <para>This line declares the arguments of the configuration file. You
- can omit this line if there is no reference to <varname>pkgs</varname>
- and <varname>config</varname> inside the configuration file.</para>
-
- <para>The argument <varname>pkgs</varname> refers to NixPkgs and allow
- you to access all attributes contained inside it. In this
- example <varname>pkgs</varname> is used to retrieve common functions to
- ease the writing of configuration files
- like <varname>mkOption</varname>, <varname>mkIf</varname>
- and <varname>mkThenElse</varname>.</para>
-
- <para>The argument <varname>config</varname> corresponds to the whole
- NixOS configuration. This is a set which is build by merging all
- configuration files imported to set up the system. Thus all options
- declared are contained inside this variable. In this
- example <varname>config</varname> is used to retrieve the status of
- the <varname>enable</varname> flag. The important point of this
- argument is that it contains either the result of the merge of different
- settings or the default value, therefore you cannot assume
- that <option>config.services.locate.enable</option> is always false
- because it may have been defined in another configuration file.</para>
-
- </callout>
-
- <callout arearefs='conf-syntax-2'>
-
- <para>This line is used to import a functions that are useful for
- writing this configuration file.</para>
-
- </callout>
-
- <callout arearefs='conf-syntax-3'>
-
- <para>The variable <varname>options</varname> is
- a <emphasis>configuration set</emphasis> which is only used to declare
- options with the function <varname>mkOption</varname> imported
- from <filename>pkgs/lib/default.nix</filename>. Options may contained
- any attribute but only the following have a special
- meaning: <varname>default</varname>, <varname>example</varname>,
- <varname>description</varname>, <varname>merge</varname>
- and <varname>apply</varname>.</para>
-
- <para>The <varname>merge</varname> attribute is used to merge all values
- defined in all configuration files and this function return a value
- which has the same type as the default value. If the merge function is
- not defined, then a default function
- (<varname>pkgs.lib.mergeDefaultOption</varname>) is used to merge
- values. The <varname>merge</varname> attribute is a function which
- expect two arguments: the location of the option and the list of values
- which have to be merged.</para>
-
- <para>The <varname>apply</varname> attribute is a function used to
- process the option. Thus the value return
- by <option>config.<replaceable>option</replaceable></option> would be
- the result of the <varname>apply</varname> function called with either
- the <varname>default</varname> value or the result of
- the <varname>merge</varname> function.</para>
-
- </callout>
-
- <callout arearefs='conf-syntax-4'>
-
- <para>This line is a common trick used to reduce the amount of
- writing. In this case <varname>cfg</varname> is just a sugar over
- <option>config.services.locate</option></para>
-
- </callout>
-
- <callout arearefs='conf-syntax-5'>
-
- <para>This line is used to declare a special <emphasis>IF</emphasis>
- statement. If you had put a usual <emphasis>IF</emphasis> statement
- here, with the same condition, then you will get an infinite loop. The
- reason is that your condition ask for the value of the
- option <option>config.services.locate.enable</option> but in order to
- get this value you have to evaluate all configuration sets including the
- configuration set contained inside your file.</para>
-
- <para>To remove this extra complexity, <varname>mkIf</varname> has been
- introduced to get rid of possible infinite loop and to factor your
- writing.</para>
-
- </callout>
-
- <callout arearefs='conf-syntax-6'>
-
- <para>The attribute <varname>imports</varname> contains a list of other
- module location. These modules should provide option declarations for
- the current module in order to be evaluated safely.</para>
-
- <para>When a dependence on a NixOS module has to be made, then you
- should use the argument <varname>modulesPath</varname> to prefix the
- location of your NixOS repository.</para>
-
- </callout>
-
- <callout arearefs='conf-syntax-7'>
-
- <para>The attribute <varname>config</varname>, which should not be
- confused with the argument of the same name, contains a set of option
- definitions defined by this module. When there is
- neither <varname>imports</varname> nor <varname>options</varname>, then
- this attribute set can be return without any enclosing. This feature
- allow you to write your <filename>configuration.nix</filename> as a
- module which does not contains any option declarations.</para>
-
- <para>As <varname>mkIf</varname> does not need
- any <emphasis>then</emphasis> part or <emphasis>else</emphasis> part,
- then you can specify one on each option definition with the
- function <varname>mkThenElse</varname>.</para>
-
- <para>To avoid a lot of <varname>mkThenElse</varname> with empty
- <emphasis>else</emphasis> part, a sugar has been added to infer the
- corresponding <emphasis>empty</emphasis>-value of your option when the
- function <varname>mkThenElse</varname> is not used.</para>
-
- <para>If your <emphasis>then</emphasis> part
- and <emphasis>else</emphasis> part are identical, then you should use
- the function <varname>mkAlways</varname> to ignore the condition.</para>
-
- <para>If you need to add another condition, then you can add
<varname>mkIf</varname> to on
- the appropriate location. Thus the <emphasis>then</emphasis> part will
- only be used if all conditions declared with <varname>mkIf</varname>
- are satisfied.</para>
-
- </callout>
-
-</calloutlist>
+</section>
-</para>
-</section>
+<!--===============================================================-->
<section>
@@ -271,6 +303,8 @@
</section>
+<!--===============================================================-->
+
<section>
<title>Building your own NixOS CD</title>
@@ -323,6 +357,8 @@
</section>
+<!--===============================================================-->
+
<section>
<title>Testing the <literal>initrd</literal></title>
_______________________________________________
nix-commits mailing list
[email protected]
http://mail.cs.uu.nl/mailman/listinfo/nix-commits