Skip to content

Commit f24e0c9

Browse files
committed
Add nix module system with project helper and reflex-dom dep
- default.nix: top-level entry point delegating to nix/ - nix/default.nix: project function wrapping nix-haskell with obelisk module pre-imported - nix/module.nix: declare obelisk.static and obelisk.frontend.js as NixOS module options (replacing function arguments) - nix/lib.nix: rename ghcjsFrontend to frontendJs, add reflex-dom and reflex-dom-core as source-repository-packages - Add reflex-dom and nix-haskell submodules
1 parent 2f42104 commit f24e0c9

File tree

9 files changed

+202
-0
lines changed

9 files changed

+202
-0
lines changed

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[submodule "deps/nix-haskell"]
2+
path = deps/nix-haskell
3+
url = git@github.com:reflex-frp/nix-haskell.git
4+
[submodule "deps/reflex-dom"]
5+
path = deps/reflex-dom
6+
url = https://github.com/ymeister/reflex-dom.git

default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import ./nix

deps/nix-haskell

Submodule nix-haskell added at 0d5c5af

deps/reflex-dom

Submodule reflex-dom added at 5494148

docs/modules.man

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../deps/nix-haskell/docs/modules.man

docs/modules.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../deps/nix-haskell/docs/modules.md

nix/default.nix

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{ system }:
2+
3+
let lib = import ./lib.nix { inherit system; };
4+
5+
nix-haskell = import ../deps/nix-haskell { inherit system; };
6+
7+
module = import ./module.nix;
8+
9+
in lib // {
10+
inherit module;
11+
inherit (lib) extraCabalProject;
12+
13+
project = userModule: (nix-haskell {
14+
imports = [
15+
module
16+
userModule
17+
];
18+
}).haskell-nix.project;
19+
}

