Skip to content

Commit cc84d09

Browse files
hamishmackbooniepepper
authored andcommitted
Add haskell-nix.project (and project') (input-output-hk#703)
Generalized version of the `cabalProject` and `stackProject` functions. Automatically selects the correct project type based on the `projectFileName` argument if provided or what files exist in the `src` directory if no `projectFileName` was specified. If it cannot be determined which it should use the following error message is given: ``` error: haskell-nix.project : both `stack.yaml` and `cabal.project` files exist set `projectFileName = "stack.yaml;"` or `projectFileName = "cabal.project";` ```
1 parent 63c676d commit cc84d09

File tree

9 files changed

+95
-51
lines changed

9 files changed

+95
-51
lines changed

docs/tutorials/clean-git.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ packages:
7575
Then in `repoA/default.nix` we can use:
7676

7777
```
78-
haskell-nix.cabalProject {
78+
haskell-nix.project {
7979
src = haskell-nix.haskellLib.cleanSourceWith {
8080
src = haskell-nix.haskellLib.cleanGits {
8181
name = "root";

docs/tutorials/getting-started.md

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,19 @@ $ cachix use iohk
1818

1919
## Scaffolding
2020

21-
The following configuration will use `stack.yaml` if it exists,
22-
otherwise fallback to `cabal.project`.
21+
The following work with `stack.yaml` and `cabal.project` based
22+
projects.
2323

2424
Add `default.nix`:
2525

2626
```nix
27-
{ haskellCompiler ? "ghc865"
27+
{ # Default version of GHC to use (when not otherwise specified)
28+
defaultCompilerNixName ? "ghc865"
2829
2930
# Fetch the latest haskell.nix and import its default.nix
30-
, haskellNix ? import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz) {}
31+
, haskellNix ? import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz) {
32+
inherit defaultCompilerNixName;
33+
}
3134
3235
# haskell.nix provides access to the nixpkgs pins which are used by our CI, hence
3336
# you will be more likely to get cache hits when using these.
@@ -40,26 +43,26 @@ Add `default.nix`:
4043
4144
# import nixpkgs with overlays
4245
, pkgs ? import nixpkgsSrc nixpkgsArgs
46+
}: pkgs.haskell-nix.project {
47+
# 'cleanGit' cleans a source directory based on the files known by git
48+
src = pkgs.haskell-nix.haskellLib.cleanGit {
49+
name = "haskell-nix-project";
50+
src = ./.;
51+
};
52+
}
53+
```
54+
55+
Or a shorter `default.nix` that uses the default nixpkgs and default GHC:
4356

44-
# 'cleanGit' cleans a source directory based on the files known by git
45-
, src ? pkgs.haskell-nix.haskellLib.cleanGit {
57+
```nix
58+
{ haskellNix ? import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz) {}
59+
, pkgs ? haskellNix.pkgs
60+
}: pkgs.haskell-nix.project {
61+
src = pkgs.haskell-nix.haskellLib.cleanGit {
4662
name = "haskell-nix-project";
4763
src = ./.;
48-
}
49-
, hasStack ? builtins.pathExists (./. + "/cabal.project")
50-
, hasCabalProject ? builtins.pathExists (./. + "/stack.yaml")
51-
}:
52-
53-
assert (if hasStack && hasCabalProject then throw "This project has both stack.yaml and cabal.project. Edit default.nix to pick the one you'd like to use." else true);
54-
55-
if hasStack
56-
then pkgs.haskell-nix.stackProject
57-
{ inherit src;
58-
}
59-
else pkgs.haskell-nix.cabalProject
60-
{ inherit src;
61-
compiler-nix-name = haskellCompiler;
62-
}
64+
};
65+
}
6366
```
6467

6568
!!! note "git dependencies"

docs/tutorials/materialization.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ of an IFD (import from derviation).
88

99
## Why use materialization?
1010

11-
Using functions like `cabalProject`, `stackProject` and `hackage-package`
12-
results in a lot of dependencies (all the dependencies of nix-tools
13-
for instance).
11+
Using functions like `project`, `cabalProject`, `stackProject`
12+
and `hackage-package` results in a lot of dependencies (all the
13+
dependencies of nix-tools for instance).
1414

1515
* They can be slow to calculate (even if no work needs to be done it
1616
is not unusual for it to take 5 seconds per project).
@@ -59,8 +59,8 @@ trace: Using index-state: 2020-04-15T00:00:00Z for hlint
5959
```
6060

6161
To materialize the nix files we need to take care to pin down the
62-
inputs. For `cabalProject` and `hackage-package` this means
63-
we must specify the `index-state` of hackage we want to use:
62+
inputs. For cabal projects this means we must specify the
63+
`index-state` of hackage we want to use:
6464

6565
```nix
6666
let inherit (import ./. {}) sources nixpkgsArgs;
@@ -88,7 +88,7 @@ $ nix-hash --base32 --type sha256 /nix/store/8z6p4237rin3c6c1lmjwshmj8rdqrhw2-hl
8888
```
8989

