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!
This commit is contained in:
Michael Peyton Jones 2020-03-20 07:52:34 +00:00 committed by GitHub
parent cb3acc6bd5
commit 33dc7bce34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 144 additions and 54 deletions

84
ci.nix
View File

@ -3,66 +3,42 @@
# - https://github.com/NixOS/nixpkgs/pull/68398
let
inherit (import ./dimension.nix) dimension;
nixpkgsVersions = {
# "release-18.09" = builtins.fetchTarball "https://github.com/input-output-hk/nixpkgs/archive/7e4dcacbf066a8e2d12693a9de1fb30c77081c5d.tar.gz";
"release-19.03" = builtins.fetchTarball "https://github.com/input-output-hk/nixpkgs/archive/a8f81dc037a5977414a356dd068f2621b3c89b60.tar.gz";
# "release-19.09" = builtins.fetchTarball "https://github.com/input-output-hk/nixpkgs/archive/3d623a406cec9052ae0a16a79ce3ce9de11236bb.tar.gz";
};
systems = {
"x86_64-linux" = {};
};
crossSystems = {
"x86_64-pc-mingw32" = {};
};
haskellNixArgs = import ./.;
defaultNixpkgs = import (nixpkgsVersions."release-19.03") {};
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;
in
recRecurseIntoAttrs (x: with defaultNixpkgs; lib.isAttrs x && !lib.isDerivation x) (
builtins.mapAttrs (nixpkgsName: nixpkgsSrc: with (import nixpkgsSrc {}); {
x86_64-linux = {
hello = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; }));
(haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
x86_64-pc-mingw32-hello = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; crossSystem.config = "x86_64-pc-mingw32"; }));
(haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
dimension "Nixpkgs version" nixpkgsVersions (nixpkgsName: nixpkgsSrc:
dimension "System" systems (system: _:
# Native builds
# TODO: can we merge this into the general case by picking an appropriate "cross system" to mean native?
let pkgs = import nixpkgsSrc (haskellNixArgs // { inherit system; });
in pkgs.recurseIntoAttrs {
hello = (pkgs.haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
iserv-proxy = pkgs.ghc-extra-packages.ghc865.iserv-proxy.components.exes.iserv-proxy;
ghc = pkgs.recurseIntoAttrs pkgs.haskell-nix.compiler;
tests = pkgs.lib.optionalAttrs (system == "x86_64-linux") (import ./test { inherit pkgs; });
}
//
dimension "Cross system" crossSystems (crossSystem: _:
# Cross builds
let pkgs = import nixpkgsSrc (haskellNixArgs // { inherit system; crossSystem.config = crossSystem; });
in pkgs.recurseIntoAttrs {
hello = (pkgs.haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
iserv-proxy = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; }));
(ghc-extra-packages.ghc865.iserv-proxy.components.exes).iserv-proxy;
iserv-proxy = pkgs.ghc-extra-packages.ghc865.iserv-proxy.components.exes.iserv-proxy;
x86_64-pc-mingw32-iserv-proxy = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; crossSystem.config = "x86_64-pc-mingw32"; }));
(buildPackages.ghc-extra-packages.ghc865.iserv-proxy.components.exes).iserv-proxy;
x86_64-pc-mingw32-remote-iserv = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; crossSystem.config = "x86_64-pc-mingw32"; }));
(ghc-extra-packages.ghc865.remote-iserv.components.exes).remote-iserv;
};
x86_64-darwin = {
hello = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; }));
(haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
x86_64-pc-mingw32-hello = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; crossSystem.config = "x86_64-pc-mingw32"; }));
(haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2";}).components.exes.hello;
iserv-proxy = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; }));
(ghc-extra-packages.ghc865.iserv-proxy.components.exes).iserv-proxy;
x86_64-pc-mingw32-iserv-proxy = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; crossSystem.config = "x86_64-pc-mingw32"; }));
(buildPackages.ghc-extra-packages.ghc865.iserv-proxy.components.exes).iserv-proxy;
x86_64-pc-mingw32-remote-iserv = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; crossSystem.config = "x86_64-pc-mingw32"; }));
(ghc-extra-packages.ghc865.remote-iserv.components.exes).remote-iserv;
};
haskell-nix.compiler = {
x86_64-linux = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; }));
haskell-nix.compiler;
x86_64-darwin = with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin";}));
haskell-nix.compiler;
};
tests = {
x86_64-linux = (import ./test { nixpkgs = nixpkgsSrc; nixpkgsArgs = { system = "x86_64-linux"; }; });
# x86_64-darwin = (import ./test { nixpkgs = nixpkgsSrc; nixpkgsArgs = { system = "x86_64-darwin"; }; });
};
# Don't build (all of) stackage on linux for now.
# stackage = {
# x86_64-linux = (with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-linux"; }));
# haskell-nix.snapshots."lts-13.29");
# # x86_64-darwin = (with (import nixpkgsSrc (haskellNixArgs // { system = "x86_64-darwin"; }));
# # haskell-nix.snapshots."lts-13.29");
# };
}) nixpkgsVersions)
remote-iserv = pkgs.ghc-extra-packages.ghc865.remote-iserv.components.exes.remote-iserv;
}
)
)
)

