Enable faster building of formatter

Since the formatter always depended on devShell packages, building the
formatter involved building all the devShell packages, which can be
slow.

In the case where formatters are set to plain strings, such as
"nixpkgs-fmt", depending on the devShell packages is necessary in order
to put the formatting utility on the path. But when a formatters option
is set to an package, such as "${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt",
then that formatter option does not depend on the devShell packages.

Flakelight now detects if any of the configured formatters are using the
first form, and only if so does it add the devShell packages dependency.
This allows the first form to still work, without incurring a cost for
flakes that only use the second form.

Users can use the second form for all formatters options if they wish to
not build the devShell packages when using the formatter.
This commit is contained in:
Archit Gupta 2024-02-19 02:16:16 -08:00
parent 981e22f851
commit efcf01325b
2 changed files with 19 additions and 7 deletions

View File

@ -836,10 +836,17 @@ You can set `formatters` to an attribute set, for which the keys are a file name
pattern and the value is the corresponding formatting command. `formatters` can
optionally be a function that takes packages and returns the above.
Formatting tools should be added to `devShell.packages` and all packages in
`devShell.packages` will be available for formatting commands.
Formatting tools should be added to `devShell.packages`; this enables easier use
as described below, as well as allowing flake users to use the tools directly
when in the devShell.
For example, to set Rust and Zig formatters:
Formatters can be set to a plain string like `"zig fmt"` or a full path like
`"${pkgs.zig}/bin/zig fmt"`. Formatters set as plain strings have access to all
packages in `devShell.packages`.
If building the formatter is slow due to building devShell packages, use full
paths for the formatters; the devShell packages are only included if a
formatting option is set to a plain string.
```nix
{

View File

@ -4,6 +4,7 @@
{ config, src, lib, flakelight, genSystems, ... }:
let
inherit (builtins) all hasContext;
inherit (lib) mkDefault mkMerge mkOption mkIf mapAttrsToList;
inherit (lib.types) functionTo lazyAttrsOf package str;
inherit (flakelight.types) nullable optFunctionTo;
@ -29,19 +30,23 @@ in
outputs.formatter = mkDefault (genSystems
({ pkgs, lib, fd, coreutils, ... }:
let
inherit (lib) attrValues makeBinPath;
formatters = config.formatters pkgs;
fullContext = all hasContext (attrValues formatters);
packages =
if config.devShell == null then [ ]
else (config.devShell pkgs).packages pkgs;
caseArms = toString (mapAttrsToList
(n: v: "\n ${n}) ${v} \"$f\" & ;;")
formatters);
in
pkgs.writeShellScriptBin "formatter" ''
PATH=${lib.makeBinPath packages}
PATH=${if fullContext then "" else makeBinPath packages}
for f in "$@"; do
if [ -d "$f" ]; then
${fd}/bin/fd "$f" -Htf -x "$0" &
else
case "$(${coreutils}/bin/basename "$f")" in
${toString (mapAttrsToList
(n: v: "${n}) ${v} \"$f\" & ;;") (config.formatters pkgs))}
case "$(${coreutils}/bin/basename "$f")" in${caseArms}
esac
fi
done &>/dev/null