Wie teile ich /etc/nixos/configuration.nix in separate Module auf?

14

Angenommen, ich habe eine sehr einfache NixOS-Konfigurationsdatei :

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

Ich weiß, dass NixOS ein Modulsystem implementiert und ein Modul eine .nixDatei ist. Jede .nixDatei sollte einen gültigen Nix-Ausdruck enthalten (zB eine Funktion oder eine Menge). Dies bedeutet, dass die NixOS-Konfigurationsdatei /etc/nixos/configuration.nixselbst ein Modul ist, das einen Nix-Ausdruck enthält.

Ich weiß auch, dass ich eine integrierte importFunktion verwenden kann, um den Nix-Ausdruck in einem anderen Modul für das Modul, mit dem ich arbeite, sichtbar zu machen .

Ich möchte die Deklaration von Systempaketen (die Liste mit emacsund gitFull) in Dateien aufteilen packages.nix. Wie teile ich die NixOS-Konfigurationsdatei in separate Module auf?

Mirzhan Irkegulov
quelle

Antworten:

22

Nix Ausdrücke

Ein Nix-Ausdruck ist wie jeder Ausdruck in einer Programmiersprache: alles, was zu einem Wert oder einer Funktion ausgewertet wird. Ein Wert kann in diesem Fall auch eine Liste oder eine Menge sein. Als Nix-Modul (Datei mit Endung.nix ) einen beliebigen Nix-Ausdruck enthalten kann, ist zu erwarten, dass die NixOS-Konfigurationsdatei ( /etc/nixos/configuration.nix) einen einzelnen Nix-Ausdruck als Dateiinhalt enthält.

Die NixOS-Konfigurationsdatei enthält einen Nix-Ausdruck der Form:

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

Wenn Sie genau hinschauen, können Sie sehen, dass es sich um eine Funktion handelt , da Funktionen der Form folgen pattern: form. Sie können auch sehen, dass es sich um eine Funktion handelt, die eine Menge akzeptiert und eine Menge zurückgibt. Wenn Sie beispielsweise eine Funktion haben f = {x, y}: {a = x + y;}, können Sie sie als aufrufenf {x=1; y=2;} und ein Set zurückerhalten {a=3;}.

Das bedeutet, dass beim nixos-rebuild switchAufrufen die Funktion in der NixOS-Konfigurationsdatei mit der Menge aufgerufen wird, die Attribute configund enthalten muss pkgs.

Importe

Das folgende Beispiel zeigt ./hardware-configuration.nix, wie Sie die Liste der Pakete auf einfache Weise in ein separates Modul extrahieren können packages.nix, indem Sie die environment.systemPackagesOption rippen und ./packages.nixin die importsOption einfügen. Ihr /etc/nixos/configuration.nixwürde so aussehen:

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

Ihr /etc/nixos/packages.nixwürde so aussehen:

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

Wie funktioniert das? Bei der Ausführung nixos-rebuild switchwird der Prozess, der Nix-Ausdrücke auswertet und entscheidet, Pakete usw. zu installieren, configuration.nixmit einer Reihe von Attributen aufgerufen, von denen einige Attribute sindconfig und pkgs.

Es findet Attribut importsinnerhalb des zurückgegebenen Satzes, so dass es jeden Nichts Ausdrucks in den Modulen auswertet , die importsmit den gleichen Argumenten enthalten ( config, pkgsusw.).

Sie müssen pkgsein Argument (oder, technisch gesehen, ein Attribut einer Menge, das selbst ein Argument ist) einer Funktion in sich haben packages.nix, da der Prozess aus Sicht der Nix-Sprache die Funktion mit der Menge möglicherweise so aufruft oder nicht enthält pkgs. Wenn nicht, auf welches Attribut würden Sie sich bei der Ausführung beziehen with pkgs?

Sie müssen auch Auslassungszeichen haben, da die Funktion möglicherweise nicht nur mit anderen Attributen aufgerufen wird pkgs.

Warum gibt es pkgsin configuration.nix? Sie können es haben, aber wenn Sie sich in der Datei nicht darauf beziehen, können Sie es sicher weglassen, da die Auslassungspunkte sie sowieso einschließen würden.

Aktualisieren eines Attributs durch Aufrufen einer externen Funktion

Eine andere Möglichkeit besteht darin, eine Funktion zu erstellen, die eine Menge mit einem bestimmten Attribut und dem Wert dieses Attributs zurückgibt, den Sie eingeben würden environment.systemPackages. Das ist dein 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
}

Ihr packages.nix:

pkgs: with pkgs; [ emacs gitFull ]

import ./packages.nix pkgsbedeutet: Lade und gib den Nix-Ausdruck in ./packages.nixund rufe ihn mit einem Argument auf, da es sich um eine Funktion handelt pkgs. with pkgs; [ emacs gitFull ]Wenn es sich um einen With-Ausdruck handelt , wird der Gültigkeitsbereich des Ausdrucks vor dem Semikolon auf den Ausdruck nach dem Semikolon gesetzt. Ohne es wäre es [ pkgs.emacs pkgs.gitFull ].

Mirzhan Irkegulov
quelle
1
Wie werden Importe zusammengeführt? Verwenden sie recursiveUpdate oder ähnliches?
17.
1
Gibt es eine Möglichkeit, bedingte Importe durchzuführen?
CMCDragonkai
1
@CMCDragonkai der Wert von importsist nur eine Liste, so dass Sie Elemente an die Bedingung anhängen können, z. B.imports = [ ./foo.nix ./bar.nix ] ++ (if baz then [ ./quux.nix ] else []);
Warbo