lib.genAttrs
lib.genAttrs — функция, которая принимает список имён и функцию-генератор, создавая набор атрибутов, где каждый элемент списка становится ключом, а значение вычисляется функцией-генератором на основе этого ключа.
Инструмент для избежания повторения в конфигурациях NixOS, особенно когда нужно применить похожую конфигурацию к множеству сущностей(службы, пользователи, cпособы взаимодействия(interfaces))
Сигнатура
genAttrs :: [String] -> (String -> Any) -> AttrSet
- первый аргумент — список строк (имена будущих атрибутов);
- второй аргумент — функция, принимающая имя и возвращающая значение для этого атрибута;
Возвращает набор атрибутов { name1 = value1; name2 = value2; ... }
Примеры
Основной
{ lib }:
let
names = [ "foo" "bar" "baz" ];
# Функция-генератор: добавляет "-suffix" к имени
addSuffix = name: "${name}-suffix";
result = lib.genAttrs names addSuffix;
in
result
Результат:
{
foo = "foo-suffix";
bar = "bar-suffix";
baz = "baz-suffix";
}
Создание множества служб
{ config, lib, pkgs, ... }:
let
myServices = [ "nginx" "postgresql" "redis" ];
# Создаём атрибутный набор включённых сервисов
enabledServices = lib.genAttrs myServices (name: {
enable = true;
});
in
{
# Включаем все сервисы одним выражением
services = enabledServices;
# Эквивалентно:
# services.nginx.enable = true;
# services.postgresql.enable = true;
# services.redis.enable = true;
}
Создание пользователей
{ config, lib, ... }:
let
users = [ "alice" "bob" "charlie" ];
# Создаём базовую конфигурацию для каждого пользователя
userConfigs = lib.genAttrs users (name: {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ];
createHome = true;
home = "/home/${name}";
});
in
{
users.users = userConfigs;
}
Настройка пакетов
{ pkgs, lib, ... }:
let
languages = [ "python3" "go" "nodejs" "rustc" ];
# Устанавливаем последние версии языков программирования
devPackages = lib.genAttrs languages (name: pkgs.${name});
in
{
environment.systemPackages = builtins.attrValues devPackages;
# Или с дополнительной конфигурацией:
languages = lib.genAttrs languages (name: {
enable = true;
package = pkgs.${name};
});
}
Генерация конфигурационных файлов
{ config, lib, ... }:
let
domains = [ "example.com" "test.com" "admin.example.com" ];
nginxVhosts = lib.genAttrs domains (domain: {
serverName = domain;
root = "/var/www/${domain}";
locations."/".proxyPass = "http://localhost:8080";
enableSSL = true;
sslCertificate = "/var/ssl/${domain}.crt";
sslCertificateKey = "/var/ssl/${domain}.key";
});
in
{
services.nginx.virtualHosts = nginxVhosts;
}
Продвинутый пример с зависимостью от имени
{ lib, ... }:
let
interfaces = [ "eth0" "eth1" "wlan0" ];
networkConfig = lib.genAttrs interfaces (name:
if lib.hasPrefix "eth" name then {
useDHCP = false;
ipv4.addresses = [{
address = "192.168.1.${toString (10 + lib.elemIndex name interfaces)}";
prefixLength = 24;
}];
} else {
useDHCP = true;
wireless.enable = true;
}
);
in
{
networking.interfaces = networkConfig;
}
Разница с listToAttrs
Часто путают genAttrs с listToAttrs. Вот ключевое отличие:
# genAttrs - проще, когда нужно создать значения на основе имён
lib.genAttrs [ "a" "b" ] (name: "value-${name}")
# => { a = "value-a"; b = "value-b"; }
# listToAttrs - когда у вас уже есть пары {name, value}
lib.listToAttrs [
{ name = "a"; value = 1; }
{ name = "b"; value = 2; }
]
# => { a = 1; b = 2; }
Использование
Комбинирование с другими функциями
lib.genAttrs (lib.filter (s: lib.hasPrefix "dev" s) allNames) (name: ...)
Использование в модулях NixOS
options = lib.genAttrs [ "foo" "bar" ] (name: lib.mkOption {
type = lib.types.str;
default = name;
});
Динамическое создание атрибутов из списка
let
keys = builtins.attrNames someInputSet;
processed = lib.genAttrs keys (key: transformFunction someInputSet.${key});
in
processed
No comments to display
No comments to display