Skip to content

Commit 366113b

Browse files
committed
Refactors the haskell.nix configurations with extras/flake-haskell.nix
1 parent f31debc commit 366113b

File tree

16 files changed

+1652
-591
lines changed

16 files changed

+1652
-591
lines changed

extras/build.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
purescriptFlake = import ./flake-purescript.nix pkgs;
1212
rustFlake = import ./flake-rust.nix pkgs;
1313
haskellData = import ./haskell-data.nix pkgs;
14+
haskellFlake = import ./flake-haskell.nix pkgs;
15+
haskellPlutusFlake = import ./flake-haskell-plutus.nix inputs.cardano-haskell-packages pkgs;
1416
};
1517
};
1618

extras/flake-haskell-plutus.nix

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Makes a Haskell Flake using haskell.nix with a simplified interface with support for Plutus development.
2+
cardano-haskell-packages: pkgs: opts:
3+
let
4+
plutusMod = (import ./haskell.nix/plutus.nix) opts.compiler-nix-name cardano-haskell-packages;
5+
opts' =
6+
if "modules" ? opts then opts // {
7+
modules = opts.modules ++ [ plutusMod ];
8+
}
9+
else opts // { modules = [ plutusMod ]; };
10+
in
11+
(import ./flake-haskell.nix pkgs) opts'

