feat: update contents about lib.mkBefore & lib.mkAfter

This commit is contained in:
Ryan Yin 2023-12-21 13:28:36 +08:00
parent 883393eeb9
commit 50ef281137
2 changed files with 126 additions and 86 deletions

View File

@ -185,6 +185,8 @@ Then, for my desktop machine, I override the value in [ryan4yin/nix-config/blob/
In addition to `lib.mkDefault` and `lib.mkForce`, there are also `lib.mkBefore` and `lib.mkAfter`, which are used to set the merge order of **list-type options**. These functions further contribute to the modularization of the configuration. In addition to `lib.mkDefault` and `lib.mkForce`, there are also `lib.mkBefore` and `lib.mkAfter`, which are used to set the merge order of **list-type options**. These functions further contribute to the modularization of the configuration.
> I haven't found the official documentation for list-type options, but I simply understand that they are types whose merge results are related to the order of merging. According to this understanding, both `list` and `string` types are list-type options, and these functions can indeed be used on these two types in practice.
As mentioned earlier, when you define multiple values with the same **override priority**, Nix will throw an error. However, by using `lib.mkOrder`, `lib.mkBefore`, or `lib.mkAfter`, you can define multiple values with the same override priority, and they will be merged in the order you specify. As mentioned earlier, when you define multiple values with the same **override priority**, Nix will throw an error. However, by using `lib.mkOrder`, `lib.mkBefore`, or `lib.mkAfter`, you can define multiple values with the same override priority, and they will be merged in the order you specify.
To examine the source code of `lib.mkBefore`, you can run `nix repl -f '<nixpkgs>'` and then enter `:e lib.mkBefore`. To learn more about `nix repl`, type `:?` for the help information: To examine the source code of `lib.mkBefore`, you can run `nix repl -f '<nixpkgs>'` and then enter `:e lib.mkBefore`. To learn more about `nix repl`, type `:?` for the help information:
@ -210,69 +212,86 @@ Therefore, `lib.mkBefore` is a shorthand for `lib.mkOrder 500`, and `lib.mkAfter
To test the usage of `lib.mkBefore` and `lib.mkAfter`, let's create a simple Flake project: To test the usage of `lib.mkBefore` and `lib.mkAfter`, let's create a simple Flake project:
```shell{16-29} ```nix{10-38}
# Create flake.nix with the following content # flake.nix
cat <<EOF | sudo tee flake.nix
{ {
description = "Ryan's NixOS Flake"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
outputs = {nixpkgs, ...}: {
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
};
outputs = { self, nixpkgs, ... }@inputs: {
nixosConfigurations = { nixosConfigurations = {
"nixos-test" = nixpkgs.lib.nixosSystem { "nixos-test" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ modules = [
# Demo module 1: insert 'git' at the head of the list ({lib, ...}: {
({lib, pkgs, ...}: { programs.bash.shellInit = lib.mkBefore ''
environment.systemPackages = lib.mkBefore [pkgs.git]; echo 'insert before default'
'';
programs.zsh.shellInit = lib.mkBefore "echo 'insert before default';";
nix.settings.substituters = lib.mkBefore [
"https://nix-community.cachix.org"
];
}) })
# Demo module 2: insert 'vim' at the tail of the list ({lib, ...}: {
({lib, pkgs, ...}: { programs.bash.shellInit = lib.mkAfter ''
environment.systemPackages = lib.mkAfter [pkgs.vim]; echo 'insert after default'
'';
programs.zsh.shellInit = lib.mkAfter "echo 'insert after default';";
nix.settings.substituters = lib.mkAfter [
"https://ryan4yin.cachix.org"
];
}) })
# Demo module 3: simply add 'curl' to the list ({lib, ...}: {
({lib, pkgs, ...}: { programs.bash.shellInit = ''
environment.systemPackages = with pkgs; [curl]; echo 'this is default'
'';
programs.zsh.shellInit = "echo 'this is default';";
nix.settings.substituters = [
"https://nix-community.cachix.org"
];
}) })
]; ];
}; };
}; };
}; };
} }
EOF
# Create flake.lock
nix flake update
# Enter the nix repl environment
nix repl
Welcome to Nix 2.13.3. Type :? for help.
# Load the flake we just created
nix-repl> :lf .
Added 9 variables.
# Check the order of systemPackages
nix-repl> outputs.nixosConfigurations.nixos-test.config.environment.systemPackages
[ «derivation /nix/store/0xvn7ssrwa0ax646gl4hwn8cpi05zl9j-git-2.40.1.drv»
«derivation /nix/store/7x8qmbvfai68sf73zq9szs5q78mc0kny-curl-8.1.1.drv»
«derivation /nix/store/bly81l03kh0dfly9ix2ysps6kyn1hrjl-nixos-container.drv»
......
......
«derivation /nix/store/qpmpv
q5azka70lvamsca4g4sf55j8994-vim-9.0.1441.drv» ]
``` ```
As you can see, the order of `systemPackages` is `git -> curl -> default packages -> vim`, which matches the order we defined in `flake.nix`. The flake above contains the usage of `lib.mkBefore` and `lib.mkAfter` on multiline strings, single-line strings, and lists. Let's test the results:
```bash
# Example 1: multiline string merging
echo $(nix eval .#nixosConfigurations.nixos-test.config.programs.bash.shellInit)
trace: warning: system.stateVersion is not set, defaulting to 23.11. Read why this matters on https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersio
n.
"echo 'insert before default'
echo 'this is default'
if [ -z \"$__NIXOS_SET_ENVIRONMENT_DONE\" ]; then
. /nix/store/60882lm9znqdmbssxqsd5bgnb7gybaf2-set-environment
fi
echo 'insert after default'
"
# example 2: single-line string merging
echo $(nix eval .#nixosConfigurations.nixos-test.config.programs.zsh.shellInit)
"echo 'insert before default';
echo 'this is default';
echo 'insert after default';"
# Example 3: list merging
nix eval .#nixosConfigurations.nixos-test.config.nix.settings.substituters
[ "https://nix-community.cachix.org" "https://nix-community.cachix.org" "https://cache.nixos.org/" "https://ryan4yin.cachix.org" ]
```
As you can see, `lib.mkBefore` and `lib.mkAfter` can define the order of merging of multiline strings, single-line strings, and lists. The order of merging is the same as the order of definition.
> Although adjusting the order of `systemPackages` may not be useful in practice, it can be helpful in other scenarios.
> For a deeper introduction to the module system, see [Module System & Custom Options](../other-usage-of-flakes/module-system.md). > For a deeper introduction to the module system, see [Module System & Custom Options](../other-usage-of-flakes/module-system.md).

View File

@ -162,6 +162,8 @@ Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,
`lib.mkBefore``lib.mkAfter` 用于设置**列表类型**的合并顺序,它们跟 `lib.mkDefault``lib.mkForce` 一样,也被用于模块化配置。 `lib.mkBefore``lib.mkAfter` 用于设置**列表类型**的合并顺序,它们跟 `lib.mkDefault``lib.mkForce` 一样,也被用于模块化配置。
> 列表类型的定义我没找到官方文档但我简单理解应该就是合并结果与合并先后顺序有关的类型。按这个理解list 跟 string 类型都是列表类型,实际测试这几个函数也确实能用在这两个类型上。
前面说了如果你定义了多个优先级相同的值Nix 会报错说存在参数冲突,需要你手动解决。 前面说了如果你定义了多个优先级相同的值Nix 会报错说存在参数冲突,需要你手动解决。
但是如果你定义的是**列表类型**的值Nix 就不会报错了,因为 Nix 会把你定义的多个值合并成一个列表,而 `lib.mkBefore``lib.mkAfter` 就是用于设置这个列表的合并顺序的。 但是如果你定义的是**列表类型**的值Nix 就不会报错了,因为 Nix 会把你定义的多个值合并成一个列表,而 `lib.mkBefore``lib.mkAfter` 就是用于设置这个列表的合并顺序的。
@ -189,67 +191,86 @@ Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,
为了更直观地理解这两个函数,现在来创建一个 flake 测试下: 为了更直观地理解这两个函数,现在来创建一个 flake 测试下:
```shell{16-29} ```nix{10-38}
# 使用如下内容创建一个 flake.nix 文件 # flake.nix
cat <<EOF | sudo tee flake.nix
{ {
description = "Ryan's NixOS Flake"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
outputs = {nixpkgs, ...}: {
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
};
outputs = { self, nixpkgs, ... }@inputs: {
nixosConfigurations = { nixosConfigurations = {
"nixos-test" = nixpkgs.lib.nixosSystem { "nixos-test" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ modules = [
# demo module 1, 在列表头插入 git ({lib, ...}: {
({lib, pkgs, ...}: { programs.bash.shellInit = lib.mkBefore ''
environment.systemPackages = lib.mkBefore [pkgs.git]; echo 'insert before default'
'';
programs.zsh.shellInit = lib.mkBefore "echo 'insert before default';";
nix.settings.substituters = lib.mkBefore [
"https://nix-community.cachix.org"
];
}) })
# demo module 2, 在列表尾插入 vim ({lib, ...}: {
({lib, pkgs, ...}: { programs.bash.shellInit = lib.mkAfter ''
environment.systemPackages = lib.mkAfter [pkgs.vim]; echo 'insert after default'
'';
programs.zsh.shellInit = lib.mkAfter "echo 'insert after default';";
nix.settings.substituters = lib.mkAfter [
"https://ryan4yin.cachix.org"
];
}) })
# demo module 3, 添加 curl但是不设置优先级 ({lib, ...}: {
({lib, pkgs, ...}: { programs.bash.shellInit = ''
environment.systemPackages = with pkgs; [curl]; echo 'this is default'
'';
programs.zsh.shellInit = "echo 'this is default';";
nix.settings.substituters = [
"https://nix-community.cachix.org"
];
}) })
]; ];
}; };
}; };
}; };
} }
EOF
# 生成 flake.lock
nix flake update
# 进入 nix REPL 解释器
nix repl
Welcome to Nix 2.13.3. Type :? for help.
# 将我们刚刚创建好的 flake 加载到当前作用域中
nix-repl> :lf .
Added 9 variables.
# 检查下 systemPackages 的顺序,看看跟我们预期的是否一致
nix-repl> outputs.nixosConfigurations.nixos-test.config.environment.systemPackages
[ «derivation /nix/store/0xvn7ssrwa0ax646gl4hwn8cpi05zl9j-git-2.40.1.drv»
«derivation /nix/store/7x8qmbvfai68sf73zq9szs5q78mc0kny-curl-8.1.1.drv»
«derivation /nix/store/bly81l03kh0dfly9ix2ysps6kyn1hrjl-nixos-container.drv»
......
......
«derivation /nix/store/qpmpvq5azka70lvamsca4g4sf55j8994-vim-9.0.1441.drv» ]
``` ```
能看到 `systemPackages` 的顺序是 `git -> curl -> default packages -> vim`,跟我们预期的一致。`lib.mkBefore [pkgs.git]` 确实是将 `git` 插入到了列表头,而 `lib.mkAfter [pkgs.vim]` 则是将 `vim` 插入到了列表尾。 上面的例子包含了在多行字符串、单行字符串,以及列表三种类型上应用 `lib.mkBefore``lib.mkAfter`,下面测试下结果:
```bash
# 示例一:多行字符串合并
echo $(nix eval .#nixosConfigurations.nixos-test.config.programs.bash.shellInit)
trace: warning: system.stateVersion is not set, defaulting to 23.11. Read why this matters on https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersio
n.
"echo 'insert before default'
echo 'this is default'
if [ -z \"$__NIXOS_SET_ENVIRONMENT_DONE\" ]; then
. /nix/store/60882lm9znqdmbssxqsd5bgnb7gybaf2-set-environment
fi
echo 'insert after default'
"
# 示例二:单行字符串合并
echo $(nix eval .#nixosConfigurations.nixos-test.config.programs.zsh.shellInit)
"echo 'insert before default';
echo 'this is default';
echo 'insert after default';"
# 示例三:列表合并
nix eval .#nixosConfigurations.nixos-test.config.nix.settings.substituters
[ "https://nix-community.cachix.org" "https://nix-community.cachix.org" "https://cache.nixos.org/" "https://ryan4yin.cachix.org" ]
```
可以看到,`lib.mkBefore` 会将后面的值插入到前面,而 `lib.mkAfter` 会将后面的值插入到前面。
> 虽然单纯调整 `systemPackages` 的顺序没什么用,但是在其他地方可能会有用...
> 对模块系统更深入的介绍,参见 [模块系统与自定义 options](../other-usage-of-flakes/module-system.md). > 对模块系统更深入的介绍,参见 [模块系统与自定义 options](../other-usage-of-flakes/module-system.md).