about summary refs log tree commit diff
path: root/nixpkgs/maintainers/scripts/haskell/test-configurations.nix
blob: 8473ed4db8a2c172775a89cbc41801b773af2f43 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* 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
  );

  packageSetsWithVersionedHead = pkgs.haskell.packages // (
    let
      headSet = pkgs.haskell.packages.ghcHEAD;
      # Determine the next GHC release version following GHC HEAD.
      # GHC HEAD always has an uneven, tentative version number, e.g. 9.7.
      # GHC releases always have even numbers, i.e. GHC 9.8 is branched off from
      # GHC HEAD 9.7. Since we use the to be release number for GHC HEAD's
      # configuration file, we need to calculate this here.
      headVersion = lib.pipe headSet.ghc.version [
        lib.versions.splitVersion
        (lib.take 2)
        lib.concatStrings
        lib.strings.toInt
        (builtins.add 1)
        toString
      ];
    in
    {
      "ghc${headVersion}" = headSet;
    }
  );

  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: packageSetsWithVersionedHead.${name}) (
        builtins.filter (setName:
          lib.hasPrefix "ghc${configVersion}" setName
          && (skipBinaryGHCs -> !(lib.hasInfix "Binary" setName))
        ) (
          builtins.attrNames packageSetsWithVersionedHead
        )
      );

      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