on iko/ghcjs-patch-master help sign in
Tidy ci.nix using dimension (#500)

I recently came across this rather nice way of structuring build matrices for ci.nix. I think it makes the haskell.nix ci.nix a lot clearer!

commit33dc7bce3444f8957dec9dccb484dd4b40ee463d authorMichael Peyton Jones <michael.peyton-jones@iohk.io> dateFri 20 Mar 2020, 07:52 (7 years ago) parentcb3acc6
2 files changed+146−56
ci.nix+32−56 dimension.nix+114
ci.nix+32−56
@@ -3,66 +3,42 @@
33# - https://github.com/NixOS/nixpkgs/pull/68398
44
55let
6+ inherit (import ./dimension.nix) dimension;
67 nixpkgsVersions = {
78# "release-18.09" = builtins.fetchTarball "https://github.com/input-output-hk/nixpkgs/archive/7e4dcacbf066a8e2d12693a9de1fb30c77081c5d.tar.gz";
89 "release-19.03" = builtins.fetchTarball "https://github.com/input-output-hk/nixpkgs/archive/a8f81dc037a5977414a356dd068f2621b3c89b60.tar.gz";
910 # "release-19.09" = builtins.fetchTarball "https://github.com/input-output-hk/nixpkgs/archive/3d623a406cec9052ae0a16a79ce3ce9de11236bb.tar.gz";
1011 };
12+ systems = {
13+ "x86_64-linux" = {};
14+ };
15+ crossSystems = {
16+ "x86_64-pc-mingw32" = {};
17+ };
1118 haskellNixArgs = import ./.;
12− defaultNixpkgs = import (nixpkgsVersions."release-19.03") {};
13− recRecurseIntoAttrs = with defaultNixpkgs; pred: x: if pred x then recurseIntoAttrs (lib.mapAttrs (n: v: if n == "buildPackages" then v else recRecurseIntoAttrs pred v) x) else x;
1419in
15− recRecurseIntoAttrs (x: with defaultNixpkgs; lib.isAttrs x && !lib.isDerivation x) (
16− builtins.mapAttrs (nixpkgsName: nixpkgsSrc: with (import nixpkgsSrc {}); {
17− x86_64-linux = {
18− hello = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; }));
19− (haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
20− x86_64-pc-mingw32-hello = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; crossSystem.config = "x86_64-pc-mingw32"; }));
21− (haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
22−
23− iserv-proxy = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; }));
24− (ghc-extra-packages.ghc865.iserv-proxy.components.exes).iserv-proxy;
25−
26− x86_64-pc-mingw32-iserv-proxy = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; crossSystem.config = "x86_64-pc-mingw32"; }));
27− (buildPackages.ghc-extra-packages.ghc865.iserv-proxy.components.exes).iserv-proxy;
28−
29− x86_64-pc-mingw32-remote-iserv = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; crossSystem.config = "x86_64-pc-mingw32"; }));
30− (ghc-extra-packages.ghc865.remote-iserv.components.exes).remote-iserv;
31−
32− };
33− x86_64-darwin = {
34− hello = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; }));
35− (haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
36− x86_64-pc-mingw32-hello = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; crossSystem.config = "x86_64-pc-mingw32"; }));
37− (haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
38−
39− iserv-proxy = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; }));
40− (ghc-extra-packages.ghc865.iserv-proxy.components.exes).iserv-proxy;
41−
42− x86_64-pc-mingw32-iserv-proxy = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; crossSystem.config = "x86_64-pc-mingw32"; }));
43− (buildPackages.ghc-extra-packages.ghc865.iserv-proxy.components.exes).iserv-proxy;
44−
45− x86_64-pc-mingw32-remote-iserv = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; crossSystem.config = "x86_64-pc-mingw32"; }));
46− (ghc-extra-packages.ghc865.remote-iserv.components.exes).remote-iserv;
47−
48− };
49− haskell-nix.compiler = {
50− x86_64-linux = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; }));
51− haskell-nix.compiler;
52− x86_64-darwin = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin";}));
53− haskell-nix.compiler;
54− };
55− tests = {
56− x86_64-linux = (import ./test { nixpkgs = nixpkgsSrc; nixpkgsArgs = { system = "x86_64-linux"; }; });
57− # x86_64-darwin = (import ./test { nixpkgs = nixpkgsSrc; nixpkgsArgs = { system = "x86_64-darwin"; }; });
58− };
59−
60−# Don't build (all of) stackage on linux for now.
61−# stackage = {
62−# x86_64-linux = (with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; }));
63−# haskell-nix.snapshots."lts-13.29");
64−# # x86_64-darwin = (with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; }));
65−# # haskell-nix.snapshots."lts-13.29");
66−# };
67−
68−}) nixpkgsVersions)
20+dimension "Nixpkgs version" nixpkgsVersions (nixpkgsName: nixpkgsSrc:
21+ dimension "System" systems (system: _:
22+ # Native builds
23+ # TODO: can we merge this into the general case by picking an appropriate "cross system" to mean native?
24+ let pkgs = import nixpkgsSrc (haskellNixArgs // { inherit system; });
25+ in pkgs.recurseIntoAttrs {
26+ hello = (pkgs.haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
27+ iserv-proxy = pkgs.ghc-extra-packages.ghc865.iserv-proxy.components.exes.iserv-proxy;
28+ ghc = pkgs.recurseIntoAttrs pkgs.haskell-nix.compiler;
29+ tests = pkgs.lib.optionalAttrs (system == "x86_64-linux") (import ./test { inherit pkgs; });
30+ }
31+ //
32+ dimension "Cross system" crossSystems (crossSystem: _:
33+ # Cross builds
34+ let pkgs = import nixpkgsSrc (haskellNixArgs // { inherit system; crossSystem.config = crossSystem; });
35+ in pkgs.recurseIntoAttrs {
36+ hello = (pkgs.haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
37+
38+ iserv-proxy = pkgs.ghc-extra-packages.ghc865.iserv-proxy.components.exes.iserv-proxy;
39+
40+ remote-iserv = pkgs.ghc-extra-packages.ghc865.remote-iserv.components.exes.remote-iserv;
41+ }
42+ )
43+ )
44+)
dimension.nixnew file+114
@@ -0,0 +1,114 @@
1+# Borrowed from https://github.com/cachix/ghcide-nix/pull/4/files#diff-70bfff902f4dec33e545cac10ee5844d
2+# Tweaked to use builtins.mapAttrs instead of needing the one from nixpkgs lib
3+{
4+ /*
5+ dimension: name -> attrs -> function -> attrs
6+ where
7+ function: keyText -> value -> attrsOf package
8+
9+ WARNING: Attribute names must not contain periods (".").
10+ See https://github.com/NixOS/nix/issues/3088
11+
12+ NOTE: The dimension name will be picked up by agent and web ui soon.
13+
14+ Specifies a dimension of the build matrix. For example
15+
16+ dimension "Example" {
17+ withP = { p = true; }
18+ withoutP = { p = false; }
19+ } (key: # either "withP" or "withoutP"
20+ { p }: # either p = true or p = false
21+ myProject p
22+ )
23+
24+ evaluates roughly to
25+
26+ {
27+ withP = myProject true;
28+ withoutP = myProject false;
29+ }
30+
31+ Use nested calls for multiple dimensions.
32+
33+ Example:
34+
35+ dimension "System" {
36+ "x86_64-linux" = {};
37+ # ...
38+ }: (system: {}:
39+
40+ dimension "Nixpkgs release" (
41+ {
42+ "nixpkgs-19_03".nixpkgs = someSource
43+ } // optionalAttrs (system != "...") {
44+ "nixpkgs-unstable".nixpkgs = someOtherSource
45+ }
46+ ) (_key: { nixpkgs }:
47+
48+ myProject system nixpkgs
49+
50+ )
51+ )
52+
53+ evaluates roughly to
54+
55+ {
56+ x86_64-linux.nixpkgs-19_03 = myProject "x86_64-linux" someSource;
57+ x86_64-linux.nixpkgs-unstable = myProject "x86_64-linux" someOtherSource;
58+ ...
59+ }
60+
61+ If you need to make references across attributes, you can do so by binding
62+ the result. Wherever you write
63+
64+ dimension "My dimension" {} (key: value: f1 key value)
65+
66+ You can also write
67+
68+ let
69+ myDimension = dimension "My dimension" {} (key: value: f2 key value myDimension)
70+ in
71+ myDimension
72+
73+ This example builds a single test runner to reuse across releases:
74+
75+ let
76+ overlay =
77+ testRunnerPkgs: self: super: {
78+ # ...
79+ };
80+ myProject =
81+ { nixpkgs,
82+ pkgs ? import nixpkgs { overlays = [ overlay ]; },
83+ testRunnerPkgs ? pkgs
84+ }: pkgs;
85+ in
86+
87+ let
88+ latest = "nixpkgs-19_03";
89+ releases =
90+ dimension "Nixpkgs release"
91+ {
92+ nixpkgs-18_09.nixpkgs = someSource
93+ nixpkgs-19_03.nixpkgs = someOtherSource
94+ }
95+ (_key: { nixpkgs }:
96+
97+ myProject {
98+ inherit nixpkgs;
99+ testRunnerPkgs = releases."${latest}";
100+ }
101+
102+ );
103+ in releases;
104+
105+ */
106+ dimension = name: attrs: f:
107+ builtins.mapAttrs
108+ (k: v:
109+ let o = f k v;
110+ in o // { recurseForDerivations = o.recurseForDerivations or true; }
111+ )
112+ attrs
113+ // { meta.dimension.name = name; };
114+}