Option dependencies¶
Now we have some basic knowledge of how to create an option and set its value with a config. But previously, we created an option that was both the input and output. What if we want several inputs and a output that is some combination of those inputs?
That is completely possible!
Options can depend on other options, making it possible to build more useful abstractions.
To make option values available to a module, the arguments of the function declaring the module must include the config
attribute.
Note
Lazy evaluation in the Nix language allows the module system to make a value available in the config argument passed to the module which defines that value.
{
lib,
config,
...
}: let
cfg = config;
in {
options = {
name = lib.mkOption {
type = lib.types.str;
};
title = lib.mkOption {
type = lib.types.str;
};
origin = lib.mkOption {
type = lib.types.str;
};
greeting = lib.mkOption {
type = lib.types.str;
};
};
config = {
greeting = ''
Hello
My name is ${cfg.name}.
I am a ${cfg.title}.
I am from ${cfg.origin}.'';
};
}
As you can see, we have added config
to the function argument of the options.nix
module.
We have also declared name
, title
, and origin
which are all str
types.
Those will be our inputs that will we configure.
We have also declared an option, greeting
, which is also a str
type.
In the same file, we have defined its value using the final configuration values of the other options.
Note
The line cfg = config;
is not strictly necessary.
We could have used the config
argument wherever cfg
was used.
However, it does help mentally separate the idea of the config argument and the config attribute.
If you explore the NixOS modules, you will find more interesting examples of this pattern.
Warning
The config
argument is not the same as the config
attribute:
- The
config
argument holds the result of the module system’s lazy evaluation, which takes into account all modules passed toevalModules
and theirimports
. - The
config
attribute of a module exposes that particular module’s option values to the module system for evaluation.
So now we just set values for name
, title
, and origin
in config.nix
like we have done before.
{...}: {
config = {
name = "Boaty McBoatface";
title = "Autonomous Underwater Vehicle";
origin = "England";
};
}
Setup an eval.nix
to evaluate our modules and return the config
attribute.
{pkgs}:
(
pkgs.lib.evalModules {
modules = [
./options.nix
./config.nix
];
}
)
.config
Create a run.sh
run script to evalute the eval.nix
file.
nix eval -f eval.nix \
--apply 'x: x {pkgs = import <nixpkgs> {};}' \
--json | nix run nixpkgs#jq -- .
And if we run the script (./run.sh
), we have our configuration.
{
"greeting": "Hello\nMy name is Boaty McBoatface.\nI am a Autonomous Underwater Vehicle.\nI am from England.",
"name": "Boaty McBoatface",
"origin": "England",
"title": "Autonomous Underwater Vehicle"
}
Notice that it gave use the entire configuration, which is to be expected.
What if we just want greeting
?
We can specify to only return the greeting
attribute in our new eval-greeting.nix
file.
{pkgs}:
(
pkgs.lib.evalModules {
modules = [
./options.nix
./config.nix
];
}
)
.config
.greeting
Update our run script as shown in run-greeting.sh
.
nix eval -f eval-greeting.nix \
--apply 'x: x {pkgs = import <nixpkgs> {};}' \
--json | nix run nixpkgs#jq -- -r
And if we run the new script (./run-greeting.sh
), we have just the configuration of greeting
.
Hello
My name is Boaty McBoatface.
I am a Autonomous Underwater Vehicle.
I am from England.