Jak podzielić /etc/nixos/configuration.nix na osobne moduły?


14

Załóżmy, że mam bardzo prosty plik konfiguracyjny NixOS :

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

Wiem, że NixOS implementuje system modułów , a moduł jest .nixplikiem. Każdy .nixplik powinien zawierać dowolne prawidłowe wyrażenie Nix (np. Funkcję lub zestaw). Oznacza to, że sam plik konfiguracyjny NixOS /etc/nixos/configuration.nixjest modułem zawierającym wyrażenie Nix.

Wiem również, że aby wyrażenie Nix w innym module było widoczne dla modułu, z którym pracuję, mogę użyć wbudowanej importfunkcji .

Chcę podzielić deklarację pakietów systemowych (listę zawierającą emacsi gitFull) na plik packages.nix. Jak podzielić plik konfiguracyjny NixOS na osobne moduły?

Odpowiedzi:


22

Wyrażenia Nix

Wyrażenie Nix jest jak każdy ekspresji języka programowania: wszystko, co ma wartość wartości lub funkcji. Wartość w tym przypadku może być również listą lub zestawem. Ponieważ moduł Nix (plik z rozszerzeniem .nix) może zawierać dowolne wyrażenie Nix, można oczekiwać, że plik konfiguracyjny NixOS ( /etc/nixos/configuration.nix) będzie zawierał pojedyncze wyrażenie Nix jako jego zawartość.

Plik konfiguracyjny NixOS zawiera wyrażenie Nix w postaci:

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

Jeśli przyjrzysz się uważnie, zobaczysz, że jest to funkcja , ponieważ funkcje są zgodne z formą pattern: form. Możesz także zobaczyć, że jest to funkcja, która akceptuje zestaw i zwraca zestaw. Na przykład, jeśli masz funkcję f = {x, y}: {a = x + y;}, możesz ją wywołać jako f {x=1; y=2;}i odzyskać zestaw {a=3;}.

Oznacza to, że kiedy wywołujesz nixos-rebuild switch, coś wywołuje funkcję w pliku konfiguracyjnym NixOS z zestawem, który musi zawierać atrybuty configi pkgs.

import

Zgodnie z przykładem ./hardware-configuration.nixprostego sposobu na wyodrębnienie listy pakietów do oddzielnego modułu packages.nixjest po prostu zgrywanie environment.systemPackagesopcji i umieszczenie jej ./packages.nixw importsopcji. Twój /etc/nixos/configuration.nixwyglądałby jak:

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

Twój /etc/nixos/packages.nixwyglądałby jak:

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

Jak to działa? Po uruchomieniu nixos-rebuild switchproces, który ocenia wyrażenia Nix i decyduje się zainstalować pakiety i tak dalej wywołania configuration.nixz zestawem atrybutów, z których niektóre to configi pkgs.

Stwierdzi atrybut importswewnątrz zwróconego zestawu, tak ocenia każde wyrażenie Nix w modułach, które importszawiera z tymi samymi argumentami ( config, pkgsitp).

Musisz mieć pkgsjako argument (lub, technicznie rzecz biorąc, atrybut zestawu, który sam jest argumentem) funkcji w packages.nix, ponieważ z perspektywy języka Nix proces może lub nie może wywoływać funkcję z zestawem, który zawiera pkgs. Jeśli tak się nie stanie, do jakiego atrybutu odnosiłbyś się podczas uruchamiania with pkgs?

Musisz również mieć wielokropek, ponieważ funkcja może być wywoływana z innymi atrybutami, nie tylko pkgs.

Dlaczego nie ma pkgsw configuration.nix? Możesz go mieć, ale jeśli nie odwołujesz się do niego nigdzie w pliku, możesz go bezpiecznie pominąć, ponieważ elipsa i tak je uwzględni.

Aktualizowanie atrybutu przez wywołanie funkcji zewnętrznej

Innym sposobem jest po prostu utworzenie funkcji, która zwraca zestaw z jakimś atrybutem i wartością tego atrybutu, który byś w nim wstawił environment.systemPackages. To jest twój 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
}

Twój packages.nix:

pkgs: with pkgs; [ emacs gitFull ]

import ./packages.nix pkgsoznacza: załaduj i zwróć wyrażenie Nix, ./packages.nixa ponieważ jest to funkcja, wywołaj ją z argumentem pkgs. with pkgs; [ emacs gitFull ]jest wyrażeniem z , przenosi zakres wyrażenia przed średnikiem do wyrażenia po średniku. Bez tego byłoby [ pkgs.emacs pkgs.gitFull ].


1
Jak scalane są importy? Czy używają recursiveUpdate czy czegoś podobnego?
aij

1
Czy istnieje sposób na import warunkowy?
CMCDragonkai,

1
@CMCDragonkai wartość importsjest tylko listą, więc możesz warunkowo dołączyć do niej elementy, np.imports = [ ./foo.nix ./bar.nix ] ++ (if baz then [ ./quux.nix ] else []);
Warbo
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.