From cd4564ebb391c343f0f8fad1772a462b53c86084 Mon Sep 17 00:00:00 2001 From: Daniel Baker Date: Thu, 16 May 2024 19:55:13 -0700 Subject: [PATCH] Add first lesson for the new module tutorials. --- source/tutorials/index.md | 2 +- .../module-system/a-basic-module/config.nix | 6 + .../module-system/a-basic-module/eval.nix | 7 ++ .../module-system/a-basic-module/index.md | 108 ++++++++++++++++++ .../module-system/a-basic-module/options.nix | 6 + .../module-system/a-basic-module/run.sh | 3 + source/tutorials/module-system/index.md | 9 ++ 7 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 source/tutorials/module-system/a-basic-module/config.nix create mode 100644 source/tutorials/module-system/a-basic-module/eval.nix create mode 100644 source/tutorials/module-system/a-basic-module/index.md create mode 100644 source/tutorials/module-system/a-basic-module/options.nix create mode 100644 source/tutorials/module-system/a-basic-module/run.sh create mode 100644 source/tutorials/module-system/index.md diff --git a/source/tutorials/index.md b/source/tutorials/index.md index 616ad75fa..eca4196f4 100644 --- a/source/tutorials/index.md +++ b/source/tutorials/index.md @@ -14,5 +14,5 @@ Package parameters and overrides working-with-local-files.md nixos/index.md cross-compilation.md -module-system/module-system.md +module-system/index.md ``` diff --git a/source/tutorials/module-system/a-basic-module/config.nix b/source/tutorials/module-system/a-basic-module/config.nix new file mode 100644 index 000000000..ed9c5aa4d --- /dev/null +++ b/source/tutorials/module-system/a-basic-module/config.nix @@ -0,0 +1,6 @@ +{ ... }: +{ + config = { + name = "Boaty McBoatface"; + }; +} diff --git a/source/tutorials/module-system/a-basic-module/eval.nix b/source/tutorials/module-system/a-basic-module/eval.nix new file mode 100644 index 000000000..2a0e09417 --- /dev/null +++ b/source/tutorials/module-system/a-basic-module/eval.nix @@ -0,0 +1,7 @@ +{ pkgs }: +(pkgs.lib.evalModules { + modules = [ + ./options.nix + ./config.nix + ]; +}).config diff --git a/source/tutorials/module-system/a-basic-module/index.md b/source/tutorials/module-system/a-basic-module/index.md new file mode 100644 index 000000000..c7ad23b5c --- /dev/null +++ b/source/tutorials/module-system/a-basic-module/index.md @@ -0,0 +1,108 @@ +# A basic module + +What is a module? + +* A module is a function that takes an attrset and returns an attrset. +* It *may* declare options. +* It *may* define option values. +* When evaluated, it produces a configuration based on the declarations and definitions. + +The format is like so: + +```{code-block} nix +:caption: useless.nix +{...}: { +} +``` + +This, as the filename suggests, is completely useless. +It takes no arguments and returns an empty attrset. +However, it is a valid module. +Let us add to this to make it a bit more useful. + +To define any values, the module system first has to know which ones are allowed. +This is done by declaring options that specify which values can be set and used elsewhere. +Options are declared by adding an attribute under the top-level `options` attribute. +The most general way to declare an option is using `lib.mkOption`. + +```{literalinclude} options.nix +:language: nix +:caption: options.nix +``` + +While many attributes for customizing options are available, +the most important one is `type`, +which specifies which values are valid for an option. +There are several types available under [`lib.types`][option-types-basic] in the Nixpkgs library. + +As you can see, we have declared an option `name`. +We have specificied that the `name` option will be of type `str`, so the module system will expect a string when we set a value. + +You may have noticed that we also changed the function arguments. +Now the module is a function which takes *at least* one argument, `lib`, +and may accept other arguments (expressed by the ellipsis `...`). +This will make Nixpkgs library functions available within the function body. +We needed this to get access to `mkOption` and `types`. + +:::{note} +The ellipsis `...` is necessary because arbitrary arguments can be passed to modules. +Every module should have this. + +The `lib` argument is passed automatically by the module system. +It is absolutely vital for modules that have option declarations, as you will need `lib` for defining options and their types. +It is one of several arguments that are automatically provided by the module system. +The full list of arguments is discussed later. +::: + +Now that we have declared an option, we would naturally want to give it a value. +Options can be set or *defined* using another top-level attribute, `config`. + +```{literalinclude} config.nix +:language: nix +:caption: config.nix +``` + +Previously, in our option declaration, we created an option, `name`, with a string type. +Here, in our option definition, we have set that same option to a string. + +:::{note} +`options` and `config` and have formal names — +that is ***option declarations*** and ***option definitions*** respectively. +The rest of these lessons will use them interchangeably. +::: + +:::{note} +Our option declarations and option definitions do not need to exist in the same file. +When we evaluate our modules, we can simply include both files. +As long as every definition has a declaration, we can successfully evaluate our modules. +If there is an option definition that has not been declared, the module system will throw an error. +::: + +Now that we have our declaration and definition, how do we evaluate them? +There is a function provided by the Nixpkgs library, `evalModules`. +It takes an attrset as an argument and one of the attributes is `modules` which is a list of modules you want to merge and evaluate. +The output of `evalModules` is a rather large attrset with a information about all the modules. +For now, the attribute we care about is `config` which is where the final configuration values appear. + +```{literalinclude} eval.nix +:language: nix +:caption: eval.nix +``` + +We can create a helper script to parse and evaluate our `eval.nix` file and print the output in a nice format. + +```{literalinclude} run.sh +:language: bash +:caption: run.sh +``` + +If you execute the run file (`./run.sh`), you should see an output that matches what we have configured. + +```{code-block} +{ + "name": "Boaty McBoatface" +} +``` + +[option-types-basic]: https://nixos.org/manual/nixos/stable/#sec-option-types-basic + diff --git a/source/tutorials/module-system/a-basic-module/options.nix b/source/tutorials/module-system/a-basic-module/options.nix new file mode 100644 index 000000000..aca25b084 --- /dev/null +++ b/source/tutorials/module-system/a-basic-module/options.nix @@ -0,0 +1,6 @@ +{ lib, ... }: +{ + options = { + name = lib.mkOption { type = lib.types.str; }; + }; +} diff --git a/source/tutorials/module-system/a-basic-module/run.sh b/source/tutorials/module-system/a-basic-module/run.sh new file mode 100644 index 000000000..66d9980ed --- /dev/null +++ b/source/tutorials/module-system/a-basic-module/run.sh @@ -0,0 +1,3 @@ +nix eval -f eval.nix \ + --apply 'x: x {pkgs = import {};}' \ + --json | nix run nixpkgs#jq -- . diff --git a/source/tutorials/module-system/index.md b/source/tutorials/module-system/index.md new file mode 100644 index 000000000..0db4d58d6 --- /dev/null +++ b/source/tutorials/module-system/index.md @@ -0,0 +1,9 @@ +# Module system + +Learn about the module system. + +```{toctree} +:maxdepth: 1 +a-basic-module/index.md +module-system.md +```