如何将 /etc/nixos/configuration.nix 拆分为单独的模块?

Mir*_*lov 18 nixos nix

假设我有一个非常简单的NixOS 配置文件

{ config, pkgs, ... }:    
{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];
  # SOME STUFF
  environment.systemPackages = with pkgs; [ emacs gitFull ];
  # SOME STUFF
}
Run Code Online (Sandbox Code Playgroud)

我知道 NixOS 实现了一个模块系统,一个模块就是一个.nix文件。每个.nix文件都应该包含任何有效的Nix 表达式(例如一个函数或一个集合)。这意味着 NixOS 配置文件/etc/nixos/configuration.nix本身就是一个模块,包含一个 Nix 表达式。

我也知道要使另一个模块中的 Nix 表达式对我正在使用的模块可见,我可以使用内置import函数

我想将系统包的声明(包含emacs和的列表gitFull)拆分为 file packages.nix。如何将 NixOS 配置文件拆分为单独的模块?

Mir*_*lov 24

Nix 表达式

一个尼克斯的表达就像任何编程语言的表达:任何计算结果为数值或功能。这种情况下的值也可以是列表或集合。作为 Nix 模块(带有扩展名的文件.nix)可以包含任何 Nix 表达式,您希望 NixOS 配置文件 ( /etc/nixos/configuration.nix) 包含单个 Nix 表达式作为其文件内容。

NixOS 配置文件包含以下形式的 Nix 表达式:

{config, pkgs, ...}: { /* various configuration options */ }
Run Code Online (Sandbox Code Playgroud)

如果你仔细观察,你会发现它是一个函数,因为函数遵循形式pattern: form。您还可以看到它是一个接受集合并返回集合的函数。例如,如果您有一个 function f = {x, y}: {a = x + y;},那么您可以将其称为 asf {x=1; y=2;}并返回一个 set {a=3;}

因此,这意味着当您调用 时nixos-rebuild switch,某些东西会调用 NixOS 配置文件中的函数,并使用必须包含属性configpkgs.

进口

下面的例子./hardware-configuration.nix,简单的方法来提取的软件包列表到一个单独的模块packages.nix就是翻录environment.systemPackages选项,并把./packages.nix进入imports选项。你/etc/nixos/configuration.nix会看起来像:

{ config, ... }:    
{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
      # Include the package list.
      ./packages.nix
    ];
  # SOME STUFF
  # SOME STUFF
}
Run Code Online (Sandbox Code Playgroud)

/etc/nixos/packages.nix会看起来像:

{ pkgs, ... }:
{
  environment.systemPackages = with pkgs; [ emacs gitFull ];
}
Run Code Online (Sandbox Code Playgroud)

这是如何运作的?当您运行 时nixos-rebuild switch,评估 Nix 表达式并决定安装包等的过程会configuration.nix使用一组属性调用,其中一些属性是configpkgs

它发现属性imports返回set里面,所以它的计算结果中的模块,每一个尼克斯表达imports使用相同的参数(包含configpkgs等)。

你必须有pkgs一个函数的参数(或者,从技术上讲,一个集合的属性,它本身就是一个参数) in packages.nix,因为,从 Nix 语言的角度来看,这个过程可能会也可能不会调用带有集合的函数包含pkgs. 如果不是,你会在运行时引用什么属性with pkgs

您还必须有省略号,因为可能会使用其他属性调用该函数,而不仅仅是pkgs.

为什么没有pkgsconfiguration.nix?您可以拥有它,但如果您不在文件中的任何地方引用它,则可以放心地省略它,因为无论如何省略号都会包含它们。

通过调用外部函数更新属性

另一种方法是创建一个函数,该函数返回一个具有某些属性的集合,并将该属性的值放入environment.systemPackages. 这是你的configuration.nix

{ config, pkgs, ... }:    
{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];
  # SOME STUFF
  environment.systemPackages = import ./packages.nix pkgs;
  # SOME STUFF
}
Run Code Online (Sandbox Code Playgroud)

你的packages.nix

pkgs: with pkgs; [ emacs gitFull ]
Run Code Online (Sandbox Code Playgroud)

import ./packages.nix pkgs意思是:加载并返回 Nix 表达式./packages.nix,因为它是一个函数,使用参数调用它pkgswith pkgs; [ emacs gitFull ]是一个with-expression,它将分号之前的表达式的范围带到分号之后的表达式。没有它,它将是[ pkgs.emacs pkgs.gitFull ]

  • @CMCDragonkai `imports` 的值只是一个列表,因此您可以有条件地将元素附加到该列表中,例如 `imports = [ ./foo.nix ./bar.nix ] ++ (if baz then [ ./quux.nix ] 其他 []);` (2认同)