extras/flake-haskell.nix

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Makes a Haskell Flake using haskell.nix with a simplified interface.
2+
pkgs:
3+
let
4+
haskellNixOpts =
5+
{ src
6+
, name
7+
, dependencies ? [ ]
8+
, devShellTools ? [ ]
9+
, devShellHook
10+
, index-state
11+
, compiler-nix-name
12+
, modules ? [ ]
13+
}: {
14+
inherit src name dependencies devShellTools devShellHook index-state compiler-nix-name modules;
15+
};
16+
17+
hsNixProj = opts: with (haskellNixOpts opts);
18+
let
19+
proj = { lib, ... }: {
20+
inherit src name index-state compiler-nix-name;
21+
extraHackage = dependencies;
22+
modules = [
23+
(_: {
24+
packages = {
25+
allComponent.doHoogle = true;
26+
allComponent.doHaddock = true;
27+
28+
# Enable strict compilation
29+
"${name}".configureFlags = [ "-f-dev" ];
30+
};
31+
})
32+
];
33+
34+
shell = {
35+
withHoogle = true;
36+
exactDeps = true;
37+
nativeBuildInputs = devShellTools;
38+
39+
tools = {
40+
cabal = { };
41+
haskell-language-server = { };
42+
};
43+
44+
shellHook = lib.mkForce devShellHook;
45+
};
46+
47+
};
48+
in
49+
proj;
50+
51+
hsNixFlake = opts: with (haskellNixOpts opts);
52+
(pkgs.haskell-nix.cabalProject' ([
53+
((import ./haskell.nix/extra-hackage.nix) compiler-nix-name)
54+
(hsNixProj opts)
55+
]
56+
++ modules
57+
)
58+
).flake { };
59+
60+
in
61+
hsNixFlake
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Creates a haskell.nix module that adds the `extraHackage` options for specifying Cabal sources as additional compile dependencies.
2+
compiler-nix-name:
3+
let
4+
mylib = { pkgs, compiler-nix-name }: rec {
5+
mkPackageSpec = src:
6+
with pkgs.lib;
7+
let
8+
cabalFiles = concatLists (mapAttrsToList
9+
(name: type: if type == "regular" && hasSuffix ".cabal" name then [ name ] else [ ])
10+
(builtins.readDir src));
11+
12+
cabalPath =
13+
if length cabalFiles == 1
14+
then src + "/${builtins.head cabalFiles}"
15+
else builtins.abort "Could not find unique file with .cabal suffix in source: ${src}";
16+
cabalFile = builtins.readFile cabalPath;
17+
parse = field:
18+
let
19+
lines = filter (s: if builtins.match "^${field} *:.*$" (toLower s) != null then true else false) (splitString "\n" cabalFile);
20+
line =
21+
if lines != [ ]
22+
then head lines
23+
else builtins.abort "Could not find line with prefix ''${field}:' in ${cabalPath}";
24+
in
25+
replaceStrings [ " " ] [ "" ] (head (tail (splitString ":" line)));
26+
pname = parse "name";
27+
version = parse "version";
28+
in
29+
{ inherit src pname version; };
30+
31+
mkHackageDirFor = { pname, version, src }:
32+
pkgs.runCommand "${pname}-${version}-hackage" { }
33+
''
34+
set -e
35+
mkdir -p $out/${pname}/${version}
36+
md5=11111111111111111111111111111111
37+
sha256=1111111111111111111111111111111111111111111111111111111111111111
38+
length=1
39+
cat <<EOF > $out/"${pname}"/"${version}"/package.json
40+
{
41+
"signatures" : [],
42+
"signed" : {
43+
"_type" : "Targets",
44+
"expires" : null,
45+
"targets" : {
46+
"<repo>/package/${pname}-${version}.tar.gz" : {
47+
"hashes" : {
48+
"md5" : "$md5",
49+
"sha256" : "$sha256"
50+
},
51+
"length" : $length
52+
}
53+
},
54+
"version" : 0
55+
}
56+
}
57+
EOF
58+
cp ${src}/*.cabal $out/"${pname}"/"${version}"/
59+
'';
60+
61+
mkHackageTarballFromDirsFor = hackageDirs:
62+
let
63+
f = dir: ''
64+
echo ${dir}
65+
ln -s ${dir}/* hackage/
66+
'';
67+
in
68+
pkgs.runCommand "01-index.tar.gz" { } ''
69+
mkdir hackage
70+
${builtins.concatStringsSep "" (map f hackageDirs)}
71+
cd hackage
72+
tar --sort=name --owner=root:0 --group=root:0 --mtime='UTC 2009-01-01' -hczvf $out */*/*
73+
'';
74+
75+
mkHackageTarballFor = pkg-specs:
76+
mkHackageTarballFromDirsFor (map mkHackageDirFor pkg-specs);
77+
78+
mkHackageNixFor = hackageTarball:
79+
pkgs.runCommand "hackage-nix" { } ''
80+
set -e
81+
export LC_CTYPE=C.UTF-8
82+
export LC_ALL=C.UTF-8
83+
export LANG=C.UTF-8
84+
cp ${hackageTarball} 01-index.tar.gz
85+
${pkgs.gzip}/bin/gunzip 01-index.tar.gz
86+
${pkgs.haskell-nix.nix-tools.${compiler-nix-name}}/bin/hackage-to-nix $out 01-index.tar "https://mkHackageNix/"
87+
'';
88+
89+
copySrc = src: builtins.path {
90+
path = src;
91+
name = "copied-src-${builtins.baseNameOf (builtins.unsafeDiscardStringContext src)}";
92+
};
93+
94+
mkModuleFor = pkg-specs: { lib, ... }: {
95+
# Prevent nix-build from trying to download the packages
96+
packages = pkgs.lib.listToAttrs (map
97+
(spec: {
98+
name = spec.pname;
99+
value = { src = lib.mkOverride 99 (copySrc spec.src); };
100+
})
101+
pkg-specs);
102+
};
103+
104+
mkHackageFromSpecFor = pkg-specs: rec {
105+
extra-hackage-tarball = mkHackageTarballFor pkg-specs;
106+
extra-hackage = mkHackageNixFor extra-hackage-tarball;
107+
module = mkModuleFor pkg-specs;
108+
};
109+
110+
mkHackageFor = srcs: mkHackageFromSpecFor (map mkPackageSpec srcs);
111+
};
112+
in
113+
114+
{ lib, config, pkgs, ... }:
115+
let
116+
l = mylib { inherit pkgs; inherit compiler-nix-name; };
117+
# FIXME: We have only one Hackage now
118+
# FIXME: Do copySrc here, but for some reason Nix shits itself
119+
theHackages = [ (l.mkHackageFor config.extraHackage) ];
120+
ifd-parallel = pkgs.runCommandNoCC "ifd-parallel" { myInputs = builtins.foldl' (b: a: b ++ [ a.extra-hackage a.extra-hackage-tarball ]) [ ] theHackages; } "echo $myInputs > $out";
121+
ifdseq = x: builtins.seq (builtins.readFile ifd-parallel.outPath) x;
122+
nlib = pkgs.lib;
123+
in
124+
{
125+
_file = "lambda-buffers/extras/haskell.nix/extra-hackage.nix";
126+
options = with lib.types; {
127+
extraHackage = lib.mkOption {
128+
type = listOf str; # FIXME: Allow passing in a tuple of the src and cabal file instead.
129+
default = [ ];
130+
description = "List of paths to cabal projects to include as extra hackages";
131+
};
132+
};
133+
config = lib.mkIf (config.extraHackage != [ ]) {
134+
modules = ifdseq (builtins.map (x: x.module) theHackages);
135+
extra-hackage-tarballs = ifdseq (
136+
nlib.listToAttrs (nlib.imap0
137+
(i: x: {
138+
name = "_" + builtins.toString i;
139+
value = x.extra-hackage-tarball;
140+
})
141+
theHackages));
142+
extra-hackages = ifdseq (builtins.map (x: import x.extra-hackage) theHackages);
143+
};
144+
}

extras/haskell.nix/plutus.nix

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Creates a haskell.nix module that prepares a Cabal environment for building with Plutus.
2+
compiler-nix-name: cardano-haskell-packages:
3+
{ lib, config, pkgs, ... }:
4+
let
5+
pkgs' = pkgs;
6+
# https://github.com/input-output-hk/haskell.nix/issues/1177
7+
nonReinstallablePkgs = [
8+
"array"
9+
"base"
10+
"binary"
11+
"bytestring"
12+
"Cabal"
13+
"containers"
14+
"deepseq"
15+
"directory"
16+
"exceptions"
17+
"filepath"
18+
"ghc"
19+
"ghc-bignum"
20+
"ghc-boot"
21+
"ghc-boot"
22+
"ghc-boot-th"
23+
"ghc-compact"
24+
"ghc-heap"
25+
# "ghci"
26+
# "haskeline"
27+
"ghcjs-prim"
28+
"ghcjs-th"
29+
"ghc-prim"
30+
"ghc-prim"
31+
"hpc"
32+
"integer-gmp"
33+
"integer-simple"
34+
"mtl"
35+
"parsec"
36+
"pretty"
37+
"process"
38+
"rts"
39+
"stm"
40+
"template-haskell"
41+
"terminfo"
42+
"text"
43+
"time"
44+
"transformers"
45+
"unix"
46+
"Win32"
47+
"xhtml"
48+
];
49+
brokenLibsModule =
50+
let
51+
responseFile = builtins.toFile "response-file" ''
52+
--optghc=-XFlexibleContexts
53+
--optghc=-Wwarn
54+
--optghc=-fplugin-opt=PlutusTx.Plugin:defer-errors
55+
'';
56+
l = [
57+
"cardano-binary"
58+
"cardano-crypto-class"
59+
"cardano-crypto-praos"
60+
"cardano-prelude"
61+
"heapwords"
62+
"measures"
63+
"strict-containers"
64+
"cardano-ledger-byron"
65+
"cardano-slotting"
66+
];
67+
in
68+
{
69+
_file = "lambda-buffers/extras/haskell.nix/plutus.nix:brokenLibsModule";
70+
packages = builtins.listToAttrs (builtins.map
71+
(name: {
72+
inherit name;
73+
value.components.library.setupHaddockFlags = [ "--haddock-options=@${responseFile}" ];
74+
value.components.library.ghcOptions = [ "-XFlexibleContexts" "-Wwarn" "-fplugin-opt=PlutusTx.Plugin:defer-errors" ];
75+
value.components.library.extraSrcFiles = [ responseFile ];
76+
})
77+
l);
78+
};
79+
module = { pkgs, ... }: {
80+
_file = "lambda-buffers/extras/haskell.nix/plutus.nix:module";
81+
# FIXME: contentAddressed = true;
82+
inherit nonReinstallablePkgs; # Needed for a lot of different things
83+
packages = {
84+
cardano-crypto-class.components.library.pkgconfig = pkgs.lib.mkForce [ [ pkgs.libsodium-vrf pkgs.secp256k1 ] ];
85+
cardano-crypto-praos.components.library.pkgconfig = pkgs.lib.mkForce [ [ pkgs.libsodium-vrf ] ];
86+
};
87+
};
88+
in
89+
{
90+
_file = "lambda-buffers/extras/haskell.nix/plutus.nix";
91+
config = {
92+
cabalProjectLocal = ''
93+
repository cardano-haskell-packages
94+
url: https://input-output-hk.github.io/cardano-haskell-packages
95+
secure: True
96+
root-keys:
97+
key-threshold: 0
98+
99+
allow-newer:
100+
*:base,
101+
*:containers,
102+
*:directory,
103+
*:time,
104+
*:bytestring,
105+
*:aeson,
106+
*:protolude,
107+
*:template-haskell,
108+
*:ghc-prim,
109+
*:ghc,
110+
*:cryptonite,
111+
*:formatting,
112+
monoidal-containers:aeson,
113+
size-based:template-haskell,
114+
snap-server:attoparsec,
115+
-- tasty-hedgehog:hedgehog,
116+
*:hashable,
117+
*:text
118+
119+
constraints:
120+
text >= 2
121+
, aeson >= 2
122+
, dependent-sum >= 0.7
123+
, protolude >= 0.3.2
124+
, nothunks >= 0.1.3
125+
126+
package nothunks
127+
flags: +vector +bytestring +text
128+
'';
129+
inherit compiler-nix-name;
130+
modules = [ module brokenLibsModule ];
131+
inputMap."https://input-output-hk.github.io/cardano-haskell-packages" = "${cardano-haskell-packages}";
132+
shell = {
133+
withHoogle = lib.mkOverride 999 false; # FIXME set to true
134+
exactDeps = lib.mkOverride 999 true;
135+
tools.haskell-language-server = { };
136+
# We use the ones from Nixpkgs, since they are cached reliably.
137+
# Eventually we will probably want to build these with haskell.nix.
138+
nativeBuildInputs = [
139+
pkgs'.cabal-install
140+
];
141+
};
142+
};
143+
}

0 commit comments

Comments
 (0)