从零开始的 NixOS 教程(Flake篇)
本文最后更新于 2023年11月11日 凌晨
想不到还有人看,本来我都弃坑了,想到有人看,又捡起来了。我的 flake 已经托管到 github 仓库了,目前我还算新手,因此提交信息还比较乱。
安装教程见从零开始的 NixOS 教程(安装篇)。
Nix 系列最吸引我的地方之一就在于 flake 了,我们可以把所有的 flake 托管到 GitHub, 然后在服务器上引入。这样简简单单就备份好了各种配置文件。重装系统或者批量部署非常容易。
简单说明 Nix 的语法
我在写 flake 的时候,最痛苦的就是不知道要怎么写,也不知道该去哪里学。后来慢慢读了一些文档,但是也还是不会写。直到我看到了 nix pills. 对 nix 的机制有了一些了解,才算比较会用/会写 nix 了。
Nix 是一个函数式编程语言,我们需要注意的通常就三点:
{}
是一个set
, 不是其他语言中的作用域的概念。p:q
是一个函数,接受一个参数p
,输出一个q
.- 某些
.nix
文件需要遵守特定的格式(包含且只能包含某些特定的属性,比如flake.nix
)
开始抄一个 Flake
我们在上一篇教程里面已经开启了 flake 支持,现在只要在 /etc/nixos
下面新建 flake.nix
并输入如下内容
1 |
|
这里简单说一下: 这个 flake.nix
就是一个 set
, 具有三个属性 description
(字符串), inputs
(set
), outputs
(函数)。
没错, outputs
是一个函数 {self,nixpkgs,...}:{}
参数是第一个 {}
中的 self
(就是 output
自己)与 nixpkgs
, 还有一些省略的参数...
(就是说你可以多传,但是我们不使用),
函数返回值{}
是一个 set
, 它包含一个属性 nixosConfigurations
。
保存之后执行 nix flake update
会自动生成一个 flake.lock
, 它是一个 json, 记录了当时所使用的仓库的具体的 commit id 以保证可重复性。
1 |
|
接下来我们运行 nixos-rebuild switch
来切换到 flake.nix
。当存在 flake.nix
的时候, Nix 会优先使用 flake.nix
而不是 configuration.nix
。(注意:并不是同时使用,因此我们在 flake.nix
里面手动引入了 configuration.nix
)
注意:如果你启用了 flake, 并使用 Git 来管理文件,那么 nix 会忽略不由 Git 管理的文件,并且仅读取 stage 或者 commit 了的文件。 这点在创建新文件的时候需要注意。
另外可以把 /etc/nixos
链接到用户目录下,并且权限改为 777(或者把 owner 修改为自己的用户,这样子可以用普通用户修改了,问过 NickCao, 这么干没问题)
值得注意的是 flake.nix
的语法是固定的,我们并不能在 output 里面自己定义变量。下面举个例子说明:
1 |
|
这样子是不可以的,在 output里面只能使用它规定好的一些属性(比如nixosConfigurations
),不能自己定义新的属性。
当我们需要一些辅助变量的时候,我们要使用 let
块,举例:
1 |
|
另外一个建议是在 flake 的最后配置一个 Formatter, 我一般使用
1 |
|
然后每次提交之前执行 nix fmt
格式化文档。当然你也可以把它写到git pre-commit 的 hook 里面,这样每次提交前会自动帮你格式化。
使用 Nvfetcher 更新 vscode 插件
vscode 的插件只有一部分在 nix 的官方源里面,其他的要自己管理,但是管理起来比较麻烦。需要手动填写版本号跟shasum, 每次还得手动更新,让人苦不堪言。
但是后来有人给我推荐了 nvfetcher, 它可以自动更新版本号跟 shasum, 替代手工维护,达到跟 flake.lock
类似的效果。我们只需要写一个 nvfetcher.toml
然后执行 nvfetcher 就能自动生成一个 nix 文件跟 json文件。
先看一下 nvfetcher 的配置吧
1 |
|
这几个部分都是必要的,不能再精简了。
生成的文件我们只用 generated.json
, 不使用 generated.nix
. 这里需要用到一些 nix 的内置函数来处理 json, 我们先看一下需要的格式长什么样
1 |
|
[]
之间的部分就是我们需要的啦,它是一个 list of set(集合的数组)。
再看看我们的 gernerated.json
(一小部分)
1 |
|
我们需要一个函数把 json转化为 nix 的 set. 可以参考如下函数。
1 |
|
这里 parsePkg
接受一个 pkg
返回一个 set
, 其中 with pkg;
算是一个局部作用域,在后面可以直接使用 pkg
的属性,例如 version
,而不用写 ``pkg.version.
inherit version 是
version=version的简便写法,因此这里等同于
version=pkg.version`.
nix 下有函数可以读取 json
1 |
|
最后我们可以使用 builtins.attrValues
来将 属性转化为 list
1 |
|
整体可以看 extFromMarket.