Featured image of post home-managerをNix flakesで書き直してdotfiles管理をいい感じにする

home-managerをNix flakesで書き直してdotfiles管理をいい感じにする

もともとNixpkgsとhome-managerを利用してシェル環境や開発環境を管理していたのですが、昨年末に重い腰を上げてnix flakeに移行しました。

あけましておめでとうございます。 2023年気持ちも新たに、まずはdotfilesの見直しから開始しました。\nこれまでは、Emacs以外の fish や git などのconfigはpCloud経由で管理し、シンボリックリンク経由で利用していました。 またWSL環境やPC/Mac環境の再構築をする中で、config以外の exa や fzf といった普段利用しているパッケージのインストールも毎回必要なため、 homebrewやlinuxbrewを含めたインストール手順を実行していました。\n
Nixとhome-managerにdotfiles管理を移行する

nix flakeとは

Nixパッケージマネージャの実験的機能で、より再現性のある構成管理と依存関係の宣言を可能にする仕組みです。 2021年11月にNix 2.4でリリースされた比較的新しい機能で、2025年1月現在も experimental という扱いになっています。

Nixシステムは純粋関数のコンセプトを持っているので、インプットが変化しなければ同じアプトプットを得られるのがメリットです。

flakeを用いない従来のNixパッケージマネージャでは、基本的に channel にソースを設定し、システム全体で同じソースを利用していました。 このため、例えばhome-managerでも、プロジェクト毎に用意したshell.nixでも同じパッケージソースを参照していました。

nix flakeでは flake.nix というファイル単位でインプットとアウトプットを定義することができ、 更にインプットについては実行時のrevisionを flake.lock ファイルで固定することもできるようになっています。

他にもコマンド体系が変更されているなど違いが色々あるようですが、詳しくは以下の公式情報を参照してください。

Flakes - NixOS Wiki

セットアップ

NixOSとそれ以外でセットアップ方法が異なりますが、ここではNixOSではないLinux Distroでの方法を紹介します。 具体的にはWSL Ubuntu 24.05を利用します。詳細な手順は公式のHome Manager Manualにありますので、こちらを参照してください。

最新のNixをインストールしてあることを前提にします。

まず ~/.config/nix/nix.conf に以下を記述しflakesを有効化します。

experimental-features = nix-command flakes

次に以下のコマンドで ~/.config/home-manager/ 以下にhome.nixとflake.nixを生成します。

1
nix run home-manager/master -- init

今回は、home.nixを書き換えるので --switch オプションを付けずに実行しています。 --switch オプションを付与するとhome-managerのセットアップをそのまま有効化できます。

もし既存のhome.nixとflake.nixがあれば、それらを ~/.config/home-manager 以下に配置してから --switch オプション付きでコマンドを実行すれば設定の適用が可能です。

なお、flakesは上記のNixOS Wikiにあるようにgit repository内で利用する場合は git add しておく必要があるので注意が必要です。

For flakes in git repos, only files in the working tree will be copied to the store. Therefore, if you use git for your flake, ensure to git add any project files after you first create them.

home-managerのconfigを書く

私のflake.nixファイルは以下のようになりました。

 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
{
  description = "Home Manager configuration of tomoyukim";

  inputs = {
    # Specify the source of Home Manager and Nixpkgs.
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    nixgl.url = "github:nix-community/nixGL";
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    emacs-overlay = {
      url = "github:nix-community/emacs-overlay/087cf45264b4487b2848e08548bb4c5f933d460c"; # 2024/07/30
      inputs.nixpkgs.follows = "nixpkgs";
    };
    dracula-tmux = {
      url = "github:dracula/tmux/5eb04b9db918bdfbf6928fc3b59942efb7de6e54";
      flake = false;
    };
  };

  outputs = { ... }@inputs:
    let
      system = "x86_64-linux";
      username = "tomoyukim";
      pkgs = import inputs.nixpkgs {
        inherit system;
        config.allowUnfree = true;
        overlays = [
          inputs.emacs-overlay.overlay
        ];
      };
      nixgl = inputs.nixgl;
    in {
      homeConfigurations."${username}" = inputs.home-manager.lib.homeManagerConfiguration {
        pkgs = pkgs.extend (final: prev: {
          tmuxPlugins = prev.tmuxPlugins // {
            dracula = prev.tmuxPlugins.dracula.overrideAttrs (oldAttrs: {
              version = "3.0.0";
              src = inputs.dracula-tmux;
            });
          };
        });

        extraSpecialArgs = {
          inherit username;
          inherit nixgl;
        };

        # Specify your home configuration modules here, for example,
        # the path to your home.nix.
        modules = [ ./home.nix ];

        # Optionally use extraSpecialArgs
        # to pass through arguments to home.nix
      };
    };
}

