aboutsummaryrefslogtreecommitdiff
path: root/docs/homogenous_modules.md
blob: aa2cbda243d24da860a014ecd0ce03b2d63706ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# Homogenous Nix Modules: Why and How
In the creation of my nixos configuration, I came to a (possibly unique) issue:
many services that I wanted to configure required a "system" piece, and a "home" piece.

For example, in configuring a shell, it makes sense to configure that shell as the default shell for the user in the same place.
However, in standard nixos configuration, you configure the actual shell with home-manager, and the default-ness with nixos.

My solution to this was to create a new way of managing my nixos modules, which I coined "Homogenous Modules."

The idea is as follows: each module contains three parts:
1. a shared `options.nix` file,
2. a nixos part, and
3. a home-manager part (or [Hjem](github.com/feel-co/hjem), in my case).

The `options.nix` file contains _only_ the `options` section of a module.
The nixos part contains the `config` section of the module, as if it was a nixos module.
The home-manager part contains the `config` section of the module, as if it was a home-manager module.

Now, `{imports = [./options.nix ./nixos.nix];}` is a valid nixos module, and
`{imports = [./options.nix ./home.nix];}` is a valid home-manager module.

## Example
Let's implement that shell example from the start, from scratch.
We'll start with with the `options.nix`:
```nix
{lib, ...}: let
  inherit (lib) mkOption mkEnableOption;
in {
  options = {
    collinux.shells = {
      zsh = {
        enable = mkEnableOption "the zsh shell and customizations to it";
        default = mkEnableOption "make zsh the default shell";
      };
      bash = {
        enable = mkEnableOption "the bash shell and customizations to it";
        default = mkEnableOption "make bash the default shell";
      };
    };
  };
  config.assertions = [
    {
      assertion = with collinux.shells; !(zsh.default && bash.default);
      message = "You can only have one default shell!";
    }
  ];
}
```

Here, we define a simple configuration.

In the nixos part, we'll set the default shell:
```nix
{pkgs, config, lib, ...}: let
  cfg = config.collinux.shells;
in {
  users.users."collin".shell =
    if config.zsh.enable
    then pkgs.zsh
    else if config.bash.enable
    then pkgs.bash
    else null;
}
```

And in the home-manager part, we'll set some customization options:
```nix
{pkgs, config, lib, ...}: let
  cfg = config.collinux.shells;

  shellAliases = {
    ll = "ls -l";
    update = "home-manager switch";
  };
in {
  programs.zsh = {
    enable = cfg.zsh.enable;
    syntaxHighlighting.enable = true;
    inherit shellAliases;
  };

  programs.bash = {
    enable = cfg.bash.enable;
    inherit shellAliases;
  };
}
```