From 4585d422cd4428e2279e344d7dc84436bab93300 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar <3998+srid@users.noreply.github.com> Date: Fri, 10 Feb 2023 15:07:06 -0500 Subject: [PATCH] Make `overrides` an overlay type rather than a `functionTo` (#67) --- CHANGELOG.md | 2 ++ flake-module.nix | 57 ++++++++++++++++++++++++++++++++++++++++-------- test/flake.nix | 35 ++++++++++++++++++++--------- 3 files changed, 75 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4625452..0a80ba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ - #37: Group `buildTools` (renamed to `tools`), `hlsCheck` and `hlintCheck` under the `devShell` submodule option; and allow disabling them all using `devShell.enable = false;` (useful if you want haskell-flake to produce just the package outputs). - #64: Remove hlintCheck (use [treefmt-nix](https://github.com/numtide/treefmt-nix#flake-parts) instead) - #52: Expose the final package set as `finalPackages`. Rename `haskellPackages`, accordingly, to `basePackages`. Overlays are applied on top of `basePackage` -- using `source-overrides`, `overrides`, `packages` in that order -- to produce `finalPackages`. + - #68: You can now use `imports` inside of `haskellProjects.` to modularize your Haskell project configuration. + - #67: `overrides` will be combined using `composeManyExtensions`, however their order is arbitrary. This is an experimental feature, and a warning will be logged. ## 0.1.0 diff --git a/flake-module.nix b/flake-module.nix index eb7ea8a..742034d 100644 --- a/flake-module.nix +++ b/flake-module.nix @@ -99,16 +99,55 @@ in description = ''Package overrides given new source path''; default = { }; }; - overrides = mkOption { - type = functionTo (functionTo (types.lazyAttrsOf raw)); - description = '' - Overrides for the Cabal project + overrides = + let + # WARNING: While the order is deterministic, it is not + # determined by the user. Thus overlays may be applied in + # an unexpected order. + # We need: https://github.com/NixOS/nixpkgs/issues/215486 + haskellOverlayType = types.mkOptionType { + name = "haskellOverlay"; + description = "An Haskell overlay function"; + descriptionClass = "noun"; + # NOTE: This check is not exhaustive, as there is no way + # to check that the function takes two arguments, and + # returns an attrset. + check = lib.isFunction; + merge = _loc: defs: + let + logWarning = + if builtins.length defs > 1 + then builtins.trace "WARNING[haskell-flake]: Multiple haskell overlays are applied in arbitrary order." null + else null; + overlays = + map (x: x.value) + (builtins.seq + logWarning + defs); + in + lib.composeManyExtensions overlays; + }; + in + mkOption { + type = haskellOverlayType; + description = '' + Cabal package overrides for this Haskell project - For handy functions, see - ''; - default = self: super: { }; - defaultText = lib.literalExpression "self: super: { }"; - }; + For handy functions, see + + + **WARNING**: When using `imports`, multiple overlays + will be merged using `lib.composeManyExtensions`. + However the order the overlays are applied can be + arbitrary (albeit deterministic, based on module system + implementation). Thus, the use of `overrides` via + `imports` is not officiallly supported. If you'd like + to see proper support, add your thumbs up to + . + ''; + default = self: super: { }; + defaultText = lib.literalExpression "self: super: { }"; + }; packages = mkOption { type = types.lazyAttrsOf packageSubmodule; description = '' diff --git a/test/flake.nix b/test/flake.nix index 6768ad8..9f8c253 100644 --- a/test/flake.nix +++ b/test/flake.nix @@ -24,19 +24,34 @@ ]; perSystem = { self', pkgs, ... }: { haskellProjects.default = { + # Multiple modules should be merged correctly. + imports = + let + defaults = { + overrides = self: super: { + # This is purposefully incorrect (pointing to ./.) because we + # expect it to be overriden below. + foo = self.callCabal2nix "foo" ./. { }; + }; + devShell = { + tools = hp: { + # Setting to null should remove this tool from defaults. + ghcid = null; + }; + hlsCheck.enable = true; + }; + }; + in + [ defaults ]; overrides = self: super: { - # Custom library overrides (here, "foo" comes from a flake input) + # This overrides the overlay above (in `defaults`), because the + # module system merges them in such order. cf. the WARNING in option + # docs. foo = self.callCabal2nix "foo" (inputs.haskell-multi-nix + /foo) { }; }; - devShell = { - tools = hp: { - # Some buildTools are included by default. If you do not want them, - # set them to 'null' here. - ghcid = null; - # You can also add additional build tools. - fzf = pkgs.fzf; - }; - hlsCheck.enable = true; + devShell.tools = hp: { + # Adding a tool should make it available in devshell. + fzf = pkgs.fzf; }; }; # haskell-flake doesn't set the default package, but you can do it here.