ryota2357

treefmt-nix を flake.nix から使ってみる

投稿日:

tag icon svg Nix

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

いつからか nix fmt で nix ファイルをフォーマットしていたら、warning が出るようになった。

$ nix fmt
Passing directories or non-Nix files (such as ".") is deprecated and will be unsupported soon, please use https://treefmt.com/ instead, e.g. via https://github.com/numtide/treefmt-nix

僕は flake.nix は次のようにして、nixfmt-rfc-style を直接指定していた。このようにするのではなく、treefmt 等を使えとのことである。

{
  ..
  output = {
    ..
    formatter = nixpkgs.legacyPackages.${system}.nixfmt-rfc-style;
  };
}

せっかくなので、treefmt-nix を導入 + それ以外のフォーマッタも nix fmt でまとめてフォーマットしてみることにした。

導入にあたっては Flake-parts を使用しない方法をとった。 また、treefmt-nix の README.md には treefmt.nix という別ファイルを作って設定する方法が書かれているが、そうではなく、flake.nix の 1 ファイルで設定した。

inputs に treefmt-nix を追加

README.md では url を指定しているだけであったが、inputs.nixpkgs.follows = "nixpkgs" も指定した方が良い。

{
  inputs = {
    ..
    treefmt-nix = {
      url = "github:numtide/treefmt-nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };
}

この inputs.nixpkgs.follows の有無による変化は flake.lock を見るとわかりやすい。 inputs.nixpkgs.follows = "nixpkgs" を入れることによって、nixpkgs の依存がまとめられていることが確認できるはずである。

outputs の書き方

続いて、outputs.formatter.<system> に treefmt-nix の設定を記述していく。 提として、この <system> の部分を省略し、かつ複数 system 対応した記述をしたい。 僕個人は対象プロジェクトにおおじて次の 2 つを使い分けているので紹介する。

1 つめは flake-utils を使う。依存が増える代わりに outputs.formatter 以外も設定できるので便利である。

{
  inputs = { ..省略 };
  outputs = { treefmt-nix, .. }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        formatter = treefmt-nix.lib.mkWrapper pkgs {
          ..ここに設定を書く
        };
      };
    );
}

依存を増やしたくない場合、 nixpkgs.lib.genAttrs を使えば良い。

{
  inputs = { ..省略 };
  outputs = { treefmt-nix, .. }:
  let
    systems = ["aarch64-linux" "aarch64-darwin" "x86_64-darwin" "x86_64-linux"];
    eachSystem = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
  in
  {
    formatter = eachSystem (pkgs: treefmt-nix.lib.mkWrapper pkgs {
      ..ここに設定を書く
    });
  };
}

続いて、上記 2 つの Nix 式で省略した ..ここに設定を書く について書いていく。

設定記述

基本は README.md に書いてある通りで、以下のような感じである。

{
  projectRootFile = "flake.nix";
  programs = {
    nixfmt.enable = true;
    taplo.enable = true;
    terraform.enable = true;
    ..
  };
  settings.formatter.terraform.excludes = [ "hello.tf" ];
}

この例の通り、フォーマットの対象外にしたいものは settings.formatter.<name>.excludes を使えばいい。

また、全てのフォーマッタに対して excludes したい、つまり global な excludes の設定の記述方法は次のようにしてできる。

{
  settings.global.excludes = [
    "dir/*"
    "some_file"
  ];
}

これは treefmt-nix#171 に書かれていた。(README にも書いておいてほしい...)

excludes 以外のオプションに関しては treefmt-nix/programs/ 以下に各フォーマッタのデフォルト構成・オプションが記述されているのでそれを見ながら設定すれば良さそうである。