Архитектура модуля NixOS
Язык Nix — это функциональный язык программирования. Файлы .nix — это исходный код на языке Nix. Интерпретатор Nix (программа, которая читает эти файлы) понимает только синтаксис этого языка. Если интерпретатор получит файл с другим синтаксисом (например, обычный текст, JSON или bash-скрипт), он не сможет прочитать его как функцию или вычислить из него атрибутный набор (attrset).
В экосистеме Nix строго принято использовать расширение .nix для файлов с кодом. И хотя технически интерпретатор можно заставить прочитать текст с валидным кодом из любого файла, система сборки NixOS и сторонние утилиты ожидают именно файлы .nix. Вы можете использовать файлы с другими расширениями в своей системе, но они не являются модулями NixOS, а являются лишь данными, которые NixOS может прочитать.
Итак, базовое разделение выглядит следующим образом:
.nixфайлы- — это «мозги» (логика, функции, условия), которые понимает NixOS.
- Любые другие файлы
- — это «ресурсы» (текст, данные, конфигурации программ), которые NixOS использует как аргументы для своих функций.
Если вы хотите, чтобы какой-то файл стал полноценным участником конфигурации системы — чтобы к нему можно было обратиться через config… или передать в него pkgs — он обязан быть файлом .nix.
Визуальная схема устройства файла конфигурации NixOS:
# ВЕСЬ ФАЙЛ = МОДУЛЬ # СИГНАТУРА ФУНКЦИИ (Интерфейс. Модуль получает данные для работы.) { config, pkgs, ... } # ОПЕРАТОР (Мост. Двоеточие связывает аргументы с телом.) : # ТЕЛО ФУНКЦИИ (Атрибутный набор. Модуль возвращает данные системе.) { console = { font = "Lat2-Terminus16"; keyMap = "us"; }; }
Файл конфигурации NixOS — это модуль. Он чаще всего представляет собой анонимную функцию, которая возвращает атрибутный набор с настройками системы.
В некоторых случаях модуль может быть и обычным атрибутным набором без входных параметров.
Когда запускается nixos-rebuild switch, система находит конфигурационный файл, исполняет содержащуюся в нём анонимную функцию и получает атрибутный набор, на основе которого собирает итоговые настройки операционной системы.
Структура .nix файла
Рассмотрим структуру .nix файла от самого малого «кирпичика» до целого модуля. Это поможет понять, как данные преобразуются в исполняемую логику.
1. Фундамент: Атрибутный набор (Attrset)
Это базовый тип данных, из которого состоит всё в Nix.
- Что это: Структура данных вида «ключ – значение», похожая на словарь.
- Синтаксис: Всегда в фигурных скобках { }, каждое определение атрибута завершается точкой с запятой ;.
- Пример:
{ name = "nixos"; cores = 8; }. - Свойство: Наборы могут быть вложенными, создавая иерархию (например,
networking.hostName).
2. Механизм: Анонимная функция
Чтобы статичный набор данных стал «умным», его нужно обернуть в функцию.
- Сигнатура (Вход):
{ config, pkgs, ... }— список инструментов, которые вы просите у системы. - Оператор : (Мост): Он говорит: «возьми аргументы слева и примени их к телу справа».
- Тело (Выход): Атрибутный набор с вашими настройками.
- Зачем это нужно: Без функции файл «слеп» — он не видит
pkgs(пакеты) и не знает о настройках в других файлах.
3. Объект: Модуль
Когда вы сохраняете эту анонимную функцию в файл .nix, этот файл становится модулем.
- Роль модуля: Это завершенная единица конфигурации, которую NixOS может прочитать и применить.
- Процесс: При запуске
nixos-rebuild switchсистема вызывает функцию внутри модуля, передает ей реальные данные (pkgs,config) и получает готовый результат.
4. Контекст: Файлы и расширения
.nixфайлы: Это «мозги» системы. Только в них могут быть написаны логика, функции и условия.- Другие файлы (
.txt,.json): Это просто «сырье» или ресурсы. Nix может их прочитать, но не может запустить их как программу. - Универсальность: Эта архитектура едина для NixOS (Linux), nix-darwin (macOS) и WSL (Windows).
Итоговая иерархия в одном блоке:
Модуль (Файл.nix)
└── Анонимная функция
├── Сигнатура (Входные параметры: pkgs, config)
├── Оператор : (Связующее звено)
└── Тело функции
└── Атрибутный набор (Attrset) (Сами настройки: key = value;).
Такое разделение позволяет системе быть динамической: вы не просто пишете список программ, вы создаете функцию, которая формирует вашу систему в зависимости от внешних условий.
- Сигнатура
{ config, pkgs, ... }— это «входные ворота».- Двоеточие
- : — это «мост» между тем, что мы принимаем, и тем, что мы собираем.
- Тело
{ ... }— это сама «полезная нагрузка», то есть набор настроек, которые система применит к ядру ОС.
Всё, что находится до двоеточия, — это параметры, а всё, что после, — это результат (возвращаемое значение функции). Если вашим настройкам требуются внешние параметры (например, пакеты pkgs), их необходимо завернуть в тело функции. В таком случае двоеточие выступает критическим узлом, соединяющим входные данные с итоговым набором конфигурации.
Разбор частей функции
1. Сигнатура функции
Это первая часть файла { config, pkgs, ... }: (заголовок).
- Назначение
- Описывает «интерфейс» модуля — какие данные система должна передать в него при сборке.
- Аргументы
config,pkgs,lib— конкретные переменные, которые вы «запрашиваете» у NixOS.- Эллипсис …
- «Оператор гибкости». Сообщает системе: «Если передашь мне лишние аргументы, которые я не объявил — просто проигнорируй их». Без этого кода возникнет ошибка.
- Оператор :
- Разделитель, который отделяет описание того, что нужно функции (слева), от описания того, что функция делает (справа).
2. Тело функции
Это вторая часть файла { ... } (после двоеточия).
- Назначение
- Основной блок, содержащий логику и параметры настройки.
- Содержимое
- Это атрибутный набор, который является результатом работы функции. Именно этот набор система «вклеивает» в общую конфигурацию вашей операционной системы.
- Структура данных
- Внутри тела находятся пары
ключ = значение;. - Ключи
- Путь к настройке (например,
console). - Значения
- Конкретные параметры (например,
"us"). - Точка с запятой ;
- Обязательный завершитель каждой настройки внутри набора.
