Skip to content

Commit 50b9238

Browse files
authored
Merge pull request #657 from cachix/fix-eval
flakes: ensure that flake `packages` don't throw during construction
2 parents 54a9ece + d9ad1cf commit 50b9238

File tree

9 files changed

+188
-105
lines changed

9 files changed

+188
-105
lines changed

.github/workflows/ci.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ jobs:
2222
name: pre-commit-hooks
2323
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
2424
- run: rm -rf /opt&
25-
- run: nix-build --keep-going
25+
- name: Evaluate flake-compat default.nix
26+
run: nix eval --show-trace --file ./default.nix run
2627

2728
tests-flakes:
2829
strategy:
@@ -39,7 +40,8 @@ jobs:
3940
- run: rm -rf /opt&
4041

4142
- name: Check nixpkgs-unstable
42-
run: nix flake check -L --show-trace
43+
working-directory: ./dev
44+
run: nix flake check -L --show-trace --no-write-lock-file
4345

4446
- run: nix eval .#lib.x86_64-linux.run --show-trace
4547

@@ -58,4 +60,5 @@ jobs:
5860
- run: rm -rf /opt&
5961

6062
- name: Check nixpkgs-stable
63+
working-directory: ./dev
6164
run: nix flake check -L --show-trace --override-input nixpkgs github:NixOS/nixpkgs/nixos-25.05

default.nix

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
let
2-
flake = (import
3-
(
4-
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
5-
fetchTarball {
6-
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
7-
sha256 = lock.nodes.flake-compat.locked.narHash;
8-
}
9-
)
10-
{ src = ./.; }
11-
).defaultNix;
2+
flake =
3+
(import
4+
(
5+
let
6+
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
7+
in
8+
fetchTarball {
9+
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
10+
sha256 = lock.nodes.flake-compat.locked.narHash;
11+
}
12+
)
13+
{ src = ./.; }).defaultNix;
1214
in
13-
flake.lib.${builtins.currentSystem} // flake.packages.${builtins.currentSystem}
15+
flake.lib.${builtins.currentSystem} // flake.legacyPackages.${builtins.currentSystem}

dev/flake.nix

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
description = "An internal test flake for git-hooks.nix";
3+
4+
inputs = {
5+
git-hooks.url = "path:..";
6+
};
7+
8+
outputs =
9+
{ git-hooks
10+
, ...
11+
}:
12+
{
13+
inherit (git-hooks) legacyPackages checks;
14+
};
15+
}

flake.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@
4040
'';
4141
};
4242

43+
# The set of tools exposed by git-hooks.
44+
# We use legacyPackages because not all tools are derivations that evaluate.
45+
legacyPackages = forAllSystems ({ pkgs, exposed, ... }: exposed.tools // {
46+
pre-commit = pkgs.pre-commit;
47+
});
48+
49+
# WARN: use `legacyPackages` instead to get error messages for deprecated packages
50+
#
51+
# Each entry is guaranteed to be a derivation that evaluates.
52+
# TODO: this should be deprecated as it exposes a subset of nixpkgs, which is incompatbile with the packages output.
4353
packages = forAllSystems ({ exposed, ... }: exposed.packages // {
4454
default = exposed.packages.pre-commit;
4555
});
@@ -50,10 +60,11 @@
5060
};
5161
});
5262

53-
checks = forAllSystems ({ exposed, ... }: lib.filterAttrs (k: v: v != null) exposed.checks);
63+
checks = forAllSystems ({ exposed, ... }: exposed.checks);
5464

5565
lib = forAllSystems ({ exposed, ... }: { inherit (exposed) run; });
5666

67+
# TODO: remove and expose a `lib` function is needed
5768
exposed = forAllSystems ({ exposed, ... }: exposed);
5869
};
5970
}

modules/hooks.nix

