on iko/ghcjs-patch-master help sign in
Make it easier to access executable components (#565)

This overlay helps accessing common executable components. Typically we want to make these available in a nix-shell created with shellFor. In most cases the package name will be the same as the executable, but we have a `toolPackageName` mapping to help when it is not. ``` # To get a single tool: haskell-nix.tool "cabal" "3.2.0.0" # This does the same thing as: (haskell-nix.hackage-package { name = "cabal-install" version = "3.2.0.0" }).components.exes.cabal # To get an attr set containing multiple tools: haskell-nix.tools { cabal = "3.2.0.0"; hlint = "2.2.11"; } # To add tools to a shell: shellFor { tools = { cabal = "3.2.0.0"; hlint = "2.2.11"; }; } ``` When used in shellFor the tools will be compiled with the same version of ghc used in the shell (the build ghc in the case of cross compilation). Instead of a version string we can use an attr set containing arguments that will be passed to `cabalProject`. For instance to specify the ghc used to compile. Use: ``` haskell-nix.tool "cabal" { version = "3.2.0.0"; ghc = haskell-nix.compiler.ghc883; } ```

commit5ebce0eb3cef18551808dfa80cba8b7cd64146f0 authorHamish Mackenzie <Hamish.Mackenzie@iohk.io> dateWed 29 Apr 2020, 19:10 (7 years ago) parent52401d7
9 files changed+144−9
build.nix+11 builder/default.nix+2−1 builder/shell-for.nix+5−3 ci.nix+3−1 docs/reference/library.md+5−3 docs/user-guide/development.md+7−1 lib/default.nix+8 overlays/default.nix+1 overlays/tools.nix+102
build.nix+11
@@ -16,6 +16,17 @@ let
1616in rec {
1717 tests = import ./test/default.nix { inherit pkgs ifdLevel; };
1818
19+ tools = pkgs.recurseIntoAttrs
20+ (pkgs.lib.mapAttrs (_: ghc:
21+ let
22+ tool = name: version: pkgs.buildPackages.haskell-nix.tool name { inherit version ghc; };
23+ in pkgs.recurseIntoAttrs {
24+ cabal-32 = tool "cabal" "3.2.0.0";
25+ ghcide = tool "ghcide" "object-code";
26+ } // pkgs.lib.optionalAttrs (ghc.version == "8.6.5") {
27+ cabal-30 = tool "cabal" "3.0.0.0";
28+ }) { inherit (pkgs.buildPackages.haskell-nix.compiler) ghc865 ghc883; });
29+
1930 # Scripts for keeping Hackage and Stackage up to date, and CI tasks.
2031 # The dontRecurseIntoAttrs prevents these from building on hydra
2132 # as not all of them can work in restricted eval mode (as they
builder/default.nix+2−1
@@ -51,8 +51,9 @@ let
5151
5252 # Same as haskellPackages.shellFor in nixpkgs.
5353 shellFor = haskellLib.weakCallPackage pkgs ./shell-for.nix {
54− inherit hsPkgs ghcForComponent makeConfigFiles hoogleLocal haskellLib;
54+ inherit hsPkgs ghcForComponent makeConfigFiles hoogleLocal haskellLib buildPackages;
5555 inherit (buildPackages) glibcLocales;
56+ buildGHC = ghc.passthru.buildGHC or ghc;
5657 };
5758
5859 # Same as haskellPackages.ghcWithPackages and ghcWithHoogle in nixpkgs.
builder/shell-for.nix+5−3
@@ -1,4 +1,4 @@
1−{ lib, stdenv, glibcLocales, pkgconfig, ghcForComponent, makeConfigFiles, hsPkgs, hoogleLocal, haskellLib }:
1+{ lib, stdenv, glibcLocales, pkgconfig, ghcForComponent, makeConfigFiles, hsPkgs, hoogleLocal, haskellLib, buildPackages, buildGHC }:
22
33{ packages ? ps:
44 let
@@ -9,6 +9,7 @@
99, additional ? _: []
1010, withHoogle ? true
1111, exactDeps ? false
12+, tools ? {}
1213, ... } @ args:
1314
1415let
@@ -74,7 +75,7 @@ let
7475 # inherit (hsPkgs) hoogle;
7576 };
7677
77− mkDrvArgs = builtins.removeAttrs args ["packages" "additional" "withHoogle"];
78+ mkDrvArgs = builtins.removeAttrs args ["packages" "additional" "withHoogle" "tools"];
7879in
7980 stdenv.mkDerivation (mkDrvArgs // {
8081 name = mkDrvArgs.name or name;
@@ -84,7 +85,8 @@ in
8485 ++ lib.optional withHoogle' hoogleIndex;
8586 nativeBuildInputs = [ ghcEnv ]
8687 ++ nativeBuildInputs
87− ++ mkDrvArgs.nativeBuildInputs or [];
88+ ++ mkDrvArgs.nativeBuildInputs or []
89+ ++ lib.attrValues (buildPackages.haskell-nix.toolsForGhc buildGHC tools);
8890 phases = ["installPhase"];
8991 installPhase = "echo $nativeBuildInputs $buildInputs > $out";
9092 LANG = "en_US.UTF-8";
ci.nix+3−1
@@ -41,7 +41,7 @@ dimension "Nixpkgs version" nixpkgsVersions (nixpkgsName: nixpkgs-pin:
4141 # Native builds
4242 # TODO: can we merge this into the general case by picking an appropriate "cross system" to mean native?
4343 native = pkgs.recurseIntoAttrs {
44− inherit (build) tests maintainer-scripts maintainer-script-cache;
44+ inherit (build) tests tools maintainer-scripts maintainer-script-cache;
4545 hello = (pkgs.haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2"; }).components.exes.hello;
4646 iserv-proxy = pkgs.ghc-extra-packages.ghc865.iserv-proxy.components.exes.iserv-proxy;
4747 ghc = pkgs.recurseIntoAttrs pkgs.haskell-nix.compiler;
@@ -53,6 +53,8 @@ dimension "Nixpkgs version" nixpkgsVersions (nixpkgsName: nixpkgs-pin:
5353 let pkgs = import pinnedNixpkgsSrc (nixpkgsArgs // { inherit system crossSystem; });
5454 build = import ./build.nix { inherit pkgs ifdLevel; };
5555 in pkgs.recurseIntoAttrs {
56+ # TODO: look into making tools work when cross compiling
57+ # inherit (build) tools;
5658 hello = (pkgs.haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2"; }).components.exes.hello;
5759 iserv-proxy = pkgs.ghc-extra-packages.ghc865.iserv-proxy.components.exes.iserv-proxy;
5860 remote-iserv = pkgs.ghc-extra-packages.ghc865.remote-iserv.components.exes.remote-iserv;
docs/reference/library.md+5−3
@@ -366,9 +366,11 @@ shellFor =
366366| Argument | Type | Description |
367367|----------------|------|---------------------|
368368| `packages` | Function | Package selection function. It takes a list of [Haskell packages](#haskell-package) and returns a subset of these packages. |
369−| `withHoogle` | Boolean | Whether to build a Hoogle documentation index and provide the `hoogle` command. |
370−| `exactDeps` | Boolean | Prevents the Cabal solver from choosing any package dependency other than what are in the package set. |
371−| `{ ... }` | Attrset | All the other arguments are passed to [`mkDerivation`](https://nixos.org/nixpkgs/manual/#sec-using-stdenv). |
369+| `additional` | Function | Similar to `packages`, but the selected packages are built and included in `ghc-pkg list` (not just their dependencies). |
370+| `withHoogle` | Boolean | Whether to build a Hoogle documentation index and provide the `hoogle` command. |
371+| `exactDeps` | Boolean | Prevents the Cabal solver from choosing any package dependency other than what are in the package set. |
372+| `tools` | Function | AttrSet of tools to make available e.g. `{ cabal = "3.2.0.0"; }` or `{ cabal = { version = "3.2.0.0"; }; }` |
373+| `{ ... }` | Attrset | All the other arguments are passed to [`mkDerivation`](https://nixos.org/nixpkgs/manual/#sec-using-stdenv). |
372374
373375**Return value**: a derivation
374376
docs/user-guide/development.md+7−1
@@ -66,8 +66,14 @@ in
6666 withHoogle = true;
6767
6868 # You might want some extra tools in the shell (optional).
69+
70+ # Some common tools can be added with the `tools` argument
71+ tools = { cabal = "3.2.0.0"; hlint = "2.2.11"; };
72+ # See overlays/tools.nix for more details
73+
74+ # Some you may need to get some other way.
6975 buildInputs = with pkgs.haskellPackages;
70− [ hlint stylish-haskell ghcid ];
76+ [ ghcid ];
7177
7278 # Prevents cabal from choosing alternate plans, so that
7379 # *all* dependencies are provided by Nix.
lib/default.nix+8
@@ -199,4 +199,12 @@ with haskellLib;
199199 # This is the same as isCrossHost but for use when building ghc itself
200200 isCrossTarget = stdenv.targetPlatform != stdenv.hostPlatform
201201 && !(stdenv.hostPlatform.isLinux && stdenv.targetPlatform.isMusl);
202+
203+ # Takes a version number or attr set of arguments (for cabalProject)
204+ # and conversios it to an attr set of argments. This allows
205+ # the use of "1.0.0.0" or { version = "1.0.0.0"; ... }
206+ versionOrArgsToArgs = versionOrArgs:
207+ if lib.isAttrs versionOrArgs
208+ then versionOrArgs
209+ else { version = versionOrArgs; };
202210}
overlays/default.nix+1
@@ -13,6 +13,7 @@
1313 (import ./windows.nix)
1414 (import ./armv6l-linux.nix)
1515 (import ./musl.nix)
16+ (import ./tools.nix)
1617 # Restore nixpkgs haskell and haskellPackages
1718 (_: super: { inherit (super.haskell-nix-super) haskell haskellPackages; })
1819]
overlays/tools.nixnew file+102
@@ -0,0 +1,102 @@
1+# This overlay helps accessing common executable components.
2+# Typically we want to make these available in a nix-shell
3+# created with shellFor. In most cases the package name
4+# will be the same as the executable, but we have a
5+# `toolPackageName` mapping to help when it is not.
6+#
7+# To get a single tool:
8+# haskell-nix.tool "cabal" "3.2.0.0"
9+#
10+# This does the same thing as:
11+# (haskell-nix.hackage-package {
12+# name = "cabal-install"
13+# version = "3.2.0.0"
14+# }).components.exes.cabal
15+#
16+# To get an attr set containing multiple tools:
17+# haskell-nix.tools { cabal = "3.2.0.0"; hlint = "2.2.11"; }
18+#
19+# To add tools to a shell:
20+# shellFor { tools = { cabal = "3.2.0.0"; hlint = "2.2.11"; }; }
21+#
22+# When used in shellFor the tools will be compiled with the same version
23+# of ghc used in the shell (the build ghc in the case of cross compilation).
24+#
25+# Instead of a version string we can use an attr set containing
26+# arguments that will be passed to `cabalProject`.
27+#
28+# For instance to specify the ghc used to compile. Use:
29+# haskell-nix.tool "cabal" {
30+# version = "3.2.0.0";
31+# ghc = haskell-nix.compiler.ghc883;
32+# }
33+#
34+self: super:
35+let
36+ inherit (self) lib;
37+
38+in { haskell-nix = super.haskell-nix // {
39+
40+ # Some times the package name in hackage is not the same as tool name.
41+ toolPackageName = {
42+ cabal = "cabal-install";
43+ };
44+
45+ hackage-tool = { name, ... }@args:
46+ (self.haskell-nix.hackage-package
47+ (args // { name = self.haskell-nix.toolPackageName."${name}" or name; }))
48+ .components.exes."${name}";
49+
50+ tool = name: versionOrArgs:
51+ let
52+ args = self.haskell-nix.haskellLib.versionOrArgsToArgs versionOrArgs;
53+ in
54+ (if self.haskell-nix.custom-tools ? "${name}"
55+ && self.haskell-nix.custom-tools."${name}" ? "${args.version}"
56+ then self.haskell-nix.custom-tools."${name}"."${args.version}"
57+ else self.haskell-nix.hackage-tool) (args // { inherit name; });
58+
59+ tools = lib.mapAttrs self.haskell-nix.tool;
60+
61+ # Like `tools` but allows default ghc to be specified
62+ toolsForGhc = ghc: toolSet:
63+ self.haskell-nix.tools (
64+ lib.mapAttrs (name: versionOrArgs:
65+ # Add default ghc if not specified in the args
66+ { inherit ghc; }
67+ // self.haskell-nix.haskellLib.versionOrArgsToArgs versionOrArgs
68+ ) toolSet
69+ );
70+
71+ # Tools not in hackage yet
72+ custom-tools = {
73+ ghcide.object-code = args:
74+ (self.haskell-nix.cabalProject (args // {
75+ name = "ghcide";
76+ src = self.fetchFromGitHub {
77+ owner = "mpickering";
78+ repo = "ghcide";
79+ rev = "706c59c97c25c66798815c1dc3ee6885a298918a";
80+ sha256 = "0d158xifwvz0y69ah98ckxakzqpz229mq7rpf2bpbmwhnpw3jmm6";
81+ };
82+ modules = [({config, ...}: {
83+ packages.ghcide.configureFlags = [ "--enable-executable-dynamic" ];
84+ nonReinstallablePkgs = [ "Cabal" "array" "base" "binary" "bytestring" "containers" "deepseq"
85+ "directory" "filepath" "ghc" "ghc-boot" "ghc-boot-th" "ghc-compact"
86+ "ghc-heap" "ghc-prim" "ghci" "haskeline" "hpc" "integer-gmp"
87+ "libiserv" "mtl" "parsec" "pretty" "process" "rts" "stm"
88+ "template-haskell" "terminfo" "text" "time" "transformers" "unix"
89+ "xhtml"
90+ ];
91+ })];
92+ pkg-def-extras = [
93+ (hackage: {
94+ packages = {
95+ "alex" = (((hackage.alex)."3.2.5").revisions).default;
96+ "happy" = (((hackage.happy)."1.19.12").revisions).default;
97+ };
98+ })
99+ ];
100+ })).ghcide.components.exes.ghcide;
101+ };
102+}; }