home.nixは別ファイルとして管理しており、再利用できるようにしてあります。

また、いくつか個人的に加えていた変更もflake.nixに集約してすっきり管理できるようになりました。

emacs-overlay

emacsは適当なversionをビルドして使っているため、home-managerではemacs-overlayを使っていました。

Bleeding edge emacs overlay [maintainer=@adisbladis] - GitHub - nix-community/emacs-overlay: Bleeding edge emacs overlay [maintainer=@adisbladis]
GitHub - nix-community/emacs-overlay: Bleeding edge emacs overlay [maintainer=@adisbladis]

emacs-overlayは取り回しのためにhome.nixに直接overlayのコードを記述していました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{ config, lib, pkgs, ... }:
with lib;
rec {
  nixpkgs.overlays = [
    (import (builtins.fetchGit {
      url = "https://github.com/nix-community/emacs-overlay.git";
      ref = "master";
      rev = "087cf45264b4487b2848e08548bb4c5f933d460c"; # 2024/07/30
    }))
  ];

  home = {
    ...
  };
  ...
}

nix flakesではoverlayをhome.nixではなくflake.nixに記述でき、インプットとアウトプットでソースの取得とoverlayの適用を分けて書けるので読みやすくなりました。

なお、urlには github:nix-community/emacs-overlay/087cf45264b4487b2848e08548bb4c5f933d460c のようにgitのhashを指定することでrevisionを固定することもできます。

dracula/tmuxを固有revisionで利用する

私はターミナルマルチプレクサとしてtmuxを利用しており、emacs諸々と共通にしておくと都合がよいのでテーマをdraculaで統一しています。

🧛🏻‍♂️ Dark theme for tmux. Contribute to dracula/tmux development by creating an account on GitHub.
GitHub - dracula/tmux: 🧛🏻‍♂️ Dark theme for tmux

nixpkgsで配布されているdracula pluginはversionが2.x系で古いままになっており、最新で利用できる機能(天気表示とか)を利用したかったのでoverrideしています。

flakes以前はdelivationを作って ~/.config/nixpkgs/config.nix で取り込んでいたのですが、こちらもflake.nixにすっきりと書くことができるようになりました。

1
2
3
4
dracula-tmux = {
  url = "github:dracula/tmux/5eb04b9db918bdfbf6928fc3b59942efb7de6e54";
  flake = false;
};

flakesではインプットにflake.nix以外のリポジトリの指定もできるため、fetchFromGithubなどを使わずにソースの取得ができます。 flake.nix以外をインプットに指定する際は、 flake = false アトリビュートを指定します。

1
2
3
4
5
6
7
8
pkgs = pkgs.extend (final: prev: {
  tmuxPlugins = prev.tmuxPlugins // {
    dracula = prev.tmuxPlugins.dracula.overrideAttrs (oldAttrs: {
      version = "3.0.0";
      src = inputs.dracula-tmux;
    });
  };
});

nixGLの導入

最後はnixGLです。 これは私の場合はalacrittyで利用する必要があるのですが、NixをNixOS以外のLinux Distroで利用する場合、グラフィックドライバ回りでエラーが出ることが知られています。 nixGLはこの問題を回避するためのwrapper toolです。

A wrapper tool for nix OpenGL application [maintainer=@guibou] - nix-community/nixGL
GitHub - nix-community/nixGL: A wrapper tool for nix OpenGL application [maintainer=@guibou]

MacやWSL環境ではこの問題はないのですが、Raspberry Pi OSやZorin OSのようなLinux Distroでは利用する必要があります。

こちらもインプットにnixGLを指定し、home.nix内で以下のように指定するだけなので、channelを使っているときよりも明示的かつ集約して書けるようになりました。

1
package = config.lib.nixGL.wrap pkgs.alacritty;

まとめ

home-manager導入当時はexperimentalということもあって利用しなかったflakesですが、最近利用例も増えてきていてそろそろ使い時かなと思っていたので、年末の時間を使って移行できてよかったです。

実際に使ってみると、上記のflakesのメリットはかなり享受できていると感じています。home-manager以外のプロジェクトでもflakes化を進めていますが、 flake.lockflake.nix 単位での管理やインプット、アウトプットの記述も非常に取り回しがよいです。

urlで指定できるものの、インプットにrevisionの概念がなく、ロックしかできないなど気になるところもありますが、これからNixを導入する方はflakesで始めてもいいのではないかと思いました。

大きく概念が違うシステムが同じNixのシステムに共存しているので、それはそれでよりラーニングの弊害になっていそうですが、今後Nixとしてどういう方針になっていくのか興味深いところです。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。