Comment diviser /etc/nixos/configuration.nix en modules séparés?

14

Supposons que j'ai un fichier de configuration NixOS très simple :

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

Je sais que NixOS implémente un système de modules , et un module est un .nixfichier. Chaque .nixfichier doit contenir toute expression Nix valide (par exemple une fonction ou un ensemble). Cela signifie que le fichier de configuration NixOS /etc/nixos/configuration.nixest lui-même un module, contenant une expression Nix.

Je sais également que pour rendre l'expression Nix dans un autre module visible par le module avec lequel je travaille, je peux utiliser une importfonction intégrée .

Je veux diviser la déclaration des packages système (la liste contenant emacset gitFull) dans un fichier packages.nix. Comment diviser le fichier de configuration NixOS en modules séparés?

Mirzhan Irkegulov
la source

Réponses:

22

Expressions Nix

Une expression Nix est comme n'importe quelle expression de langage de programmation: tout ce qui évalue une valeur ou une fonction. Dans ce cas, une valeur peut également être une liste ou un ensemble. Comme un module Nix (fichier avec extension .nix) peut contenir n'importe quelle expression Nix, vous vous attendez à ce que le fichier de configuration NixOS ( /etc/nixos/configuration.nix) contienne une seule expression Nix comme contenu de fichier.

Le fichier de configuration NixOS contient une expression Nix de la forme:

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

Si vous regardez attentivement, vous pouvez voir que c'est une fonction , car les fonctions suivent le formulaire pattern: form. Vous pouvez également voir que c'est une fonction qui accepte un ensemble et renvoie un ensemble. Par exemple, si vous avez une fonction f = {x, y}: {a = x + y;}, vous pouvez l'appeler comme f {x=1; y=2;}et récupérer un ensemble {a=3;}.

Cela signifie donc que lorsque vous appelez nixos-rebuild switch, quelque chose appelle la fonction à l'intérieur du fichier de configuration NixOS avec l'ensemble qui doit contenir les attributs configet pkgs.

importations

Dans l'exemple suivant ./hardware-configuration.nix, la manière simple d'extraire la liste des packages dans un module séparé packages.nixconsiste simplement à extraire l' environment.systemPackagesoption et à la mettre ./packages.nixen importsoption. Votre /etc/nixos/configuration.nixressemblerait à:

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

Votre /etc/nixos/packages.nixressemblerait à:

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

Comment ça marche? Lorsque vous exécutez nixos-rebuild switch, le processus qui évalue les expressions Nix et décide d'installer des packages et ainsi de suite appelle configuration.nixavec un ensemble d'attributs, dont certains sont configet pkgs.

Elle trouve attribut à l' importsintérieur de l'ensemble de retour, de sorte qu'il évalue chaque expression Nix dans les modules qui importscontient les mêmes arguments ( config, pkgs, etc.).

Vous devez avoir pkgscomme argument (ou, techniquement parlant, un attribut d'un ensemble, qui est lui-même un argument) d'une fonction dans packages.nix, car, du point de vue du langage Nix, le processus peut ou non appeler la fonction avec l'ensemble qui contient pkgs. Si ce n'est pas le cas, à quel attribut feriez-vous référence lors de l'exécution with pkgs?

Vous devez également avoir des points de suspension, car la fonction peut être appelée avec d'autres attributs, pas seulement pkgs.

Pourquoi n'y pkgsen a- configuration.nixt- il pas ? Vous pouvez l'avoir, mais si vous n'y faites référence nulle part dans le fichier, vous pouvez l'omettre en toute sécurité, car les points de suspension les incluraient de toute façon.

Mise à jour d'un attribut en appelant une fonction externe

Une autre façon consiste simplement à créer une fonction qui renvoie un ensemble avec un attribut et la valeur de cet attribut que vous mettriez à l'intérieur environment.systemPackages. Voici votre 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
}

Votre packages.nix:

pkgs: with pkgs; [ emacs gitFull ]

import ./packages.nix pkgssignifie: charger et renvoyer l'expression Nix dans ./packages.nixet comme c'est une fonction, l'appeler avec un argument pkgs. with pkgs; [ emacs gitFull ]est une with-expression , elle apporte la portée de l'expression avant le point-virgule à l'expression après le point-virgule. Sans elle, ce serait [ pkgs.emacs pkgs.gitFull ].

Mirzhan Irkegulov
la source
1
Comment les importations sont-elles fusionnées? Utilisent-ils recursiveUpdate ou quelque chose comme ça?
aij
1
Existe-t-il un moyen d'effectuer des importations conditionnelles?
CMCDragonkai
1
@CMCDragonkai dont la valeur importsn'est qu'une liste, vous pouvez donc y ajouter des éléments de manière conditionnelle, par exempleimports = [ ./foo.nix ./bar.nix ] ++ (if baz then [ ./quux.nix ] else []);
Warbo