on iko/ghcjs-patch-master help sign in
Merge pull request #13 from input-output-hk/builder-haddock2

builder: Add haddock and hoogle

commit2520ce0f893723c7df3295d4e528c337fee7c0c2 authorRodney Lorrimar <dev@rodney.id.au> dateTue 12 Feb 2019, 12:54 (8 years ago) parent18be9568ad8731
12 files changed+275−18
builder/comp-builder.nix+57−14 builder/default.nix+5−1 lib/default.nix+3 modules/package.nix+26 test/builder-haddock/Setup.hs+2 test/builder-haddock/TestHaddock.hs+6 test/builder-haddock/default.nix+92 test/builder-haddock/plan.nix+23 test/builder-haddock/test-haddock.cabal+15 test/builder-haddock/test-haddock.nix+36 test/cabal-simple/default.nix+9−3 test/default.nix+1
builder/comp-builder.nix+57−14
@@ -16,6 +16,7 @@
1616, preBuild ? null, postBuild ? null
1717, preCheck ? null, postCheck ? null
1818, preInstall ? null, postInstall ? null
19+, preHaddock ? null, postHaddock ? null
1920, shellHook ? null
2021
2122, doCheck ? component.doCheck || haskellLib.isTest componentId
@@ -25,6 +26,11 @@
2526
2627, static ? stdenv.hostPlatform.isMusl
2728, deadCodeElimination ? true
29+
30+# Options for Haddock generation
31+, doHaddock ? component.doHaddock # Enable haddock and hoogle generation
32+, doHoogle ? true # Also build a hoogle index
33+, hyperlinkSource ? true # Link documentation to the source code
2834}:
2935
3036let
@@ -164,7 +170,8 @@ let
164170 # other flags
165171 "--enable-executable-stripping"
166172 "--enable-library-stripping"
167− ] ++ lib.optional (deadCodeElimination && stdenv.hostPlatform.isLinux) "--enable-split-sections"
173+ ] ++ lib.optional doHaddock' "--docdir=${docdir "$doc"}"
174+ ++ lib.optional (deadCodeElimination && stdenv.hostPlatform.isLinux) "--enable-split-sections"
168175 ++ lib.optional (static) "--enable-static"
169176 ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) (
170177 map (arg: "--hsc2hs-option=" + arg) ["--cross-compile" "--via-asm"]
@@ -182,7 +189,14 @@ let
182189 inherit package configFiles;
183190 };
184191
185−in stdenv.mkDerivation ({
192+ # the target dir for haddock documentation
193+ docdir = docoutput: docoutput + "/share/doc/" + componentId.cname;
194+
195+ doHaddock' = doHaddock && (haskellLib.isLibrary componentId);
196+
197+in stdenv.lib.fix (drv:
198+
199+stdenv.mkDerivation ({
186200 name = fullName;
187201
188202 inherit src doCheck doCrossCheck dontPatchELF dontStrip;
@@ -192,6 +206,10 @@ in stdenv.mkDerivation ({
192206 config = component;
193207 inherit configFiles;
194208 env = shellWrappers;
209+
210+ # The directory containing the haddock documentation.
211+ # `null' if no haddock documentation was built.
212+ haddockDir = if doHaddock' then "${docdir drv.doc}/html" else null;
195213 };
196214
197215 meta = {
@@ -216,13 +234,17 @@ in stdenv.mkDerivation ({
216234 ++ component.pkgconfig;
217235
218236 nativeBuildInputs =
219− [ghc]
237+ [ghc buildPackages.removeReferencesTo]
220238 ++ lib.optional (component.pkgconfig != []) pkgconfig
221239 ++ executableToolDepends;
222240
223241 SETUP_HS = setup + /bin/Setup;
224242
243+ outputs = ["out" ] ++ (lib.optional doHaddock' "doc");
244+
225245 # Phases
246+ preInstallPhases = lib.optional doHaddock' "haddockPhase";
247+
226248 prePatch = lib.optionalString (cabalFile != null) ''
227249 cat ${cabalFile} > ${package.identifier.name}.cabal
228250 '';
@@ -250,6 +272,32 @@ in stdenv.mkDerivation ({
250272 runHook postCheck
251273 '';
252274
275+ haddockPhase = ''
276+ runHook preHaddock
277+ docdir="${docdir "$doc"}"
278+ mkdir -p "$docdir"
279+
280+ $SETUP_HS haddock \
281+ "--html" \
282+ ${lib.optionalString doHoogle "--hoogle"} \
283+ ${lib.optionalString hyperlinkSource "--hyperlink-source"} \
284+ ${lib.concatStringsSep " " component.setupHaddockFlags}
285+
286+ html="dist/doc/html/${componentId.cname}"
287+
288+ if [ -d "$html" ]; then
289+ # Ensure that libraries are not pulled into the docs closure.
290+ # As an example, the prettified source code of a
291+ # Paths_package module will contain store paths of the library package.
292+ for x in "$html/src/"*.html; do
293+ remove-references-to -t $out $x
294+ done
295+
296+ cp -R "$html" "$docdir"/html
297+ fi
298+ runHook postHaddock
299+ '';
300+
253301 # Note: Cabal does *not* copy test executables during the `install` phase.
254302 installPhase = ''
255303 runHook preInstall
@@ -278,15 +326,10 @@ in stdenv.mkDerivation ({
278326}
279327# patches can (if they like) depend on the version and revision of the package.
280328// lib.optionalAttrs (patches != []) { patches = map (p: if builtins.isFunction p then p { inherit (package.identifier) version; inherit revision; } else p) patches; }
281−// lib.optionalAttrs (preUnpack != "") { inherit preUnpack; }
282−// lib.optionalAttrs (postUnpack != "") { inherit postUnpack; }
283−// lib.optionalAttrs (preConfigure != "") { inherit preConfigure; }
284−// lib.optionalAttrs (postConfigure != "") { inherit postConfigure; }
285−// lib.optionalAttrs (preBuild != "") { inherit preBuild; }
286−// lib.optionalAttrs (postBuild != "") { inherit postBuild; }
287−// lib.optionalAttrs (preCheck != "") { inherit preCheck; }
288−// lib.optionalAttrs (postCheck != "") { inherit postCheck; }
289−// lib.optionalAttrs (preInstall != "") { inherit preInstall; }
290−// lib.optionalAttrs (postInstall != "") { inherit postInstall; }
329+// haskellLib.optionalHooks {
330+ inherit preUnpack postUnpack preConfigure postConfigure
331+ preBuild postBuild preCheck postCheck
332+ preInstall postInstall preHaddock postHaddock;
333+}
291334// lib.optionalAttrs (stdenv.buildPlatform.libc == "glibc"){ LOCALE_ARCHIVE = "${buildPackages.glibcLocales}/lib/locale/locale-archive"; }
292−)
335+))
builder/default.nix+5−1
@@ -21,6 +21,8 @@
2121, postCheck
2222, preInstall
2323, postInstall
24+, preHaddock
25+, postHaddock
2426
2527, shellHook
2628
@@ -73,7 +75,9 @@ let
7375
7476 buildComp = componentId: component: comp-builder {
7577 inherit componentId component package name src flags setup cabalFile patches revision
76− preUnpack postUnpack preConfigure postConfigure preBuild postBuild preCheck postCheck preInstall postInstall
78+ preUnpack postUnpack preConfigure postConfigure
79+ preBuild postBuild preCheck postCheck
80+ preInstall postInstall preHaddock postHaddock
7781 shellHook
7882 ;
7983 };
lib/default.nix+3
@@ -61,6 +61,9 @@ with haskellLib;
6161 if componentId.ctype == "all" then ""
6262 else "${componentId.ctype}:${componentId.cname}";
6363
64+ # Remove null or empty values from an attrset.
65+ optionalHooks = lib.filterAttrs (_: hook: hook != null && hook != "");
66+
6467 # Avoid pkgs.callPackage for now. It does a lot of nonsense with OOP
6568 # style programming that we should avoid until we know we want it.
6669
modules/package.nix+26
@@ -135,6 +135,10 @@ in {
135135 type = listOfFilteringNulls str;
136136 default = config.setupInstallFlags;
137137 };
138+ setupHaddockFlags = mkOption {
139+ type = listOfFilteringNulls str;
140+ default = config.setupHaddockFlags;
141+ };
138142 doExactConfig = mkOption {
139143 type = bool;
140144 default = config.doExactConfig;
@@ -147,6 +151,11 @@ in {
147151 type = bool;
148152 default = config.doCrossCheck;
149153 };
154+ doHaddock = mkOption {
155+ description = "Enable building of the Haddock documentation from the annotated Haskell source code.";
156+ type = bool;
157+ default = config.doHaddock;
158+ };
150159 };
151160 };
152161 in {
@@ -225,6 +234,10 @@ in {
225234 type = listOfFilteringNulls str;
226235 default = [];
227236 };
237+ setupHaddockFlags = mkOption {
238+ type = listOfFilteringNulls str;
239+ default = [];
240+ };
228241 preUnpack = mkOption {
229242 type = nullOr lines;
230243 default = null;
@@ -265,6 +278,14 @@ in {
265278 type = nullOr string;
266279 default = null;
267280 };
281+ preHaddock = mkOption {
282+ type = nullOr string;
283+ default = null;
284+ };
285+ postHaddock = mkOption {
286+ type = nullOr string;
287+ default = null;
288+ };
268289 shellHook = mkOption {
269290 type = nullOr string;
270291 default = null;
@@ -282,6 +303,11 @@ in {
282303 type = bool;
283304 default = false;
284305 };
306+ doHaddock = mkOption {
307+ description = "Enable building of the Haddock documentation from the annotated Haskell source code.";
308+ type = bool;
309+ default = true;
310+ };
285311 };
286312
287313 # This has one quirk. Manually setting options on the all component
test/builder-haddock/Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
test/builder-haddock/TestHaddock.hsnew file+6
@@ -0,0 +1,6 @@
1+-- | Haddock test stuff
2+module TestHaddock (hello) where
3+
4+-- | Standard hello text.
5+hello :: String
6+hello = "Hello, world!"
test/builder-haddock/default.nixnew file+92
@@ -0,0 +1,92 @@
1+{ pkgs
2+, haskell
3+, stdenv
4+}:
5+
6+with stdenv.lib;
7+
8+let
9+ pkgSet = haskell.mkPkgSet {
10+ inherit pkgs;
11+ # generated with:
12+ # cabal new-build
13+ # plan-to-nix dist-newstyle/cache/plan.json > plan.nix
14+ # cabal-to-nix test-haddock.cabal > test-haddock.nix
15+ pkg-def = import ./plan.nix;
16+ pkg-def-overlays = [
17+ { test-haddock = ./test-haddock.nix; }
18+ ];
19+ modules = [
20+ # overrides to fix the build
21+ {
22+ packages.transformers-compat.components.library.doExactConfig = true;
23+ }
24+
25+ {
26+ # Add a hook to the haddock phase
27+ packages.test-haddock.postHaddock = ''
28+ echo "==="
29+ echo "This is the postHaddock hook. The files are:"
30+ find .
31+ echo "==="
32+ '';
33+
34+ # Check that the package option works
35+ packages.stm.doHaddock = false;
36+ }
37+ ];
38+ };
39+
40+ packages = pkgSet.config.hsPkgs;
41+
42+in
43+ stdenv.mkDerivation {
44+ name = "builder-haddock-test";
45+
46+ buildCommand = let
47+ inherit (packages.test-haddock.components) library;
48+ noDocLibrary = packages.stm.components.library;
49+ in ''
50+ ########################################################################
51+ # test haddock
52+
53+ doc="${toString library.doc}"
54+ docDir="${toString library.haddockDir}"
55+
56+ # exeDoc="$ disabled {toString packages.test-haddock.components.exes.test-haddock.doc}"
57+ # printf "checking that executable output does not have docs ... " >& 2
58+ # echo $exeDoc
59+ # test "$exeDoc" = ""
60+
61+ printf "checking that documentation directory was built... " >& 2
62+ echo "$doc" >& 2
63+ test -n "$doc"
64+
65+ printf "checking that documentation was generated... " >& 2
66+ grep hello "$docDir/TestHaddock.html" > /dev/null
67+ echo yes >& 2
68+
69+ printf "checking for hoogle index of package... " >& 2
70+ grep hello "$docDir/test-haddock.txt" > /dev/null
71+ echo yes >& 2
72+
73+ printf "checking for absence of documentation in another package... " >& 2
74+ if [ -d "${toString noDocLibrary.haddockDir}" ]; then
75+ echo "it exists - FAIL" >& 2
76+ else
77+ echo PASS >& 2
78+ fi
79+
80+ printf "checking for absence of library package store paths in docs... " >& 2
81+ if grep -R ${library} "$docDir" > /dev/null; then
82+ echo "Found ${library} - FAIL" >& 2
83+ exit 1
84+ else
85+ echo "PASS" >& 2
86+ fi
87+
88+ touch $out
89+ '';
90+
91+ meta.platforms = platforms.all;
92+} // { inherit packages pkgSet; }
test/builder-haddock/plan.nixnew file+23
@@ -0,0 +1,23 @@
1+hackage:
2+ {
3+ packages = {
4+ "ghc-prim".revision = hackage."ghc-prim"."0.5.2.0".revisions.default;
5+ "stm".revision = hackage."stm"."2.4.5.1".revisions.default;
6+ "rts".revision = hackage."rts"."1.0".revisions.default;
7+ "base".revision = hackage."base"."4.11.1.0".revisions.default;
8+ "array".revision = hackage."array"."0.5.2.0".revisions.default;
9+ "integer-gmp".revision = hackage."integer-gmp"."1.0.2.0".revisions.default;
10+ };
11+ compiler = {
12+ version = "8.4.4";
13+ nix-name = "ghc844";
14+ packages = {
15+ "ghc-prim" = "0.5.2.0";
16+ "stm" = "2.4.5.1";
17+ "rts" = "1.0";
18+ "base" = "4.11.1.0";
19+ "array" = "0.5.2.0";
20+ "integer-gmp" = "1.0.2.0";
21+ };
22+ };
23+ }
test/builder-haddock/test-haddock.cabalnew file+15
@@ -0,0 +1,15 @@
1+cabal-version: 2.2
2+name: test-haddock
3+version: 0.1.0.0
4+license: NONE
5+author: Rodney Lorrimar
6+maintainer: rodney.lorrimar@iohk.io
7+
8+library
9+ exposed-modules: TestHaddock
10+ other-modules: Paths_test_haddock
11+ -- other-extensions:
12+ build-depends: base ^>=4.11.1.0
13+ , stm
14+ -- hs-source-dirs:
15+ default-language: Haskell2010
test/builder-haddock/test-haddock.nixnew file+36
@@ -0,0 +1,36 @@
1+{ system
2+, compiler
3+, flags
4+, pkgs
5+, hsPkgs
6+, pkgconfPkgs
7+, ... }:
8+ {
9+ flags = {};
10+ package = {
11+ specVersion = "2.2";
12+ identifier = {
13+ name = "test-haddock";
14+ version = "0.1.0.0";
15+ };
16+ license = "NONE";
17+ copyright = "";
18+ maintainer = "rodney.lorrimar@iohk.io";
19+ author = "Rodney Lorrimar";
20+ homepage = "";
21+ url = "";
22+ synopsis = "";
23+ description = "";
24+ buildType = "Simple";
25+ };
26+ components = {
27+ "library" = {
28+ depends = [
29+ (hsPkgs.base)
30+ (hsPkgs.stm)
31+ ];
32+ };
33+ };
34+ } // rec {
35+ src = pkgs.lib.mkDefault ./.;
36+ }
test/cabal-simple/default.nix+9−3
@@ -19,7 +19,13 @@ let
1919 { cabal-simple = ./cabal-simple.nix;
2020 }
2121 ];
22− modules = [ ];
22+ modules = [
23+ {
24+ # Package has no exposed modules which causes
25+ # haddock: No input file(s)
26+ packages.cabal-simple.doHaddock = false;
27+ }
28+ ];
2329 };
2430
2531 packages = pkgSet.config.hsPkgs;
@@ -56,8 +62,8 @@ in
5662 meta.platforms = platforms.all;
5763
5864 passthru = {
59− inherit (packages) cabal-simple;
60− inherit pkgSet;
65+ # Used for debugging with nix repl
66+ inherit pkgSet packages;
6167
6268 # Used for testing externally with nix-shell (../tests.sh).
6369 # This just adds cabal-install to the existing shells.
test/default.nix+1
@@ -21,6 +21,7 @@ in {
2121 cabal-simple = callPackage ./cabal-simple { inherit haskell util; };
2222 cabal-22 = callPackage ./cabal-22 { inherit haskell; };
2323 with-packages = callPackage ./with-packages { inherit haskell util; };
24+ builder-haddock = callPackage ./builder-haddock { inherit haskell; };
2425
2526 # Run unit tests with: nix-instantiate --eval --strict -A unit
2627 # An empty list means success.