Lines changed: 16 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2618,7 +2618,7 @@ in
26182618
# need version >= 0.4.0 for the --from-stdin flag
26192619
toolVersionCheck = lib.versionAtLeast convco.version "0.4.0";
26202620
in
2621-
lib.throwIf (convco == null || !toolVersionCheck) "The version of Nixpkgs used by git-hooks.nix does not have the `convco` package (>=0.4.0). Please use a more recent version of Nixpkgs."
2621+
lib.throwIfNot toolVersionCheck "The version of Nixpkgs used by git-hooks.nix does not have the `convco` package (>=0.4.0). Please use a more recent version of Nixpkgs."
26222622
builtins.toString
26232623
script;
26242624
stages = [ "commit-msg" ];
@@ -3089,9 +3089,7 @@ lib.escapeShellArgs (lib.concatMap (ext: [ "--ghc-opt" "-X${ext}" ]) hooks.fourm
30893089
"$PRE_COMMIT_COMMIT_MSG_SOURCE" --commit-msg-file "$1"
30903090
'';
30913091
in
3092-
lib.throwIf (hooks.gptcommit.package == null) "The version of Nixpkgs used by git-hooks.nix does not have the `gptcommit` package. Please use a more recent version of Nixpkgs."
3093-
toString
3094-
script;
3092+
toString script;
30953093
stages = [ "prepare-commit-msg" ];
30963094
};
30973095
hadolint =
@@ -3110,13 +3108,7 @@ lib.escapeShellArgs (lib.concatMap (ext: [ "--ghc-opt" "-X${ext}" ]) hooks.fourm
31103108
## https://github.com/Frama-C/headache/blob/master/config_builtin.txt
31113109
files = "(\\.ml[ily]?$)|(\\.fmli?$)|(\\.[chy]$)|(\\.tex$)|(Makefile)|(README)|(LICENSE)";
31123110
package = tools.headache;
3113-
entry =
3114-
## NOTE: `headache` made into in nixpkgs on 12 April 2023. At the
3115-
## next NixOS release, the following code will become irrelevant.
3116-
lib.throwIf
3117-
(hooks.headache.package == null)
3118-
"The version of nixpkgs used by git-hooks.nix does not have `ocamlPackages.headache`. Please use a more recent version of nixpkgs."
3119-
"${hooks.headache.package}/bin/headache -h ${hooks.headache.settings.header-file}";
3111+
entry = "${hooks.headache.package}/bin/headache -h ${hooks.headache.settings.header-file}";
31203112
};
31213113
hindent =
31223114
{
@@ -3646,16 +3638,7 @@ lib.escapeShellArgs (lib.concatMap (ext: [ "--ghc-opt" "-X${ext}" ]) hooks.fourm
36463638
pre-commit-hook-ensure-sops = {
36473639
name = "pre-commit-hook-ensure-sops";
36483640
package = tools.pre-commit-hook-ensure-sops;
3649-
entry =
3650-
## NOTE: pre-commit-hook-ensure-sops landed in nixpkgs on 8 July 2022. Once it reaches a
3651-
## release of NixOS, the `throwIf` piece of code below will become
3652-
## useless.
3653-
lib.throwIf
3654-
(hooks.pre-commit-hook-ensure-sops.package == null)
3655-
"The version of nixpkgs used by git-hooks.nix does not have the `pre-commit-hook-ensure-sops` package. Please use a more recent version of nixpkgs."
3656-
''
3657-
${hooks.pre-commit-hook-ensure-sops.package}/bin/pre-commit-hook-ensure-sops
3658-
'';
3641+
entry = "${hooks.pre-commit-hook-ensure-sops.package}/bin/pre-commit-hook-ensure-sops";
36593642
files = "^secrets";
36603643
};
36613644
# See all CLI flags for prettier [here](https://prettier.io/docs/en/cli.html).
@@ -4134,25 +4117,17 @@ lib.escapeShellArgs (lib.concatMap (ext: [ "--ghc-opt" "-X${ext}" ]) hooks.fourm
41344117
description = "A universal formatter engine within the Tree-sitter ecosystem, with support for many languages.";
41354118
package = tools.topiary;
41364119
entry =
4137-
## NOTE: Topiary landed in nixpkgs on 2 Dec 2022. Once it reaches a
4138-
## release of NixOS, the `throwIf` piece of code below will become
4139-
## useless.
4140-
lib.throwIf
4141-
(hooks.topiary.package == null)
4142-
"The version of nixpkgs used by git-hooks.nix does not have the `topiary` package. Please use a more recent version of nixpkgs."
4143-
(
4144-
let
4145-
topiary-inplace = pkgs.writeShellApplication {
4146-
name = "topiary-inplace";
4147-
text = ''
4148-
for file; do
4149-
${hooks.topiary.package}/bin/topiary --in-place --input-file "$file"
4150-
done
4151-
'';
4152-
};
4153-
in
4154-
"${topiary-inplace}/bin/topiary-inplace"
4155-
);
4120+
let
4121+
topiary-inplace = pkgs.writeShellApplication {
4122+
name = "topiary-inplace";
4123+
text = ''
4124+
for file; do
4125+
${hooks.topiary.package}/bin/topiary --in-place --input-file "$file"
4126+
done
4127+
'';
4128+
};
4129+
in
4130+
"${topiary-inplace}/bin/topiary-inplace";
41564131
files = "(\\.json$)|(\\.toml$)|(\\.mli?$)";
41574132
};
41584133
treefmt =
@@ -4257,11 +4232,7 @@ lib.escapeShellArgs (lib.concatMap (ext: [ "--ghc-opt" "-X${ext}" ]) hooks.fourm
42574232
name = "typstyle";
42584233
description = "Beautiful and reliable typst code formatter";
42594234
package = tools.typstyle;
4260-
entry =
4261-
lib.throwIf
4262-
(hooks.typstyle.package == null)
4263-
"The version of nixpkgs used by git-hooks.nix must contain typstyle"
4264-
"${hooks.typstyle.package}/bin/typstyle -i";
4235+
entry = "${hooks.typstyle.package}/bin/typstyle -i";
42654236
files = "\\.typ$";
42664237
};
42674238
uv-check = {

nix/call-tools.nix

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
pkgs:
2-
pkgs.lib.flip builtins.removeAttrs [ "override" "overrideDerivation" ]
3-
(pkgs.callPackage ./tools.nix {
4-
cabal-fmt = (pkgs.haskell.lib.enableSeparateBinOutput pkgs.haskellPackages.cabal-fmt).bin;
5-
cabal-gild = (pkgs.haskell.lib.enableSeparateBinOutput pkgs.haskellPackages.cabal-gild).bin;
6-
hindent = pkgs.haskell.lib.enableSeparateBinOutput pkgs.haskellPackages.hindent;
7-
})
2+
pkgs.lib.flip builtins.removeAttrs [ "override" "overrideDerivation" ] (
3+
pkgs.callPackage ./tools.nix {
4+
placeholder =
5+
name:
6+
let
7+
errorMsg = ''
8+
git-hooks: the package `${name}` is not available in your nixpkgs revision.
9+
'';
10+
in
11+
{
12+
# Allows checking without forcing evaluation
13+
meta.isPlaceholder = true;
14+
15+
type = "derivation";
16+
name = name + "-placeholder";
17+
outPath = throw errorMsg;
18+
drvPath = throw errorMsg;
19+
};
20+
}
21+
)

nix/default.nix

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,51 @@ let
1919
;
2020
};
2121

22-
# Filter out any broken or missing packages from our tests.
23-
filterBrokenPackages = n: package: package != null && !(package.meta.broken or false);
22+
removeInvalidPackage = removeInvalidPackageWith { };
23+
removeInvalidPackageQuiet = removeInvalidPackageWith { warn = false; };
24+
25+
# Filter out broken and placeholder packages.
26+
removeInvalidPackageWith =
27+
{ warn ? true
28+
,
29+
}:
30+
name: package:
31+
let
32+
isPlaceholder = package.meta.isPlaceholder or false;
33+
isBroken = package.meta.broken or false;
34+
35+
check = builtins.tryEval (!(isPlaceholder || isBroken));
36+
result = check.success && check.value;
37+
38+
message =
39+
if !check.success then
40+
''
41+
Skipping ${name} because it failed to evaluate.
42+
''
43+
else if !check.value && isPlaceholder then
44+
''
45+
Skipping ${name} because it is missing from this nixpkgs revision.
46+
''
47+
else if !check.value && isBroken then
48+
''
49+
Skipping ${name} because it is marked as broken.
50+
''
51+
else
52+
""; # Not used
53+
54+
in
55+
if warn then lib.warnIfNot result message result else result;
2456
in
2557
{
2658
inherit tools run;
27-
# Flake style attributes
28-
packages = (lib.filterAttrs filterBrokenPackages tools) // {
59+
60+
# Flake-style attributes
61+
# Each should strictly be a valid derivation that evaluates.
62+
packages = (lib.filterAttrs removeInvalidPackageQuiet tools) // {
2963
inherit (pkgs) pre-commit;
3064
};
31-
checks = self.packages // {
65+
66+
checks = (lib.filterAttrs removeInvalidPackage tools) // {
3267
# A pre-commit-check for nix-pre-commit itself
3368
pre-commit-check = run {
3469
src = ../.;
@@ -57,7 +92,7 @@ let
5792
f n h.package;
5893

5994
allEntryPoints = lib.pipe allHooks [
60-
(lib.filterAttrs (getPackage filterBrokenPackages))
95+
(lib.filterAttrs (getPackage (removeInvalidPackageQuiet)))
6196
(lib.mapAttrsToList getEntry)
6297
];
6398
in

0 commit comments

Comments
 (0)