nix/lib.nix

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
{ system }:
2+
3+
let src = ../.;
4+
5+
nix-haskell = import ../deps/nix-haskell { inherit system; };
6+
7+
# Standalone project built only to produce the manifest generator executable.
8+
obelisk-asset-manifest = nix-haskell {
9+
name = "obelisk-asset-manifest";
10+
src = src + "/lib/asset/manifest";
11+
};
12+
13+
obelisk-asset-manifest-generate =
14+
"${obelisk-asset-manifest.haskell-nix.project.hsPkgs.obelisk-asset-manifest.components.exes.obelisk-asset-manifest-generate}/bin/obelisk-asset-manifest-generate";
15+
16+
# Keep only overrides whose package name exists in the project,
17+
# so overrides for absent packages are silently skipped.
18+
mkOptionalPackages = { config, lib }:
19+
lib.filterAttrs (name: _: config.packages ? ${name});
20+
21+
# Generate the Obelisk.Generated.Static Haskell module from static assets.
22+
obelisk-generated-static-manifest = static:
23+
obelisk-asset-manifest.nixpkgs.runCommand "obelisk-generated-static" {
24+
LANG = "en_US.UTF-8";
25+
LOCALE_ARCHIVE = "${obelisk-asset-manifest.nixpkgs.glibcLocales}/lib/locale/locale-archive";
26+
} ''
27+
${obelisk-asset-manifest-generate} ${static} $out obelisk-generated-static Obelisk.Generated.Static $out/files
28+
sed -i -e 's/GHC\.Internal\.Types/GHC.Types/g' $out/src/Obelisk/Generated/Static.hs
29+
'';
30+
31+
in {
32+
inherit src obelisk-asset-manifest obelisk-asset-manifest-generate;
33+
34+
# Hackage overlay entry for the generated static-asset manifest package.
35+
obeliskGeneratedStaticOverlay = static: {
36+
name = "obelisk-generated-static";
37+
version = "0";
38+
src = obelisk-generated-static-manifest static;
39+
};
40+
41+
frontendJs = config:
42+
config.haskell-nix.project.projectCross.ghcjs.hsPkgs.frontend.components.exes.frontend;
43+
44+
source-repository-packages = {
45+
obelisk-asset-manifest = src + "/lib/asset/manifest";
46+
obelisk-asset-serve-snap = src + "/lib/asset/serve-snap";
47+
obelisk-backend = src + "/lib/backend";
48+
obelisk-executable-config-inject = src + "/lib/executable-config/inject";
49+
obelisk-executable-config-lookup = src + "/lib/executable-config/lookup";
50+
obelisk-frontend = src + "/lib/frontend";
51+
obelisk-route = src + "/lib/route";
52+
obelisk-snap-extras = src + "/lib/snap-extras";
53+
tabulation = src + "/lib/tabulation";
54+
55+
reflex-dom = src + "/deps/reflex-dom/reflex-dom";
56+
reflex-dom-core = src + "/deps/reflex-dom/reflex-dom-core";
57+
};
58+
59+
extraCabalProject = [
60+
(builtins.readFile (src + "/lib/cabal.project.config"))
61+
];
62+
63+
inherit mkOptionalPackages;
64+
65+
# Force Simple build type so haskell.nix doesn't run a Setup.hs configure step.
66+
buildTypeOverride = { config, lib, ... }:
67+
let optional = mkOptionalPackages { inherit config lib; };
68+
in {
69+
packages = optional {
70+
backend.package.buildType = lib.mkOverride 75 "Simple";
71+
frontend.package.buildType = lib.mkOverride 75 "Simple";
72+
frontend-custom.package.buildType = lib.mkOverride 75 "Simple";
73+
static-manifest.package.buildType = lib.mkOverride 75 "Simple";
74+
};
75+
};
76+
77+
# Copy frontend.jsexe directory into $out/bin after GHCJS build.
78+
jsexeOverride = { config, lib, ... }:
79+
let optional = mkOptionalPackages { inherit config lib; };
80+
in {
81+
packages = optional {
82+
frontend.components.exes.frontend.postInstall = ''
83+
if [ -d dist/build/frontend/frontend.jsexe ]; then
84+
cp -r dist/build/frontend/frontend.jsexe $out/bin/
85+
fi
86+
'';
87+
};
88+
};
89+
90+
# Symlink static assets into frontend's dataDir
91+
# at both build time (preBuild) and in the installed output (postInstall).
92+
frontendDataOverride = { static ? null }:
93+
({ config, lib, pkgs, ... }:
94+
let dataDir = config.packages.frontend.package.dataDir;
95+
in {
96+
packages.frontend.components.library.preBuild = lib.optionalString (dataDir != "") ''
97+
mkdir -p ${dataDir}
98+
${if static != null && static != {} then ''ln -sf ${static} ${dataDir}/static'' else ""}
99+
'';
100+
packages.frontend.components.library.postInstall = ''
101+
for datadir in $data/share/*/*/frontend-*; do
102+
${if static != null && static != {} then ''ln -sf ${static} "$datadir/static"'' else ""}
103+
done
104+
'';
105+
}
106+
);
107+
108+
# Symlink static assets and frontend jsexe into backend's dataDir
109+
# at both build time (preBuild) and in the installed output (postInstall).
110+
backendDataOverride = { static ? null, frontendJs ? null }:
111+
({ config, lib, pkgs, ... }:
112+
let dataDir = config.packages.backend.package.dataDir;
113+
in {
114+
packages.backend.components.library.preBuild = lib.optionalString (dataDir != "") ''
115+
mkdir -p ${dataDir}
116+
${if static != null && static != {} then ''ln -sf ${static} ${dataDir}/static'' else ""}
117+
${if frontendJs != null && frontendJs != {} then ''ln -sf ${frontendJs}/bin/frontend.jsexe ${dataDir}/frontend.jsexe'' else ""}
118+
'';
119+
packages.backend.components.library.postInstall = ''
120+
for datadir in $data/share/*/*/backend-*; do
121+
${if static != null && static != {} then ''ln -sf ${static} "$datadir/static"'' else ""}
122+
${if frontendJs != null && frontendJs != {} then ''ln -sf ${frontendJs}/bin/frontend.jsexe "$datadir/frontend.jsexe"'' else ""}
123+
done
124+
'';
125+
}
126+
);
127+
128+
}

nix/module.nix

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# nix-haskell module that wires obelisk overrides and hackage overlays
2+
# into a project. Declares `obelisk.static` and `obelisk.frontend.js` options;
3+
# when set, generates hackage overlay and wires assets into frontend/backend data dirs.
4+
# frontend.js defaults to the project's GHCJS-cross-compiled frontend.
5+
{ config, lib, system, ... }:
6+
7+
let obeliskLib = import ./lib.nix { inherit system; };
8+
9+
static = config.obelisk.static;
10+
11+
frontendJs = config.obelisk.frontend.js;
12+
13+
in {
14+
options.obelisk = {
15+
static = lib.mkOption {
16+
type = lib.types.nullOr (lib.types.either lib.types.path lib.types.package);
17+
default = null;
18+
description = "Static assets path or derivation.";
19+
};
20+
21+
frontend.js = lib.mkOption {
22+
type = lib.types.nullOr lib.types.package;
23+
default = obeliskLib.frontendJs config;
24+
defaultText = lib.literalExpression "obeliskLib.frontendJs config";
25+
description = "GHCJS-compiled frontend derivation.";
26+
};
27+
};
28+
29+
config = {
30+
inherit (obeliskLib) extraCabalProject source-repository-packages;
31+
32+
hackage-overlays =
33+
if static != null
34+
then [ (obeliskLib.obeliskGeneratedStaticOverlay static) ]
35+
else [];
36+
37+
overrides = [
38+
obeliskLib.buildTypeOverride
39+
obeliskLib.jsexeOverride
40+
(obeliskLib.frontendDataOverride { inherit static; })
41+
(obeliskLib.backendDataOverride { inherit static; inherit frontendJs; })
42+
];
43+
};
44+
}

0 commit comments

Comments
 (0)