Skip to content

Commit 079e348

Browse files
authored
Merge pull request #138 from mlabs-haskell/bladyjoker/expose-lbf-nix
Demo: Expose lbf-nix for users
2 parents 61836c8 + 23045f4 commit 079e348

File tree

29 files changed

+1448
-2860
lines changed

29 files changed

+1448
-2860
lines changed

docs/plutarch/build.nix

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{ inputs, ... }:
22
{
3-
perSystem = { pkgs, config, ... }:
3+
perSystem = { config, ... }:
44
let
5-
project = { lib, ... }: {
5+
hsFlake = config.lbf-nix.haskellPlutusFlake {
66
src = ./.;
77

88
name = "plutarch-example";
99

1010
inherit (config.settings.haskell) index-state compiler-nix-name;
1111

12-
extraHackage = [
12+
dependencies = [
1313
# Load Plutarch support
1414
"${config.packages.lbf-prelude-plutarch}"
1515
"${config.packages.lbf-plutus-plutarch}"
@@ -22,49 +22,18 @@
2222
"${inputs.plutarch}/plutarch-extra"
2323
];
2424

25-
modules = [
26-
(_: {
27-
packages = {
28-
allComponent.doHoogle = true;
29-
allComponent.doHaddock = true;
30-
31-
# Enable strict compilation
32-
plutarch-example.configureFlags = [ "-f-dev" ];
33-
};
34-
})
35-
];
36-
37-
shell = {
38-
39-
withHoogle = true;
40-
41-
exactDeps = true;
42-
43-
nativeBuildInputs = config.settings.shell.tools ++ [ config.packages.lbf-plutus-to-plutarch ];
44-
45-
tools = {
46-
cabal = { };
47-
haskell-language-server = { };
48-
};
49-
50-
shellHook = lib.mkForce config.settings.shell.hook;
51-
};
25+
devShellTools = config.settings.shell.tools;
26+
devShellHook = config.settings.shell.hook;
5227
};
53-
hsNixFlake = (pkgs.haskell-nix.cabalProject' [
54-
inputs.mlabs-tooling.lib.mkHackageMod
55-
inputs.mlabs-tooling.lib.moduleMod
56-
project
57-
]).flake { };
58-
5928
in
6029

6130
{
62-
devShells.dev-plutarch-example = hsNixFlake.devShell;
31+
devShells.dev-plutarch-example = hsFlake.devShell;
6332

6433
packages = {
65-
plutarch-example-cli = hsNixFlake.packages."plutarch-example:exe:plutarch-example";
34+
plutarch-example-cli = hsFlake.packages."plutarch-example:exe:plutarch-example";
6635

67-
lbf-plutarch-example-api = config.overlayAttrs.lbf-nix.lbfPlutarch {
36+
lbf-plutarch-example-api = config.lbf-nix.lbfPlutarch {
6837
name = "lbf-plutarch-example-api";
6938
src = ./api;
7039
files = [ "Example.lbf" ];

extras/build.nix

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,52 @@
1-
# TODO(bladyjoker): Using overlayAttrs here as a hack to share functions -.- Do this properly.
2-
{ inputs, ... }: {
3-
imports = [
4-
inputs.flake-parts.flakeModules.easyOverlay # Adds perSystem.overlayAttrs
5-
];
6-
perSystem = { pkgs, ... }:
7-
{
8-
9-
overlayAttrs = {
10-
extras = {
11-
purescriptFlake = import ./flake-purescript.nix pkgs;
12-
rustFlake = import ./flake-rust.nix pkgs;
13-
haskellData = import ./haskell-data.nix pkgs;
1+
{ config, inputs, flake-parts-lib, lib, ... }: {
2+
3+
# Makes a system agnostic option (dunno why I needed this).
4+
options.lbf-nix = lib.mkOption {
5+
type = lib.types.anything; # probably not the best type
6+
default = { };
7+
};
8+
9+
# Makes it available in the system agnostic `lib` argument.
10+
config._module.args.lib = config.flake.lib // {
11+
inherit (config) lbf-nix;
12+
};
13+
14+
# Sets the above set option to system ones.
15+
config.lbf-nix = lib.genAttrs config.systems (system: (config.perSystem { inherit system; }).lbf-nix);
16+
17+
# Makes `lib.x86_64-linux.xyz` available
18+
config.flake.lib = config.lbf-nix;
19+
20+
options = {
21+
22+
# Makes a per system `lbf-nix` option.
23+
perSystem = flake-parts-lib.mkPerSystemOption
24+
({ pkgs, config, ... }: {
25+
26+
options.lbf-nix = lib.mkOption {
27+
type = lib.types.anything;
28+
default = { };
29+
};
30+
31+
# Sets a per system `lbf-nix` option.
32+
config = {
33+
lbf-nix = {
34+
# NOTE(bladyjoker): If you need to add a function the export externally and use internally via config.lbf-nix, add it here.
35+
purescriptFlake = import ./flake-purescript.nix pkgs;
36+
rustFlake = import ./flake-rust.nix pkgs;
37+
haskellData = import ./haskell-data.nix pkgs;
38+
haskellFlake = import ./flake-haskell.nix pkgs;
39+
haskellPlutusFlake = import ./flake-haskell-plutus.nix inputs.cardano-haskell-packages pkgs;
40+
};
41+
42+
# Makes it available in the per system `lib` argument.
43+
_module.args.lib = lib // {
44+
inherit (config) lbf-nix;
45+
};
46+
1447
};
15-
};
1648

17-
};
49+
});
50+
51+
};
1852
}

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: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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+
, devShellAdditionalPackages ? _: [ ]
11+
, index-state
12+
, compiler-nix-name
13+
, modules ? [ ]
14+
}: {
15+
inherit src name dependencies devShellTools devShellHook index-state compiler-nix-name modules devShellAdditionalPackages;
16+
};
17+
18+
hsNixProj = opts: with (haskellNixOpts opts);
19+
let
20+
proj = { lib, ... }: {
21+
inherit src name index-state compiler-nix-name;
22+
extraHackage = dependencies;
23+
modules = [
24+
(_: {
25+
packages = {
26+
allComponent.doHoogle = true;
27+
allComponent.doHaddock = true;
28+
29+
# Enable strict compilation
30+
"${name}".configureFlags = [ "-f-dev" ];
31+
};
32+
})
33+
];
34+
35+
shell = {
36+
withHoogle = true;
37+
exactDeps = true;
38+
nativeBuildInputs = devShellTools;
39+
additional = devShellAdditionalPackages;
40+
41+
tools = {
42+
cabal = { };
43+
haskell-language-server = { };
44+
};
45+
46+
shellHook = lib.mkForce devShellHook;
47+
};
48+
49+
};
50+
in
51+
proj;
52+
53+
hsNixFlake = opts: with (haskellNixOpts opts);
54+
(pkgs.haskell-nix.cabalProject' ([
55+
((import ./haskell.nix/extra-hackage.nix) compiler-nix-name)
56+
(hsNixProj opts)
57+
]
58+
++ modules
59+
)
60+
).flake { };
61+
62+
in
63+
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+
}

0 commit comments

Comments
 (0)