114
dimension.nix Normal file
View File

@ -0,0 +1,114 @@
# Borrowed from https://github.com/cachix/ghcide-nix/pull/4/files#diff-70bfff902f4dec33e545cac10ee5844d
# Tweaked to use builtins.mapAttrs instead of needing the one from nixpkgs lib
{
/*
dimension: name -> attrs -> function -> attrs
where
function: keyText -> value -> attrsOf package
WARNING: Attribute names must not contain periods (".").
See https://github.com/NixOS/nix/issues/3088
NOTE: The dimension name will be picked up by agent and web ui soon.
Specifies a dimension of the build matrix. For example
dimension "Example" {
withP = { p = true; }
withoutP = { p = false; }
} (key: # either "withP" or "withoutP"
{ p }: # either p = true or p = false
myProject p
)
evaluates roughly to
{
withP = myProject true;
withoutP = myProject false;
}
Use nested calls for multiple dimensions.
Example:
dimension "System" {
"x86_64-linux" = {};
# ...
}: (system: {}:
dimension "Nixpkgs release" (
{
"nixpkgs-19_03".nixpkgs = someSource
} // optionalAttrs (system != "...") {
"nixpkgs-unstable".nixpkgs = someOtherSource
}
) (_key: { nixpkgs }:
myProject system nixpkgs
)
)
evaluates roughly to
{
x86_64-linux.nixpkgs-19_03 = myProject "x86_64-linux" someSource;
x86_64-linux.nixpkgs-unstable = myProject "x86_64-linux" someOtherSource;
...
}
If you need to make references across attributes, you can do so by binding
the result. Wherever you write
dimension "My dimension" {} (key: value: f1 key value)
You can also write
let
myDimension = dimension "My dimension" {} (key: value: f2 key value myDimension)
in
myDimension
This example builds a single test runner to reuse across releases:
let
overlay =
testRunnerPkgs: self: super: {
# ...
};
myProject =
{ nixpkgs,
pkgs ? import nixpkgs { overlays = [ overlay ]; },
testRunnerPkgs ? pkgs
}: pkgs;
in
let
latest = "nixpkgs-19_03";
releases =
dimension "Nixpkgs release"
{
nixpkgs-18_09.nixpkgs = someSource
nixpkgs-19_03.nixpkgs = someOtherSource
}
(_key: { nixpkgs }:
myProject {
inherit nixpkgs;
testRunnerPkgs = releases."${latest}";
}
);
in releases;
*/
dimension = name: attrs: f:
builtins.mapAttrs
(k: v:
let o = f k v;
in o // { recurseForDerivations = o.recurseForDerivations or true; }
)
attrs
// { meta.dimension.name = name; };
}