diff --git a/doc/manual/development.xml b/doc/manual/development.xml
index 9d0b42c4349..3887904a92e 100644
--- a/doc/manual/development.xml
+++ b/doc/manual/development.xml
@@ -7,42 +7,209 @@
NixOS.
+
+
Extending NixOS
-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.
+NixOS is based on a modular system for declarative configuration.
+ This system combines multiple modules to produce one
+ configuration. One of the module which compose your computer
+ configuration is /etc/nixos/configuration.nix. Other
+ modules are available under NixOS modules
+ directory
- A configuration file is the same as your own computer
- configuration.
+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 define options to setup its
+ configuration, and it can also declare options to be
+ fed by other modules.
-Usual configuration file
+
+
+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.
+
+When the expression is a function, it should expect only one argument
+ which is an attribute set containing an attribute
+ named config and another attribute
+ named pkgs. The config 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 .
+ The pkgs attribute
+ contains nixpkgs attribute set of packages. This
+ attribute is necessary for declaring options.
+
+Usual module content
-{config, modulesPath, pkgs, ...}:
+{config, pkgs, ...}:
+
+{
+ imports = [
+
+ ];
+
+ options = {
+
+ };
+
+ config = {
+
+ };
+}
+
+
+ Illustrates
+ a module skeleton.
+
+
+
+ This line makes the current Nix expression a function. This
+ line can be omitted if there is no reference to pkgs
+ and config inside the module.
+
+
+
+ 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 modules/module-list.nix.
+ The default modules don't need to be added in the import list.
+
+
+
+ This attribute set contains an attribute set of option
+ declaration.
+
+
+
+ This attribute set contains an attribute set of option
+ definitions. 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 /etc/nixos/configuration.nix.
+
+
+
+
+
+
+
+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.
+
+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 properties.
+
+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 mkIf, mkAlways
+ and mkAssert. Global properties
+ are mkOverride, mkDefault
+ and mkOrder.
+
+mkIf is used to remove the option definitions which
+ are below it if the condition is evaluated to
+ false. mkAssert expects the condition to be evaluated
+ to true otherwise it raises an error message. mkAlways
+ is used to ignore all the mkIf
+ and mkAssert which have been made
+ previously. mkAlways and mkAssert
+ are often used together to set an option value and to ensure that it has
+ not been masked by another one.
+
+mkOverride 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, mkDefault 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.
+
+mkOrder 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.
+
+
+
+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 config argument).
+
+The config 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.
+
+Options are declared with the
+ function pkgs.lib.mkOption. 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.
+
+Types are used to provide a merge strategy for options and to ensure
+ the type of each option definitions. They are defined
+ in pkgs.lib.types.
+
+The merge function expects a list of option definitions and merge
+ them to obtain one result of the same type.
+
+The post-process function (named apply) 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.
+
+
+
+Locate Module Example
+
+{config, pkgs, ...}:
+
+with pkgs.lib;
let
- inherit (pkgs.lib) mkOption mkIf mkThenElse types;
-
- cfg = config.services.locate;
+ 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 = [
- (modulesPath + /services/scheduling/cron.nix)
+ imports = [
+ /etc/nixos/nixos/modules/services/scheduling/cron.nix
];
- options = {
+ 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 locate command.
@@ -51,7 +218,7 @@ in
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,165 +228,30 @@ in
};
};
- config = mkIf cfg.enable {
+ config = mkCheck {
services.cron = {
- systemCronJobs = mkThenElse {
- thenPart = "${cfg.period} root ${cmd}";
- elsePart = "";
- };
+ enable = mkAlways cfg.enable;
+ systemCronJobs = "${cfg.period} root ${cmd}";
};
};
}
- shows the configuration
- file 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 upstart-jobs/cron/locate.nix. 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 configuration
- set.
-
-
-
-
-
- This line declares the arguments of the configuration file. You
- can omit this line if there is no reference to pkgs
- and config inside the configuration file.
-
- The argument pkgs refers to NixPkgs and allow
- you to access all attributes contained inside it. In this
- example pkgs is used to retrieve common functions to
- ease the writing of configuration files
- like mkOption, mkIf
- and mkThenElse.
-
- The argument config 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 config is used to retrieve the status of
- the enable 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 is always false
- because it may have been defined in another configuration file.
-
-
-
-
-
- This line is used to import a functions that are useful for
- writing this configuration file.
-
-
-
-
-
- The variable options is
- a configuration set which is only used to declare
- options with the function mkOption imported
- from pkgs/lib/default.nix. Options may contained
- any attribute but only the following have a special
- meaning: default, example,
- description, merge
- and apply.
-
- The merge 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
- (pkgs.lib.mergeDefaultOption) is used to merge
- values. The merge attribute is a function which
- expect two arguments: the location of the option and the list of values
- which have to be merged.
-
- The apply attribute is a function used to
- process the option. Thus the value return
- by would be
- the result of the apply function called with either
- the default value or the result of
- the merge function.
-
-
-
-
-
- This line is a common trick used to reduce the amount of
- writing. In this case cfg is just a sugar over
-
-
-
-
-
-
- This line is used to declare a special IF
- statement. If you had put a usual IF 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 but in order to
- get this value you have to evaluate all configuration sets including the
- configuration set contained inside your file.
-
- To remove this extra complexity, mkIf has been
- introduced to get rid of possible infinite loop and to factor your
- writing.
-
-
-
-
-
- The attribute imports contains a list of other
- module location. These modules should provide option declarations for
- the current module in order to be evaluated safely.
-
- When a dependence on a NixOS module has to be made, then you
- should use the argument modulesPath to prefix the
- location of your NixOS repository.
-
-
-
-
-
- The attribute config, 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 imports nor options, then
- this attribute set can be return without any enclosing. This feature
- allow you to write your configuration.nix as a
- module which does not contains any option declarations.
-
- As mkIf does not need
- any then part or else part,
- then you can specify one on each option definition with the
- function mkThenElse.
-
- To avoid a lot of mkThenElse with empty
- else part, a sugar has been added to infer the
- corresponding empty-value of your option when the
- function mkThenElse is not used.
-
- If your then part
- and else part are identical, then you should use
- the function mkAlways to ignore the condition.
-
- If you need to add another condition, then you can add mkIf to on
- the appropriate location. Thus the then part will
- only be used if all conditions declared with mkIf
- are satisfied.
-
-
-
-
-
-
+ 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.
+
+
+
Building specific parts of NixOS
@@ -271,6 +303,8 @@ config.system.build
+
+
Building your own NixOS CD
@@ -323,6 +357,8 @@ $ ./result/bin/nixos-install
+
+
Testing the initrd