on iko/ghcjs-patch-master help sign in
Add Hix wrappers for Nix tools (#1053)

The `hix` tools are wrappers for the various `nix` tools that use `haskell.nix` without the need to add any `.nix` files. This is useful for: * A quick way to try out haskell.nix for new users. * Using haskell.nix to work on projects that do not have `.nix` files. * Testing to see if `haskell.nix` can build a project. * Making `flake` and `non flake` configurations to check `haskell.nix` treats them the same. The configuration arguments for `Hix` can be (from highest precedence to lowest): * Passed on the command line with `--arg` (or `--argstr` for string args). * Placed in `nix/hix.nix` file in the project dir. * Placed in `~/.config/hix/hix.conf` Boilerplate `default.nix`, `shell.nix` and `flake.nix` files can be added to a a project with a `nix/hix.nix` file to make it work with the standard `Nix` tools.

commit6b2839986418adf1fa6d13b777d34c2bb6760087 authorHamish Mackenzie <Hamish.Mackenzie@iohk.io> dateSat 26 Jun 2021, 17:58 (5 years ago) parent9ca4e61
8 files changed+452
default.nix+1 docs/dev/hix.md+27 docs/tutorials/getting-started-hix.md+203 hix/default.nix+44 hix/project.nix+77 modules/hix-project.nix+47 overlays/default.nix+2 overlays/hix.nix+51
default.nix+1
@@ -26,4 +26,5 @@
2626 nixpkgsArgs = { inherit config overlays system; };
2727 pkgs = import sources.nixpkgs nixpkgsArgs;
2828 pkgs-unstable = import sources.nixpkgs-unstable nixpkgsArgs;
29+ hix = import ./hix/default.nix;
2930}
docs/dev/hix.mdnew file+27
@@ -0,0 +1,27 @@
1+# Making changes to Hix
2+
3+When making changes to the way Hix works it is often useful to be able to
4+test the changes locally before uploading them to github.
5+
6+## Hix Command Wrappers
7+
8+Install the hix command wrappers after making changes to a local clone of haskell.nix:
9+
10+```
11+nix-env -iA hix -f /path/to/local/haskell.nix
12+hix-shell
13+```
14+
15+Or override the version of haskell.nix used by the commands with the `HIX_ROOT` environment variable:
16+
17+```
18+HIX_ROOT=/path/to/local/haskell.nix hix-shell
19+```
20+
21+## Flakes
22+
23+For flakes use `--override-input` to point to the modified haskell.nix:
24+
25+```
26+nix develop --override-input haskellNix /path/to/local/haskell.nix
27+```
docs/tutorials/getting-started-hix.mdnew file+203
@@ -0,0 +1,203 @@
1+# Getting started with Hix
2+
3+The `hix` tools are wrappers for the various `nix` tools that
4+use `haskell.nix` without the need to add any `.nix` files.
5+
6+This is useful for:
7+
8+* A quick way to try out haskell.nix for new users.
9+
10+* Using haskell.nix to work on projects that do not have
11+ `.nix` files.
12+
13+* Testing to see if `haskell.nix` can build a project.
14+
15+* Making `flake` and `non flake` configurations to check `haskell.nix`
16+ treats them the same.
17+
18+## Installing Nix
19+
20+To use Hix you will need to install [Nix](https://nixos.org/download.html).
21+
22+## Setting up the binary cache
23+
24+IMPORTANT: you *must* do this or you *will* build several copies of GHC!
25+
26+You can configure Nix to use our binary cache, which is pushed to by CI, so should contain the artifacts that you need.
27+
28+You need to add the following sections to `/etc/nix/nix.conf` or, if you are a trusted user, `~/.config/nix/nix.conf` (if you don't know what a "trusted user" is, you probably want to do the former).
29+
30+```
31+trusted-public-keys = [...] hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= [...]
32+substituters = [...] https://hydra.iohk.io [...]
33+```
34+
35+This can be tricky to get setup properly. If you're still having trouble getting cache hits, consult the corresponding [troubleshooting section](../reference/troubleshooting#why-am-i-building-ghc).
36+
37+## Installing Hix
38+
39+```
40+nix-env -iA hix -f https://github.com/input-output-hk/haskell.nix/tarball/master
41+```
42+
43+## Updating Hix (also updates hackage)
44+
45+```
46+hix update
47+```
48+
49+This is also necessary to make the latest nightly snapshot of hackage
50+avaiable to nix.
51+
52+## Building with Hix
53+
54+To run `cabal build` in a nix-shell with all the dependencies required:
55+
56+```
57+cabal unpack hello
58+cd hello-1.0.0.2
59+hix-shell --run 'cabal build'
60+```
61+
62+Build with nix:
63+
64+```
65+hix-build -A hsPkgs.hello.components.exes.hello
66+```
67+
68+Cross compile to JavaScript:
69+
70+```
71+hix-build -A projectCross.ghcjs.hsPkgs.hello.components.exes.hello
72+```
73+
74+## Configuring Hix
75+
76+The configuration arguments for `Hix` can be (from highest precedence to lowest):
77+
78+* Passed on the command line with `--arg` (or `--argstr` for string args).
79+
80+* Placed in `nix/hix.nix` file in the project dir.
81+
82+* Placed in `~/.config/hix/hix.conf`
83+
84+For example to build with GHC 8.10.5:
85+
86+```
87+hix-shell --argstr compiler-nix-name ghc8105 --run 'cabal build'
88+```
89+
90+or add a `nix/hix.nix` or `~/.config/hix/hix.conf` file:
91+
92+```nix
93+{ compiler-nix-name = "ghc8105"; }
94+```
95+
96+Here are just a few of the other configuration arguments you could use
97+in the files or on the command line (they are all optional):
98+
99+```nix
100+{ name = "hello"; # for better error messages and derivation names
101+ nixpkgsPin = "nixpkgs-unstable"; # or nixpkgs-2009 or nixpkgs-2003
102+ nixpkgs = <nixpkgs>; # use this instead of nixpkgsPin
103+ subDir = "some/sub/dir"; # sub dir containing the haskell project
104+ projectFileName = "stack.yaml"; # use this project file
105+ tools.haskell-language-server = "latest";
106+ tools.hlint = "latest"; # Include the latest hls and hlint in the shell
107+ index-state = "2021-02-22T00:00:00Z"; # It is normally best to put this in `cabal.project` (not here)
108+
109+# PLUS MANY MORE! Almost any argument you can pass to the project functions
110+# or to `shellFor` can be used in as a Hix configuration argument.
111+
112+}
113+```
114+
115+## Adding Nix Support with Niv
116+
117+If you have a `nix/hix.nix` file with suitable configuration that
118+you want to make available to users with Nix (without having to
119+install Hix).
120+
121+[Niv](https://github.com/nmattia/niv) is a command line tool for keeping tack of Nix project dependencies.
122+
123+After installing niv you can initialize niv and pin the latest haskell.nix
124+commit by running the following in the root directory of the project:
125+
126+```
127+niv init
128+niv add input-output-hk/haskell.nix -n haskellNix
129+```
130+
131+Add `default.nix`:
132+
133+```nix
134+(import (import nix/sources.nix).haskellNix {}).hix.project { src = ./.; }
135+```
136+
137+If you want to also pin `nixpkgs` with Niv use:
138+
139+```nix
140+let
141+ sources = import nix/sources.nix;
142+in
143+ (import sources.haskellNix {}).hix.project {
144+ inherit (sources) nixpkgs;
145+ src = ./.;
146+ }
147+```
148+
149+Add `shell.nix`:
150+
151+```nix
152+(import ./.).shell
153+```
154+
155+When you want to update to the latest version of haskell.nix use:
156+
157+```
158+niv update haskellNix
159+```
160+
161+## Adding Nix Flake Support
162+
163+To add flake support that uses the `nix/hix.nix` configuration in your
164+follow the [Getting started with flakes](getting-started.md) guide, but
165+use `haskell-nix.hix.project` instead of `haskell-nix.project'`
166+
167+The `nixpkgs` used will need to be selected as a flake input (any selection
168+made in `nix/hix.nix` will be ignored).
169+
170+Example `flake.nix` file:
171+
172+```nix
173+{
174+ description = "A very basic flake";
175+ inputs.haskellNix.url = "github:input-output-hk/haskell.nix";
176+ inputs.nixpkgs.follows = "haskellNix/nixpkgs-unstable";
177+ inputs.flake-utils.url = "github:numtide/flake-utils";
178+ outputs = { self, nixpkgs, flake-utils, haskellNix }:
179+ flake-utils.lib.eachSystem [ "x86_64-linux" "x86_64-darwin" ] (system:
180+ let
181+ overlays = [ haskellNix.overlay
182+ (final: prev: {
183+ # This overlay adds our project to pkgs
184+ helloProject =
185+ final.haskell-nix.hix.project {
186+ src = ./.;
187+ # Other project options can be put in `nix/hix.nix`
188+ };
189+ })
190+ ];
191+ pkgs = import nixpkgs { inherit system overlays; };
192+ flake = pkgs.helloProject.flake {
193+ # This adds support for `nix build .#js-unknown-ghcjs:hello:exe:hello`
194+ crossPlatforms = p: [p.ghcjs];
195+ };
196+ in flake // {
197+ # Built by `nix build .`
198+ defaultPackage = flake.packages."hello:exe:hello";
199+ });
200+}
201+```
202+
203+
hix/default.nixnew file+44
@@ -0,0 +1,44 @@
1+let
2+ sources = import (../nix/sources.nix) {};
3+ nixpkgs = import sources.nixpkgs-2009 {};
4+ args = '' --arg userDefaults "$HOME/.config/hix/hix.conf" --arg src ./.'';
5+ # Use HIX_ROOT to override the version of hix used when developing new hix features.
6+ # See docs/dev/hix.md for details.
7+ hixProject = "\${HIX_ROOT:-${./..}}/hix/project.nix";
8+in nixpkgs.symlinkJoin {
9+ name = "hix";
10+ paths = [
11+ (nixpkgs.writeScriptBin "hix-shell" ''
12+ nix-shell ${hixProject} ${args} -A shell "$@"
13+ '')
14+ (nixpkgs.writeScriptBin "hix-build" ''
15+ nix-build ${hixProject} ${args} "$@"
16+ '')
17+ (nixpkgs.writeScriptBin "hix-instantiate" ''
18+ nix-instantiate ${hixProject} ${args} "$@"
19+ '')
20+ (nixpkgs.writeScriptBin "hix-env" ''
21+ nix-env -f ${hixProject} ${args} "$@"
22+ '')
23+ (nixpkgs.writeScriptBin "hix" ''
24+ cmd=$1
25+ shift
26+ case $cmd in
27+ update)
28+ nix-env -iA hix -f https://github.com/input-output-hk/haskell.nix/tarball/master
29+ ;;
30+ build|dump-path|eval|log|path-info|run|search|show-derivation|sign-paths|verify|why-depends)
31+ nix $cmd -f ${hixProject} ${args} "$@"
32+ ;;
33+ repl)
34+ nix $cmd ${hixProject} ${args} "$@"
35+ ;;
36+ *)
37+ nix $cmd "$@"
38+ ;;
39+ esac
40+ '')
41+ ];
42+} // {
43+ project = import ./project.nix;
44+}
hix/project.nixnew file+77
@@ -0,0 +1,77 @@
1+{ src
2+, userDefaults ? {}
3+, nxipkgs ? null
4+, nixpkgsPin ? null
5+, pkgs ? null
6+, checkMaterialization ? null
7+, compiler-nix-name ? null
8+, shell ? null
9+, ...}@commandArgs:
10+let
11+ inherit ((lib.evalModules {
12+ modules = [
13+ (import ../modules/project-common.nix)
14+ (import ../modules/stack-project.nix)
15+ (import ../modules/cabal-project.nix)
16+ (import ../modules/project.nix)
17+ (import ../modules/hix-project.nix)
18+ projectDefaults
19+ commandArgs'
20+ { _module.args.pkgs = {}; }
21+ ];
22+ }).config) name;
23+ sources = import ../nix/sources.nix {};
24+ lib = import (sources.nixpkgs-unstable + "/lib");
25+ commandArgs' =
26+ builtins.listToAttrs (
27+ builtins.concatMap (
28+ name:
29+ if commandArgs.${name} == null || name == "src" || name == "userDefaults" || name == "inNixShell"
30+ then []
31+ else [{ inherit name; value = commandArgs.${name}; }]
32+ ) (builtins.attrNames commandArgs));
33+ defaultArgs = {
34+ nixpkgsPin = "nixpkgs-unstable";
35+ };
36+ importDefaults = src:
37+ if src == null || !(__pathExists src)
38+ then {}
39+ else import src;
40+ userDefaults = importDefaults (commandArgs.userDefaults or null);
41+ projectDefaults = importDefaults (toString (src.origSrcSubDir or src) + "/nix/hix.nix");
42+ inherit ((lib.evalModules {
43+ modules = [
44+ (import ../modules/project-common.nix)
45+ (import ../modules/stack-project.nix)
46+ (import ../modules/cabal-project.nix)
47+ (import ../modules/project.nix)
48+ (import ../modules/hix-project.nix)
49+ userDefaults
50+ projectDefaults
51+ commandArgs'
52+ ({config, pkgs, ...}: {
53+ haskellNix = import ./.. { inherit checkMaterialization; };
54+ nixpkgsPin = "nixpkgs-unstable";
55+ nixpkgs = config.haskellNix.sources.${config.nixpkgsPin};
56+ nixpkgsArgs = config.haskellNix.nixpkgsArgs // {
57+ overlays = config.haskellNix.nixpkgsArgs.overlays ++ config.overlays;
58+ };
59+ pkgs = import config.nixpkgs config.nixpkgsArgs;
60+ project = config.pkgs.haskell-nix.project [
61+ (import ../modules/hix-project.nix)
62+ userDefaults
63+ projectDefaults
64+ commandArgs'
65+ {
66+ src =
67+ if __pathExists (toString (src.origSrcSubDir or src) + "/.git")
68+ then config.pkgs.haskell-nix.haskellLib.cleanGit {
69+ inherit src name;
70+ }
71+ else src;
72+ }
73+ ];
74+ })
75+ ];
76+ }).config) project shell;
77+in project
modules/hix-project.nixnew file+47
@@ -0,0 +1,47 @@
1+{ lib, ... }: {
2+ _file = "haskell.nix/modules/hix-project.nix";
3+ options = {
4+ # These are options that only the Hix command wrappers use. If you make a flake
5+ # with `haskell-nix.hix.project`, then they are ignored.
6+ haskellNix = lib.mkOption {
7+ type = lib.types.unspecified;
8+ default = null;
9+ description = "Imported haskell.nix itself (this will be set by `hix`)";
10+ };
11+ nixpkgsPin = lib.mkOption {
12+ type = lib.types.str;
13+ default = "nixpkgs-unstable";
14+ description = "The name of a haskell.nix nixpkgs pin to use (e.g. nixpkgs-unstable or nixpkgs-2009)";
15+ };
16+ nixpkgs = lib.mkOption {
17+ type = lib.types.nullOr lib.types.path;
18+ default = null;
19+ description = "Path to the nixpkgs files to use (uses nixpkgsPin by default)";
20+ };
21+ nixpkgsArgs = lib.mkOption {
22+ type = lib.types.unspecified;
23+ default = null;
24+ description = "Path to the nixpkgs files to use (this will be set by `hix`)";
25+ };
26+ overlays = lib.mkOption {
27+ type = lib.types.unspecified;
28+ default = [];
29+ description = "Extra overlays to use (in addition to those haskell.nix includes)";
30+ };
31+ pkgs = lib.mkOption {
32+ type = lib.types.unspecified;
33+ default = null;
34+ description = "The pkgs (this will be set by `hix`)";
35+ };
36+ project = lib.mkOption {
37+ type = lib.types.unspecified;
38+ default = null;
39+ description = "The project (this will be set by `hix`)";
40+ };
41+ };
42+
43+ # Default values for other project options (things that do not have defaults for non hix projects)
44+ config = {
45+ compiler-nix-name = lib.mkDefault "ghc8105";
46+ };
47+}
overlays/default.nix+2
@@ -18,6 +18,7 @@ let
1818 emscripten = import ./emscripten.nix;
1919 nix-prefetch-git-minimal = import ./nix-prefetch-git-minimal.nix;
2020 gobject-introspection = import ./gobject-introspection.nix;
21+ hix = import ./hix.nix;
2122 eval-on-current = import ./eval-on-current.nix;
2223 eval-on-build = import ./eval-on-build.nix;
2324 ghcjs = import ./ghcjs.nix;
@@ -52,6 +53,7 @@ let
5253 nix-prefetch-git-minimal
5354 ghcjs
5455 gobject-introspection
56+ hix
5557 # Restore nixpkgs haskell and haskellPackages
5658 (_: prev: { inherit (prev.haskell-nix-prev) haskell haskellPackages; })
5759 ];
overlays/hix.nixnew file+51
@@ -0,0 +1,51 @@
1+final: prev: { haskell-nix = prev.haskell-nix // { hix = {
2+ project =
3+ { src
4+ , userDefaults ? {}
5+ , subDir ? null
6+ , name ? null
7+ , compiler-nix-name ? null
8+ , shell ? null
9+ , ...}@commandArgs:
10+ let
11+ inherit (final) lib;
12+ hixDefaults = { compiler-nix-name = lib.mkDefault "ghc8105"; };
13+ inherit ((lib.evalModules {
14+ modules = [
15+ (import ../modules/project-common.nix)
16+ (import ../modules/stack-project.nix)
17+ (import ../modules/cabal-project.nix)
18+ (import ../modules/project.nix)
19+ (import ../modules/hix-project.nix)
20+ projectDefaults
21+ commandArgs'
22+ { _module.args.pkgs = {}; }
23+ ];
24+ }).config) name;
25+ commandArgs' =
26+ builtins.listToAttrs (
27+ builtins.concatMap (
28+ name:
29+ if commandArgs.${name} == null || name == "src" || name == "userDefaults"
30+ then []
31+ else [{ inherit name; value = commandArgs.${name}; }]
32+ ) (builtins.attrNames commandArgs));
33+ importDefaults = src:
34+ if src == null || !(__pathExists src)
35+ then {}
36+ else import src;
37+ projectDefaults = importDefaults (toString (src.origSrcSubDir or src) + "/nix/hix.nix");
38+ in final.haskell-nix.project [
39+ (import ../modules/hix-project.nix)
40+ projectDefaults
41+ commandArgs'
42+ {
43+ src =
44+ if __pathExists (toString (src.origSrcSubDir or src) + "/.git")
45+ then final.haskell-nix.haskellLib.cleanGit {
46+ inherit src name;
47+ }
48+ else src;
49+ }
50+ ];
51+}; }; }