¿Cómo dividir /etc/nixos/configuration.nix en módulos separados?

14

Supongamos que tengo un archivo de configuración de NixOS muy simple :

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

Sé que NixOS implementa un sistema de módulos , y un módulo es un .nixarchivo. Cada .nixarchivo debe contener cualquier expresión Nix válida (por ejemplo, una función o un conjunto). Esto significa que el archivo de configuración de NixOS /etc/nixos/configuration.nixes en sí mismo un módulo, que contiene una expresión de Nix.

También sé que para hacer que la expresión de Nix en otro módulo sea visible para el módulo con el que estoy trabajando, puedo usar una importfunción incorporada .

Quiero dividir la declaración de los paquetes del sistema (la lista que contiene emacsy gitFull) en un archivo packages.nix. ¿Cómo divido el archivo de configuración de NixOS en módulos separados?

Mirzhan Irkegulov
fuente

Respuestas:

22

Expresiones Nix

Una expresión de Nix es como cualquier expresión de lenguaje de programación: cualquier cosa que se evalúe como un valor o una función. Un valor en este caso también puede ser una lista o un conjunto. Como un módulo Nix (archivo con extensión .nix) puede contener cualquier expresión Nix, esperaría que el archivo de configuración NixOS ( /etc/nixos/configuration.nix) contenga una sola expresión Nix como contenido de su archivo.

El archivo de configuración de NixOS contiene una expresión Nix de la forma:

{config, pkgs, ...}: { /* various configuration options */ }

Si observa de cerca, puede ver que es una función , porque las funciones siguen la forma pattern: form. También puede ver que es una función que acepta un conjunto y devuelve un conjunto. Por ejemplo, si tiene una función f = {x, y}: {a = x + y;}, puede llamarla como f {x=1; y=2;}y recuperar un conjunto {a=3;}.

Eso significa que cuando llamas nixos-rebuild switch, algo llama a la función dentro del archivo de configuración de NixOS con el conjunto que debe contener atributos configy pkgs.

importaciones

Siguiendo el ejemplo de ./hardware-configuration.nix, la forma simple de extraer la lista de paquetes en un módulo separado packages.nixes simplemente extraer la environment.systemPackagesopción y ponerla ./packages.nixen importsopción. Tu /etc/nixos/configuration.nixse vería así:

{ config, ... }:    
{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
      # Include the package list.
      ./packages.nix
    ];
  # SOME STUFF
  # SOME STUFF
}

Tu /etc/nixos/packages.nixse vería así:

{ pkgs, ... }:
{
  environment.systemPackages = with pkgs; [ emacs gitFull ];
}

¿Cómo funciona? Cuando ejecuta nixos-rebuild switch, el proceso que evalúa las expresiones Nix y decide instalar paquetes, etc., llama configuration.nixcon un conjunto de atributos, algunos de los cuales son configy pkgs.

Se encuentra atributo importsdentro del conjunto devuelto, por lo que evalúa cada expresión Nix en los módulos que importscontiene, con los mismos argumentos ( config, pkgs, etc).

Debe tener pkgscomo argumento (o, técnicamente hablando, un atributo de un conjunto, que en sí mismo es un argumento) de una función packages.nix, porque, desde la perspectiva del lenguaje Nix, el proceso podría o no llamar a la función con el conjunto que contiene pkgs. Si no es así, ¿a qué atributo se referiría al ejecutar with pkgs?

También debe tener puntos suspensivos, porque la función se puede llamar con otros atributos, no solo pkgs.

¿Por qué no es pkgsen configuration.nix? Puede tenerlo, pero si no se refiere a él en ninguna parte del archivo, puede omitirlo con seguridad, ya que los puntos suspensivos los incluirían de todos modos.

Actualizar un atributo llamando a una función externa

Otra forma es simplemente hacer una función que devuelva un conjunto con algún atributo, y el valor de ese atributo que pondría dentro environment.systemPackages. Este es tu 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
}

Su packages.nix:

pkgs: with pkgs; [ emacs gitFull ]

import ./packages.nix pkgssignifica: cargar y devolver la expresión Nix en ./packages.nixy como es una función, llamarla con un argumento pkgs. with pkgs; [ emacs gitFull ]es una expresión con , trae el alcance de la expresión antes del punto y coma a la expresión después del punto y coma. Sin eso, lo sería [ pkgs.emacs pkgs.gitFull ].

Mirzhan Irkegulov
fuente
1
¿Cómo se fusionan las importaciones? ¿Utilizan recursiveUpdate o algo así?
aij
1
¿Hay alguna manera de hacer importaciones condicionales?
CMCDragonkai
1
@CMCDragonkai el valor de importses solo una lista, por lo que puede agregar elementos a eso condicionalmente, por ejemploimports = [ ./foo.nix ./bar.nix ] ++ (if baz then [ ./quux.nix ] else []);
Warbo