9090
We can add the hash as `plan-sha256` or (`stack-sha256` for
91-
`stackProject`)
91+
stack projects)
9292

9393
```nix
9494
let inherit (import ./. {}) sources nixpkgsArgs;
@@ -191,10 +191,10 @@ the time, we would be better off just removing `materialized` and `plan-sha256`.
191191

192192
## How can we update the nix files with a script?
193193

194-
There are versions of the functions (`cabalProject'`, `stackProject'`
195-
and `hackage-project`) that also return the nix as `plan-nix` or
196-
`stack-nix`. By calling one of these functions without the
197-
hash and materialized nix we can find out what nix files should be.
194+
There are versions of the functions (`project'`, `cabalProject'`,
195+
`stackProject'` and `hackage-project`) that also return the nix as
196+
`plan-nix` or `stack-nix`. By calling one of these functions without
197+
the hash and materialized nix we can find out what nix files should be.
198198
For instance:
199199

200200
```nix

docs/tutorials/source-repository-hashes.md

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ that we wish to use. This is mostly handled automatically by
77
system that is configured to use restricted mode (typically hydra)
88
it will need an aditionaly hash.
99

10-
When using `cabalProject` or `stackProject` functions you can include
11-
the hash needed in a comment.
10+
When using `project`, `cabalProject` or `stackProject` functions
11+
you can include the hash needed in a comment.
1212

1313
To calculate the hash use `nix-prefetch-git`:
1414

@@ -24,7 +24,7 @@ $ nix-prefetch-git https://github.com/input-output-hk/haskell.nix.git bc01ebc05a
2424
}
2525
```
2626

27-
If you are using `cabalProject` add a `--sha256` comment to the
27+
If you have a cabal project add a `--sha256` comment to the
2828
`cabal.project` file:
2929

3030
```
@@ -36,7 +36,7 @@ source-repository-package
3636
--sha256: 003lm3pm024vhbfmii7xcdd9v2rczpflxf7gdl2pyxia7p014i8z
3737
```
3838

39-
If you are using `stackProject` add a `# nix-sha256` comment to the
39+
If you have a stack project add a `# nix-sha256` comment to the
4040
`stack.yaml` file:
4141

4242
```
@@ -48,12 +48,12 @@ extra-deps:
4848
# nix-sha256: 003lm3pm024vhbfmii7xcdd9v2rczpflxf7gdl2pyxia7p014i8z
4949
```
5050

51-
## lookupSha256
51+
## sha256map
5252

53-
In some cases we cannot modify the `cabal.project` file to add the
54-
`--sha256` comments. As an alternative we can pass in a `lookupSha256`
55-
function to get them. For instance pandoc includes a `cabal.project`
56-
file in hackage includes a `source-package-reference` to `pandoc-citeproc`:
53+
In some cases we cannot modify the `cabal.project` or `stack.yaml` file
54+
to add sha256 comments. As an alternative we can pass in a `sha256map`
55+
For instance pandoc includes a `cabal.project` file in hackage includes a
56+
`source-package-reference` to `pandoc-citeproc`:
5757

5858
```
5959
{ haskell-nix, testSrc } :
@@ -64,10 +64,9 @@ let
6464
index-state = "2020-04-15T00:00:00Z";
6565
# Function that returns a sha256 string by looking up the location
6666
# and tag in a nested attrset
67-
lookupSha256 = { location, tag, ... }:
67+
sha256map =
6868
{ "https://github.com/jgm/pandoc-citeproc"."0.17"
69-
= "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; }
70-
."${location}"."${tag}";
69+
= "0dxx8cp2xndpw3jwiawch2dkrkp15mil7pyx7dvd810pwc22pm2q"; };
7170
};
7271
in
7372
pandoc.components.exes.pandoc

overlays/haskell.nix

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,47 @@ final: prev: {
541541
shells.ghc = p.hsPkgs.shellFor {};
542542
};
543543

544+
# `project'` and `project` automatically select between `cabalProject`
545+
# and `stackProject` (when possible) by looking for `stack.yaml` or
546+
# `cabal.project` files. If both exist we can pass in one of:
547+
# `projectFileName = "stack.yaml;"`
548+
# `projectFileName = "cabal.project";`
549+
# to let it know which to choose (or pick another name). If the
550+
# selected file ends in a `.yaml` it is assumed to be for `stackProject`.
551+
# If niether `stack.yaml` nor `cabal.project` exist `cabalProject` is
552+
# used (as it will use a default `cabal.project`).
553+
project' = { src, projectFileName ? null, ... }@args:
554+
let
555+
dir = __readDir (src.origSrcSubDir or src);
556+
exists = fileName: builtins.elem (dir.${fileName} or "") ["regular" "symlink"];
557+
stackYamlExists = exists "stack.yaml";
558+
cabalProjectExists = exists "cabal.project";
559+
selectedFileName =
560+
if projectFileName != null
561+
then projectFileName # Prefer the user selected project file name
562+
else
563+
if stackYamlExists && cabalProjectExists
564+
then throw ("haskell-nix.project : both `stack.yaml` and `cabal.project` files exist "
565+
+ "set `projectFileName = \"stack.yaml\";` or `projectFileName = \"cabal.project\";`")
566+
else
567+
if stackYamlExists
568+
then "stack.yaml" # stack needs a stack.yaml
569+
else "cabal.project"; # the cabal.project file is optional
570+
in
571+
if final.lib.hasSuffix ".yaml" selectedFileName
572+
then stackProject' (args // { stackYaml = selectedFileName; })
573+
else cabalProject' (args // { cabalProjectFileName = selectedFileName; });
574+
575+
# This is the same as the `cabalPackage` and `stackPackage` wrappers
576+
# for `cabalPackage` and `stackPackage`.
577+
project = args: let p = project' args;
578+
in p.hsPkgs // {
579+
# Provide `nix-shell -A shells.ghc` for users migrating from the reflex-platform.
580+
# But we should encourage use of `nix-shell -A shellFor`
581+
shells.ghc = p.hsPkgs.shellFor {};
582+
} // final.lib.optionalAttrs (p ? stack-nix) { inherit (p) stack-nix; }
583+
// final.lib.optionalAttrs (p ? plan-nix ) { inherit (p) plan-nix; };
584+
544585
# Like `cabalProject'`, but for building the GHCJS compiler.
545586
# This is exposed to allow GHCJS developers to work on the GHCJS
546587
# code in a nix-shell with `shellFor`.

