This compromises the ability to `inputs'?formatter`, but that seems like a particularly rare use case. Instead, we treat `inputs'` as another "programmatic" as opposed to "polished" interfaces, similar to the `config` vs flake attributes distinction. The programmatic interfaces always prioritize laziness whereas the polished interfaces may choose to omit known-missing things, to a reasonable degree.
108 lines
4.4 KiB
Nix
108 lines
4.4 KiB
Nix
{ config, lib, flake-parts-lib, ... }:
|
|
let
|
|
inherit (lib)
|
|
mapAttrs
|
|
mkOption
|
|
optionalAttrs
|
|
types
|
|
;
|
|
inherit (flake-parts-lib)
|
|
mkPerSystemOption
|
|
;
|
|
|
|
# Do not copy this pattern! (probe, haveFormatterProbably, optionalAttrs)
|
|
# It kind of works somewhat for `formatter`, but it is bad.
|
|
# Nothing critical must rely on this!
|
|
# - `tryEval` makes debugging harder and more annoying
|
|
# - There's a performance cost to this otherwise useless evaluation
|
|
# - We only use it *in `formatter`* because the effects are limited to that
|
|
# particular attribute. This makes the risk somewhat manageable.
|
|
probe =
|
|
config.perSystem
|
|
# Elaborate error message that users should never see.
|
|
# The reason to even do this, is that we can sidestep
|
|
# https://github.com/hercules-ci/flake-parts/issues/288 in many cases,
|
|
# without flake author intervention to keep `nix flake check` happy.
|
|
(throw ''
|
|
For the purpose of finding out whether an option may be unset for all systems, flake-parts probes the perSystem module without a valid `system` argument, and tries to catch this exception if it finds that `system` is required for this determination. If you see this message, it means that for some reason, flake-parts was unable to catch this exception.
|
|
|
|
This may be a bug in Nix or in flake-parts, but ultimately this is due to the quirky requirement of flakes that the "system" attribute does not come first.
|
|
Flake-parts tries its best to correct that UX, but ultimately, this needs to be solved in Nix.
|
|
'');
|
|
|
|
haveFormatterProbably =
|
|
let
|
|
ev =
|
|
builtins.tryEval
|
|
probe.formatter;
|
|
in
|
|
# If it fails, we can't assume that we don't have a formatter, because it may well evaluate for a real system.
|
|
!ev.success
|
|
|| ev.value != null;
|
|
in
|
|
{
|
|
options = {
|
|
flake.formatter = mkOption {
|
|
type = types.lazyAttrsOf (types.nullOr types.package);
|
|
default = { };
|
|
description = ''
|
|
An attribute set of per system a package used by [`nix fmt`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html).
|
|
'';
|
|
};
|
|
|
|
perSystem = mkPerSystemOption {
|
|
_file = ./formatter.nix;
|
|
options = {
|
|
formatter = mkOption {
|
|
type = types.nullOr types.package;
|
|
default = null;
|
|
description = ''
|
|
A package used by [`nix fmt`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html).
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
};
|
|
config = {
|
|
flake.formatter =
|
|
# Work around `nix flake check` not allowing `null` values in output attributes.
|
|
optionalAttrs
|
|
haveFormatterProbably
|
|
(mapAttrs
|
|
(k: v:
|
|
if v.formatter != null then v.formatter
|
|
else
|
|
throw ''
|
|
flake-parts could not determine statically that no formatter is defined for *all* systems.
|
|
|
|
What happened?
|
|
|
|
1. For performance reasons, flake-parts must not query `perSystem` for every system, so it uses a heuristic to determine whether a formatter is defined for all systems.
|
|
2. Unfortunately, this heuristic is not perfect, and it wasn't able to determine for your flake that `perSystem.formatter` is always `null` (if it even is always `null`).
|
|
As a consequence of (1), flake-parts had to provide the output attribute `formatter.${k}`, but as a consequence of (2), you're seeing this error.
|
|
|
|
What to do?
|
|
|
|
This whole situation should be temporary. `nix flake check`/`show` can be changed to allow `null` values, which gives flake-parts and other frameworks a way to avoid this situation.
|
|
|
|
To change the `formatter` output attribute, you can control it precisely with the `touchup` module, for example:
|
|
|
|
imports = [ inputs.flake-parts.flakeModules.touchup ];
|
|
|
|
# Remove it
|
|
touchup.attr.formatter.enable = false;
|
|
|
|
# ... or only have it for listed systems
|
|
touchup.attr.formatter.any.enable = lib.mkDefault false;
|
|
touchup.attr.formatter.attr.x86_64-linux.enable = true;
|
|
touchup.attr.formatter.attr.aarch64-darwin.enable = true;
|
|
|
|
'')
|
|
config.allSystems);
|
|
|
|
perInput = system: flake: {
|
|
formatter = flake.formatter.${system};
|
|
};
|
|
|
|
};
|
|
}
|