ryota2357

Nix Home Manager をファイル配置ツールとして使用する

投稿日:

tag icon svg Nix

この記事は ryota2357 Advent Calendar 2024 の 4 日目の記事です。

今年の 8 月 2 日から nix をパッケージマネージャとして使い始め、10 月 3 日、Home Manager と nix-darwin を使い始めた。

Home Manager の設定をしている人の記事を見ると、programs.bashprograms.tmux のようなアトリビュートに設定を記述しているものを多く見かける。 しかし僕はこれら programs.<name> を使用せず、タイトルの通り、僕は Home Manager を config ファイルを配置するツールとしてのみ使用している。 この運用の理由と方法について書いていく。

program.<name> = { ... } の形式について

この形式は <name> で指定したツール・ソフトウェアを Nix で宣言的に書くというもので、例えば:

programs.git = {
  enable = true;
  userName = "ryota2357";
  extraConfig = {
    ...
  };
  ...
};

のような感じで色々設定できる。だが僕はこれがあまり好きではない。

この方式は、ツール間で共通した記法 (Nix 式) で宣言的に記述できるという利点がある。 しかし、Home Manager が Nix 式に基づいて「いい感じ」に各ツールの設定ファイルを生成しているので、実際に各ツールが読み込む設定は (実際に生成されたファイルを見ない限り) 直接確認できないという欠点がある。

各ツールが実際に読み込むファイルを直接確認できず、Home Manager が「いい感じに」生成するために、実際に次のような問題が issue に上がったりしている。

issue タイトルの通り、Home Manager のバグであるのだが、このように各ツールのバグではなく Home Manager のバグや「いい感じ」が生み出す問題に付き合っていく必要が出てくる。

個人的な意見を加えるならば、僕は「いい感じ」というのを「設定をする」という場面において信用していない。設定の「いい感じ」は人によって大きく異なると思っているからだ。

そこで、僕は Home Mangaer を xdg.configFile, home.packages, home.file のみを使用して、各ツールの設定は各ツールの設定ファイルをちゃんと書くという方針で利用している。

ファイル配置

先に書いた通り、Home Manager には xdg.configFile, home.file というアトリビュートが存在する。 このアトリビュートは programs.<name> の内部でも使用されていて、それぞれ単純にユーザールート以下にファイルを配置するだけである。ドキュメントを次に引用する。

xdg.configFile
    Attribute set of files to link into the user’s XDG configuration home.
    Type: attribute set of (submodule)
    Default: { }

home.file
    Attribute set of files to link into the user home.
    Type: attribute set of (submodule)
    Default: { }

また、home.packagesprograms.<name> 内部で使用されていて:

home.packages
    The set of packages to appear in the user environment.
    Type: list of package
    Default: [ ]

というものである。

なお、各 programs.<name> がどのような実装になっているかは、modules/programs/ ディレクトリで確認できる。

この 3 つのアトリビュートを使用して、僕は次のような感じで設定を書いている。例としてシェル周りの設定を次のように書いている。

# nix/home/modules/shell.nix
{ pkgs, ... }:
let
  s = name: { source = ../../../shell + "/${name}"; };
in
{
  home.packages = with pkgs; [
    bash
    # zsh   # システムのを使う
    fish
  ];
  home.file = {
    ".zshenv" = s "zsh/zshenv";
    ".zshrc" = s "zsh/zshrc";
  };
  xdg.configFile = builtins.foldl' (acc: name: acc // { ${name} = s name; }) { } [
    "zsh/alias.zsh"
    "zsh/completion.zsh"
    "zsh/option.zsh"
    "zsh/prompt.zsh"

    "fish/config.fish"
    "fish/conf.d"
    "fish/completions"
    "fish/functions"
    "fish/prompt.fish"
    "fish/shortcut.fish"
  ];
}

そして、これを次のように home-mamager.lib.homeManagerConfiguration.modules に与えている。

# nix/home/default.nix
home-manager.lib.homeManagerConfiguration {
  modules = [
    ./modules/shell.nix
    ...
  ];
  ...
}

home-mamager.lib.homeManagerConfiguration.modules を使うことで、簡単にアトリビュートセットを deep marge できる。

終わりに

このように programs.<name> を使わない Home Manager の使い方もある。 そのほか僕の dotfiles の Nix の設定の全体像については、ryota2357/dotfiles を確認してもらいたい。