test/cabal-simple/default.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Test a package set
2-
{ stdenv, util, mkCabalProjectPkgSet, cabalProject', haskellLib, recurseIntoAttrs, testSrc }:
2+
{ stdenv, util, mkCabalProjectPkgSet, project', haskellLib, recurseIntoAttrs, testSrc }:
33

44
with stdenv.lib;
55

@@ -12,7 +12,7 @@ let
1212
}
1313
];
1414

15-
project = cabalProject' {
15+
project = project' {
1616
src = testSrc "cabal-simple";
1717
inherit modules;
1818
};

test/haskell-language-server/cabal.nix

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{ testSrc, evalPackages, buildPackages }:
22

3-
(buildPackages.haskell-nix.cabalProject {
3+
(buildPackages.haskell-nix.project {
44
src = evalPackages.fetchgit {
55
url = "https://github.com/haskell/haskell-language-server.git";
66
fetchSubmodules = true;
77
rev = "d2654185eef1b0d703cebc694e85438e20600e37";
88
sha256 = "0s0k2i0imkcn9zykhrlqq0r4ssv25mwbpdyc675xkzgl1vj1l8kd";
99
};
10+
projectFileName = "cabal.project";
1011
sha256map = {
1112
"https://github.com/wz1000/shake"."fb3859dca2e54d1bbb2c873e68ed225fa179fbef" = "0sa0jiwgyvjsmjwpfcpvzg2p7277aa0dgra1mm6afh2rfnjphz8z";
1213
"https://github.com/peti/cabal-plan"."894b76c0b6bf8f7d2f881431df1f13959a8fce87" = "06iklj51d9kh9bhc42lrayypcpgkjrjvna59w920ln41rskhjr4y";

test/haskell-language-server/stack.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{ testSrc, haskell-nix, evalPackages, buildPackages }:
22

3-
(buildPackages.haskell-nix.stackProject {
3+
(buildPackages.haskell-nix.project {
44
src = evalPackages.fetchgit {
55
url = "https://github.com/haskell/haskell-language-server.git";
66
fetchSubmodules = true;
77
rev = "d2654185eef1b0d703cebc694e85438e20600e37";
88
sha256 = "0s0k2i0imkcn9zykhrlqq0r4ssv25mwbpdyc675xkzgl1vj1l8kd";
99
};
10-
stackYaml = "stack-${haskell-nix.ghc.version}.yaml";
10+
projectFileName = "stack-${haskell-nix.ghc.version}.yaml";
1111
sha256map = {
1212
"https://github.com/wz1000/shake.git"."fb3859dca2e54d1bbb2c873e68ed225fa179fbef" = "0sa0jiwgyvjsmjwpfcpvzg2p7277aa0dgra1mm6afh2rfnjphz8z";
1313
"https://github.com/peti/cabal-plan.git"."894b76c0b6bf8f7d2f881431df1f13959a8fce87" = "06iklj51d9kh9bhc42lrayypcpgkjrjvna59w920ln41rskhjr4y";

test/stack-local-resolver/default.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
{ stackProject', recurseIntoAttrs, testSrc }:
1+
{ project', recurseIntoAttrs, testSrc }:
22

33
let
4-
project = stackProject' {
4+
project = project' {
55
src = testSrc "stack-local-resolver";
66
};
77
packages = project.hsPkgs;

0 commit comments

Comments
 (0)