summary refs log tree commit diff
path: root/maintainers/scripts/haskell/test-configurations.nix
diff options
context:
space:
mode:
Diffstat (limited to 'maintainers/scripts/haskell/test-configurations.nix')
-rw-r--r--maintainers/scripts/haskell/test-configurations.nix136
1 files changed, 136 insertions, 0 deletions
diff --git a/maintainers/scripts/haskell/test-configurations.nix b/maintainers/scripts/haskell/test-configurations.nix
new file mode 100644
index 00000000000..12287896b50
--- /dev/null
+++ b/maintainers/scripts/haskell/test-configurations.nix
@@ -0,0 +1,136 @@
+/* Nix expression to test for regressions in the Haskell configuration overlays.
+
+   test-configurations.nix determines all attributes touched by given Haskell
+   configuration overlays (i. e. pkgs/development/haskell-modules/configuration-*.nix)
+   and builds all derivations (or at least a reasonable subset) affected by
+   these overrides.
+
+   By default, it checks `configuration-{common,nix,ghc-8.10.x}.nix`. You can
+   invoke it like this:
+
+     nix-build maintainers/scripts/haskell/test-configurations.nix --keep-going
+
+   It is possible to specify other configurations:
+
+     nix-build maintainers/scripts/haskell/test-configurations.nix \
+       --arg files '[ "configuration-ghc-9.0.x.nix" "configuration-ghc-9.2.x.nix" ]' \
+       --keep-going
+
+   You can also just supply a single string:
+
+     nix-build maintainers/scripts/haskell/test-configurations.nix \
+       --argstr files "configuration-arm.nix" --keep-going
+
+   You can even supply full paths which is handy, as it allows for tab-completing
+   the configurations:
+
+     nix-build maintainers/scripts/haskell/test-configurations.nix \
+       --argstr files pkgs/development/haskell-modules/configuration-arm.nix \
+       --keep-going
+
+   By default, derivation that fail to evaluate are skipped, unless they are
+   “just” marked as broken. You can check for other eval errors like this:
+
+     nix-build maintainers/scripts/haskell/test-configurations.nix \
+       --arg skipEvalErrors false --keep-going
+
+   You can also disable checking broken packages by passing a nixpkgs config:
+
+     nix-build maintainers/scripts/haskell/test-configurations.nix \
+       --arg config '{ allowBroken = false; }' --keep-going
+
+   By default the haskell.packages.ghc*Binary sets used for bootstrapping GHC
+   are _not_ tested. You can change this using:
+
+     nix-build maintainers/scripts/haskell/test-configurations.nix \
+       --arg skipBinaryGHCs false --keep-going
+
+*/
+{ files ? [
+    "configuration-common.nix"
+    "configuration-nix.nix"
+    "configuration-ghc-8.10.x.nix"
+  ]
+, nixpkgsPath ? ../../..
+, config ? { allowBroken = true; }
+, skipEvalErrors ? true
+, skipBinaryGHCs ? true
+}:
+
+let
+  pkgs = import nixpkgsPath { inherit config; };
+  inherit (pkgs) lib;
+
+  # see usage explanation for the input format `files` allows
+  files' = builtins.map builtins.baseNameOf (
+    if !builtins.isList files then [ files ] else files
+  );
+
+  setsForFile = fileName:
+    let
+      # extract the unique part of the config's file name
+      configName = builtins.head (
+        builtins.match "configuration-(.+).nix" fileName
+      );
+      # match the major and minor version of the GHC the config is intended for, if any
+      configVersion = lib.concatStrings (
+        builtins.match "ghc-([0-9]+).([0-9]+).x" configName
+      );
+      # return all package sets under haskell.packages matching the version components
+      setsForVersion =  builtins.map (name: pkgs.haskell.packages.${name}) (
+        builtins.filter (setName:
+          lib.hasPrefix "ghc${configVersion}" setName
+          && (skipBinaryGHCs -> !(lib.hasInfix "Binary" setName))
+        ) (
+          builtins.attrNames pkgs.haskell.packages
+        )
+      );
+
+      defaultSets = [ pkgs.haskellPackages ];
+    in {
+      # use plain haskellPackages for the version-agnostic files
+      # TODO(@sternenseemann): also consider currently selected versioned sets
+      "common" = defaultSets;
+      "nix" = defaultSets;
+      "arm" = defaultSets;
+      "darwin" = defaultSets;
+    }.${configName} or setsForVersion;
+
+  # attribute set that has all the attributes of haskellPackages set to null
+  availableHaskellPackages = builtins.listToAttrs (
+    builtins.map (attr: lib.nameValuePair attr null) (
+      builtins.attrNames pkgs.haskellPackages
+    )
+  );
+
+  # evaluate a configuration and only return the attributes changed by it,
+  # pass availableHaskellPackages as super in case intersectAttrs is used
+  overriddenAttrs = fileName: builtins.attrNames (
+    lib.fix (self:
+      import (nixpkgsPath + "/pkgs/development/haskell-modules/${fileName}") {
+        haskellLib = pkgs.haskell.lib.compose;
+        inherit pkgs;
+      } self availableHaskellPackages
+    )
+  );
+
+  # list of derivations that are affected by overrides in the given configuration
+  # overlays. For common, nix, darwin etc. only the derivation from the default
+  # package set will be emitted.
+  packages = builtins.filter (v:
+    lib.warnIf (v.meta.broken or false) "${v.pname} is marked as broken" (
+      v != null
+      && (skipEvalErrors -> (builtins.tryEval (v.outPath or v)).success)
+    )
+  ) (
+    lib.concatMap (fileName:
+      let
+        sets = setsForFile fileName;
+        attrs = overriddenAttrs fileName;
+      in
+        lib.concatMap (set: builtins.map (attr: set.${attr}) attrs) sets
+    ) files'
+  );
+in
+
+packages