Как разделить /etc/nixos/configuration.nix на отдельные модули?


14

Предположим, у меня есть очень простой файл конфигурации NixOS :

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

Я знаю, что NixOS реализует систему модулей , а модуль - это .nixфайл. Каждый .nixфайл должен содержать любое допустимое выражение Nix (например, функцию или набор). Это означает, что файл конфигурации NixOS /etc/nixos/configuration.nixсам по себе является модулем, содержащим выражение Nix.

Я также знаю, что для того, чтобы сделать выражение Nix в другом модуле видимым для модуля, с которым я работаю, я могу использовать встроенную importфункцию .

Я хочу разбить объявление системных пакетов (список, содержащий emacsи gitFull) в файл packages.nix. Как разделить файл конфигурации NixOS на отдельные модули?

Ответы:


22

Никс выражения

Выражение Nix , как любое выражение языка программирования: все , что имеет значение значения или функции. Значением в этом случае также может быть список или набор. Поскольку модуль Nix (файл с расширением .nix) может содержать любое выражение Nix, можно ожидать, что файл конфигурации NixOS ( /etc/nixos/configuration.nix) будет содержать одно выражение Nix в качестве содержимого файла.

Файл конфигурации NixOS содержит выражение Nix в форме:

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

Если вы посмотрите внимательно, вы увидите, что это функция , потому что функции следуют за формой pattern: form. Вы также можете увидеть, что это функция, которая принимает набор и возвращает набор. Например, если у вас есть функция f = {x, y}: {a = x + y;}, вы можете вызвать ее как f {x=1; y=2;}и вернуть набор {a=3;}.

Это означает, что когда вы вызываете nixos-rebuild switch, что-то вызывает функцию внутри файла конфигурации NixOS с набором, который должен содержать атрибуты configи pkgs.

импорт

Следуя примеру ./hardware-configuration.nix, простой способ извлечь список пакетов в отдельный модуль packages.nixпросто разорвать environment.systemPackagesвариант и положить ./packages.nixв importsопции. Ваш /etc/nixos/configuration.nixбудет выглядеть так:

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

Ваш /etc/nixos/packages.nixбудет выглядеть так:

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

Как это работает? При запуске nixos-rebuild switchпроцесс, который оценивает выражения Nix и решает установить пакеты и т. Д., Вызывает configuration.nixс набором атрибутов, некоторые из которых являются configи pkgs.

Он находит атрибут importsв возвращаемом наборе, поэтому он оценивает каждое выражение Nix в модулях, importsсодержащих одинаковые аргументы ( config, pkgsи т. Д.).

Вы должны иметь pkgsв качестве аргумента (или, технически говоря, атрибут набора, который сам является аргументом) функции packages.nix, потому что с точки зрения языка Nix процесс может вызывать или не вызывать функцию с набором, который содержит pkgs. Если это не так, на какой атрибут вы бы ссылались при запуске with pkgs?

Вы также должны иметь многоточие, потому что функция может быть вызвана с другими атрибутами, а не только pkgs.

Почему не pkgsв configuration.nix? Вы можете иметь это, но если вы не обращаетесь к нему где-либо в файле, вы можете спокойно его пропустить, поскольку многоточие будет включать их в любом случае.

Обновление атрибута путем вызова внешней функции

Другой способ - просто создать функцию, которая возвращает набор с некоторым атрибутом и значением этого атрибута, которое вы бы поместили внутрь environment.systemPackages. Это ваше 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
}

Ваш packages.nix:

pkgs: with pkgs; [ emacs gitFull ]

import ./packages.nix pkgsозначает: загрузить и вернуть выражение Nix, ./packages.nixи, поскольку оно является функцией, вызвать его с аргументом pkgs. with pkgs; [ emacs gitFull ]является выражением with , оно переносит область выражения перед точкой с запятой в выражение после точки с запятой. Без этого было бы [ pkgs.emacs pkgs.gitFull ].


1
Как объединяется импорт? Они используют recursiveUpdate или что-то подобное?
ау

1
Есть ли способ сделать условный импорт?
CMCDragonkai

1
@CMCDragonkai значение imports- это просто список, так что вы можете добавлять к нему элементы условно, например,imports = [ ./foo.nix ./bar.nix ] ++ (if baz then [ ./quux.nix ] else []);
Warbo
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.