I have a generic NixOS setup as a flake in a public repository. I want to use that as a basis for other, more personalized NixOS setups, flakes in other repositories that inherit from the generic setup. I’m struggling a bit to get the last bits of the inheritance to work.
Generic Setup aka “parent”
The flake for the generic setup looks like this: (GitLab repo)
{
description = "Multi-host operating system configuration with NixOS";
inputs = {
nixos-hardware.url = "github:NixOS/nixos-hardware?ref=master";
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
};
outputs = { nixpkgs, ... } @attrs:
let
commonModules = name: [
./hosts/${name}
./software
./system
./users
];
mkSystem = name: cfg: nixpkgs.lib.nixosSystem {
system = cfg.system or "x86_64-linux";
modules = (commonModules name) ++ (cfg.modules or [ ]);
specialArgs = attrs;
};
hostEntries = builtins.attrNames (builtins.readDir ./hosts);
systems = builtins.listToAttrs (map (name: { inherit name; value = { }; }) hostEntries);
in
{
nixosConfigurations = nixpkgs.lib.mapAttrs mkSystem systems;
};
}
The idea is that you define hosts as directories in the hosts/
folder. A “generic” host definition serves for the “inheritance”, later.
Customized Setup aka “child”
The flake implementing the customized NixOS setup is almost identical, only that it has the generic setup, “painless”, as an input in addition. (Copier template)
{
description = "Multi-host operating system configuration with NixOS";
inputs = {
nixos-hardware.url = "github:NixOS/nixos-hardware?ref=master";
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
painless.url = "gitlab:painless-software/nixos-config?ref=main";
};
outputs = { nixpkgs, painless, ... } @attrs:
let
commonModules = name: [
./hosts/${name}
./software
./system
./users
];
mkSystem = name: cfg: nixpkgs.lib.nixosSystem {
system = cfg.system or "x86_64-linux";
modules = (commonModules name) ++ (cfg.modules or [ ]) ++ painless.nixosConfigurations.generic.modules;
specialArgs = attrs;
};
hostEntries = builtins.attrNames (builtins.readDir ./hosts);
systems = builtins.listToAttrs (map (name: { inherit name; value = { }; }) hostEntries);
in
{
nixosConfigurations = nixpkgs.lib.mapAttrs mkSystem systems;
};
}
What I try to do is to concatenate the modules
of the generic setup with the modules of the local setup. Unfortunately, this doesn’t work as expected. nix flake check
errors out (complete log).
Error: attribute ‘modules’ missing
$ nix flake check
evaluating flake...
checking flake output 'nixosConfigurations'...
...
error:
… while checking flake output 'nixosConfigurations'
at /nix/store/vbp66ij6whnibdhldm5mpg5f3bvlykzd-source/flake.nix:29:7:
28| {
29| nixosConfigurations = nixpkgs.lib.mapAttrs mkSystem systems;
| ^
30| };
… while checking the NixOS configuration 'nixosConfigurations.example'
… while calling the 'seq' builtin
at /nix/store/22r7q7s9552gn1vpjigkbhfgcvhsrz68-source/lib/modules.nix:334:18:
333| options = checked options;
334| config = checked (removeAttrs config [ "_module" ]);
| ^
335| _module = checked (config._module);
(stack trace truncated; use '--show-trace' to show the full, detailed trace)
error: attribute 'modules' missing
at /nix/store/vbp66ij6whnibdhldm5mpg5f3bvlykzd-source/flake.nix:21:67:
20| system = cfg.system or "x86_64-linux";
21| modules = (commonModules name) ++ (cfg.modules or [ ]) ++ painless.nixosConfigurations.generic.modules;
| ^
22| specialArgs = attrs;
Did you mean _module?
How can I get that working? Or is the approach wrong?