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 nix-comm...@cs.uu.nl http://mail.cs.uu.nl/mailman/listinfo/nix-commits