Bagaimana cara membagi /etc/nixos/configuration.nix menjadi modul-modul terpisah?

14

Misalkan saya memiliki file konfigurasi NixOS yang sangat sederhana :

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

Saya tahu bahwa NixOS mengimplementasikan sistem modul , dan modul adalah .nixfile. Setiap .nixfile harus mengandung ekspresi Nix yang valid (misalnya fungsi atau set). Ini berarti bahwa file konfigurasi NixOS /etc/nixos/configuration.nixitu sendiri adalah modul, berisi ekspresi Nix.

Saya juga tahu bahwa untuk membuat ekspresi Nix dalam modul lain terlihat oleh modul yang saya kerjakan, saya dapat menggunakan importfungsi bawaan .

Saya ingin membagi deklarasi paket sistem (daftar yang berisi emacsdan gitFull) menjadi file packages.nix. Bagaimana cara membagi file konfigurasi NixOS menjadi modul terpisah?

Mirzhan Irkegulov
sumber

Jawaban:

22

Ekspresi Nix

Sebuah ekspresi Nix adalah seperti ekspresi bahasa pemrograman: apapun yang mengevaluasi ke nilai atau fungsi. Nilai dalam hal ini juga bisa berupa daftar atau set. Karena modul Nix (file dengan ekstensi .nix) dapat berisi ekspresi Nix apa pun, Anda akan mengharapkan file konfigurasi NixOS ( /etc/nixos/configuration.nix) mengandung satu ekspresi Nix sebagai isi file.

File konfigurasi NixOS berisi ekspresi Nix dari formulir:

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

Jika Anda melihat lebih dekat, Anda dapat melihatnya sebagai fungsi , karena fungsi mengikuti formulir pattern: form. Anda juga dapat melihat itu adalah fungsi yang menerima set dan mengembalikan set. Misalnya, jika Anda memiliki fungsi f = {x, y}: {a = x + y;}, maka Anda dapat memanggilnya f {x=1; y=2;}dan mendapatkan kembali satu set {a=3;}.

Jadi itu berarti bahwa ketika Anda menelepon nixos-rebuild switch, sesuatu memanggil fungsi di dalam file konfigurasi NixOS dengan set yang harus mengandung atribut configdan pkgs.

impor

Contoh berikut ./hardware-configuration.nix, cara sederhana untuk mengekstrak daftar paket ke modul terpisah packages.nixadalah dengan mencabut environment.systemPackagesopsi dan memasukkannya ./packages.nixke dalam importsopsi. Anda /etc/nixos/configuration.nixakan terlihat seperti:

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

Anda /etc/nixos/packages.nixakan terlihat seperti:

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

Bagaimana cara kerjanya? Ketika Anda menjalankan nixos-rebuild switch, proses yang mengevaluasi ekspresi Nix dan memutuskan untuk menginstal paket dan sebagainya panggilan configuration.nixdengan seperangkat atribut, beberapa di antaranya adalah configdan pkgs.

Ia menemukan atribut importsdalam set kembali, sehingga mengevaluasi setiap ekspresi Nix dalam modul yang importsberisi dengan argumen yang sama ( config, pkgs, dll).

Anda harus memiliki pkgssebagai argumen (atau, secara teknis, atribut dari himpunan, yang dengan sendirinya merupakan argumen) dari suatu fungsi dalam packages.nix, karena, dari perspektif bahasa Nix, proses tersebut mungkin atau mungkin tidak memanggil fungsi dengan himpunan yang berisi pkgs. Jika tidak, atribut apa yang akan Anda rujuk, saat berjalan with pkgs?

Anda juga harus memiliki ellipsis, karena fungsinya mungkin dipanggil dengan atribut lain, bukan hanya pkgs.

Kenapa tidak ada pkgsdi sana configuration.nix? Anda dapat memilikinya, tetapi jika Anda tidak merujuknya di mana pun dalam file, Anda dapat dengan aman menghilangkannya, karena ellipsis akan memasukkannya.

Memperbarui atribut dengan memanggil fungsi eksternal

Cara lain adalah dengan membuat fungsi yang mengembalikan set dengan beberapa atribut, dan nilai atribut yang akan Anda masukkan ke dalamnya environment.systemPackages. Ini milikmu 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
}

Anda packages.nix:

pkgs: with pkgs; [ emacs gitFull ]

import ./packages.nix pkgsberarti: memuat dan mengembalikan ekspresi Nix ke dalam ./packages.nixdan karena itu adalah fungsi, sebut saja dengan argumen pkgs. with pkgs; [ emacs gitFull ]adalah dengan-ekspresi , ini membawa ruang lingkup ekspresi sebelum titik koma ke ekspresi setelah titik koma. Tanpa itu, itu akan menjadi [ pkgs.emacs pkgs.gitFull ].

Mirzhan Irkegulov
sumber
1
Bagaimana cara impor digabung? Apakah mereka menggunakan pembaruan rekursif atau sesuatu seperti itu?
aij
1
Apakah ada cara untuk melakukan impor bersyarat?
CMCDragonkai
1
@CMCDragonkai nilai importshanyalah sebuah daftar, sehingga Anda dapat menambahkan elemen ke kondisi tersebut, misalnyaimports = [ ./foo.nix ./bar.nix ] ++ (if baz then [ ./quux.nix ] else []);
Warbo