Skip to content

builder: Add haddock and hoogle #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 57 additions & 14 deletions builder/comp-builder.nix
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
, preBuild ? null, postBuild ? null
, preCheck ? null, postCheck ? null
, preInstall ? null, postInstall ? null
, preHaddock ? null, postHaddock ? null
, shellHook ? null

, doCheck ? component.doCheck || haskellLib.isTest componentId
Expand All @@ -25,6 +26,11 @@

, static ? stdenv.hostPlatform.isMusl
, deadCodeElimination ? true

# Options for Haddock generation
, doHaddock ? component.doHaddock # Enable haddock and hoogle generation
, doHoogle ? true # Also build a hoogle index
, hyperlinkSource ? true # Link documentation to the source code
}:

let
Expand Down Expand Up @@ -164,7 +170,8 @@ let
# other flags
"--enable-executable-stripping"
"--enable-library-stripping"
] ++ lib.optional (deadCodeElimination && stdenv.hostPlatform.isLinux) "--enable-split-sections"
] ++ lib.optional doHaddock' "--docdir=${docdir "$doc"}"
++ lib.optional (deadCodeElimination && stdenv.hostPlatform.isLinux) "--enable-split-sections"
++ lib.optional (static) "--enable-static"
++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) (
map (arg: "--hsc2hs-option=" + arg) ["--cross-compile" "--via-asm"]
Expand All @@ -182,7 +189,14 @@ let
inherit package configFiles;
};

in stdenv.mkDerivation ({
# the target dir for haddock documentation
docdir = docoutput: docoutput + "/share/doc/" + componentId.cname;

doHaddock' = doHaddock && (haskellLib.isLibrary componentId);

in stdenv.lib.fix (drv:

stdenv.mkDerivation ({
name = fullName;

inherit src doCheck doCrossCheck dontPatchELF dontStrip;
Expand All @@ -192,6 +206,10 @@ in stdenv.mkDerivation ({
config = component;
inherit configFiles;
env = shellWrappers;

# The directory containing the haddock documentation.
# `null' if no haddock documentation was built.
haddockDir = if doHaddock' then "${docdir drv.doc}/html" else null;
};

meta = {
Expand All @@ -216,13 +234,17 @@ in stdenv.mkDerivation ({
++ component.pkgconfig;

nativeBuildInputs =
[ghc]
[ghc buildPackages.removeReferencesTo]
++ lib.optional (component.pkgconfig != []) pkgconfig
++ executableToolDepends;

SETUP_HS = setup + /bin/Setup;

outputs = ["out" ] ++ (lib.optional doHaddock' "doc");

# Phases
preInstallPhases = lib.optional doHaddock' "haddockPhase";

prePatch = lib.optionalString (cabalFile != null) ''
cat ${cabalFile} > ${package.identifier.name}.cabal
'';
Expand Down Expand Up @@ -250,6 +272,32 @@ in stdenv.mkDerivation ({
runHook postCheck
'';

haddockPhase = ''
runHook preHaddock
docdir="${docdir "$doc"}"
mkdir -p "$docdir"

$SETUP_HS haddock \
"--html" \
${lib.optionalString doHoogle "--hoogle"} \
${lib.optionalString hyperlinkSource "--hyperlink-source"} \
${lib.concatStringsSep " " component.setupHaddockFlags}

html="dist/doc/html/${componentId.cname}"

if [ -d "$html" ]; then
# Ensure that libraries are not pulled into the docs closure.
# As an example, the prettified source code of a
# Paths_package module will contain store paths of the library package.
for x in "$html/src/"*.html; do
remove-references-to -t $out $x
done

cp -R "$html" "$docdir"/html
fi
runHook postHaddock
'';

# Note: Cabal does *not* copy test executables during the `install` phase.
installPhase = ''
runHook preInstall
Expand Down Expand Up @@ -278,15 +326,10 @@ in stdenv.mkDerivation ({
}
# patches can (if they like) depend on the version and revision of the package.
// lib.optionalAttrs (patches != []) { patches = map (p: if builtins.isFunction p then p { inherit (package.identifier) version; inherit revision; } else p) patches; }
// lib.optionalAttrs (preUnpack != "") { inherit preUnpack; }
// lib.optionalAttrs (postUnpack != "") { inherit postUnpack; }
// lib.optionalAttrs (preConfigure != "") { inherit preConfigure; }
// lib.optionalAttrs (postConfigure != "") { inherit postConfigure; }
// lib.optionalAttrs (preBuild != "") { inherit preBuild; }
// lib.optionalAttrs (postBuild != "") { inherit postBuild; }
// lib.optionalAttrs (preCheck != "") { inherit preCheck; }
// lib.optionalAttrs (postCheck != "") { inherit postCheck; }
// lib.optionalAttrs (preInstall != "") { inherit preInstall; }
// lib.optionalAttrs (postInstall != "") { inherit postInstall; }
// haskellLib.optionalHooks {
inherit preUnpack postUnpack preConfigure postConfigure
preBuild postBuild preCheck postCheck
preInstall postInstall preHaddock postHaddock;
}
// lib.optionalAttrs (stdenv.buildPlatform.libc == "glibc"){ LOCALE_ARCHIVE = "${buildPackages.glibcLocales}/lib/locale/locale-archive"; }
)
))
6 changes: 5 additions & 1 deletion builder/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
, postCheck
, preInstall
, postInstall
, preHaddock
, postHaddock

, shellHook

Expand Down Expand Up @@ -73,7 +75,9 @@ let

buildComp = componentId: component: comp-builder {
inherit componentId component package name src flags setup cabalFile patches revision
preUnpack postUnpack preConfigure postConfigure preBuild postBuild preCheck postCheck preInstall postInstall
preUnpack postUnpack preConfigure postConfigure
preBuild postBuild preCheck postCheck
preInstall postInstall preHaddock postHaddock
shellHook
;
};
Expand Down
3 changes: 3 additions & 0 deletions lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ with haskellLib;
if componentId.ctype == "all" then ""
else "${componentId.ctype}:${componentId.cname}";

# Remove null or empty values from an attrset.
optionalHooks = lib.filterAttrs (_: hook: hook != null && hook != "");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nifty!


# Avoid pkgs.callPackage for now. It does a lot of nonsense with OOP
# style programming that we should avoid until we know we want it.

Expand Down
26 changes: 26 additions & 0 deletions modules/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ in {
type = listOfFilteringNulls str;
default = config.setupInstallFlags;
};
setupHaddockFlags = mkOption {
type = listOfFilteringNulls str;
default = config.setupHaddockFlags;
};
doExactConfig = mkOption {
type = bool;
default = config.doExactConfig;
Expand All @@ -147,6 +151,11 @@ in {
type = bool;
default = config.doCrossCheck;
};
doHaddock = mkOption {
description = "Enable building of the Haddock documentation from the annotated Haskell source code.";
type = bool;
default = config.doHaddock;
};
};
};
in {
Expand Down Expand Up @@ -225,6 +234,10 @@ in {
type = listOfFilteringNulls str;
default = [];
};
setupHaddockFlags = mkOption {
type = listOfFilteringNulls str;
default = [];
};
preUnpack = mkOption {
type = nullOr lines;
default = null;
Expand Down Expand Up @@ -265,6 +278,14 @@ in {
type = nullOr string;
default = null;
};
preHaddock = mkOption {
type = nullOr string;
default = null;
};
postHaddock = mkOption {
type = nullOr string;
default = null;
};
shellHook = mkOption {
type = nullOr string;
default = null;
Expand All @@ -282,6 +303,11 @@ in {
type = bool;
default = false;
};
doHaddock = mkOption {
description = "Enable building of the Haddock documentation from the annotated Haskell source code.";
type = bool;
default = true;
};
};

# This has one quirk. Manually setting options on the all component
Expand Down
2 changes: 2 additions & 0 deletions test/builder-haddock/Setup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain
6 changes: 6 additions & 0 deletions test/builder-haddock/TestHaddock.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- | Haddock test stuff
module TestHaddock (hello) where

-- | Standard hello text.
hello :: String
hello = "Hello, world!"
92 changes: 92 additions & 0 deletions test/builder-haddock/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{ pkgs
, haskell
, stdenv
}:

with stdenv.lib;

let
pkgSet = haskell.mkPkgSet {
inherit pkgs;
# generated with:
# cabal new-build
# plan-to-nix dist-newstyle/cache/plan.json > plan.nix
# cabal-to-nix test-haddock.cabal > test-haddock.nix
pkg-def = import ./plan.nix;
pkg-def-overlays = [
{ test-haddock = ./test-haddock.nix; }
];
modules = [
# overrides to fix the build
{
packages.transformers-compat.components.library.doExactConfig = true;
}

{
# Add a hook to the haddock phase
packages.test-haddock.postHaddock = ''
echo "==="
echo "This is the postHaddock hook. The files are:"
find .
echo "==="
'';

# Check that the package option works
packages.stm.doHaddock = false;
}
];
};

packages = pkgSet.config.hsPkgs;

in
stdenv.mkDerivation {
name = "builder-haddock-test";

buildCommand = let
inherit (packages.test-haddock.components) library;
noDocLibrary = packages.stm.components.library;
in ''
########################################################################
# test haddock

doc="${toString library.doc}"
docDir="${toString library.haddockDir}"

# exeDoc="$ disabled {toString packages.test-haddock.components.exes.test-haddock.doc}"
# printf "checking that executable output does not have docs ... " >& 2
# echo $exeDoc
# test "$exeDoc" = ""

printf "checking that documentation directory was built... " >& 2
echo "$doc" >& 2
test -n "$doc"

printf "checking that documentation was generated... " >& 2
grep hello "$docDir/TestHaddock.html" > /dev/null
echo yes >& 2

printf "checking for hoogle index of package... " >& 2
grep hello "$docDir/test-haddock.txt" > /dev/null
echo yes >& 2

printf "checking for absence of documentation in another package... " >& 2
if [ -d "${toString noDocLibrary.haddockDir}" ]; then
echo "it exists - FAIL" >& 2
else
echo PASS >& 2
fi

printf "checking for absence of library package store paths in docs... " >& 2
if grep -R ${library} "$docDir" > /dev/null; then
echo "Found ${library} - FAIL" >& 2
exit 1
else
echo "PASS" >& 2
fi

touch $out
'';

meta.platforms = platforms.all;
} // { inherit packages pkgSet; }
23 changes: 23 additions & 0 deletions test/builder-haddock/plan.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
hackage:
{
packages = {
"ghc-prim".revision = hackage."ghc-prim"."0.5.2.0".revisions.default;
"stm".revision = hackage."stm"."2.4.5.1".revisions.default;
"rts".revision = hackage."rts"."1.0".revisions.default;
"base".revision = hackage."base"."4.11.1.0".revisions.default;
"array".revision = hackage."array"."0.5.2.0".revisions.default;
"integer-gmp".revision = hackage."integer-gmp"."1.0.2.0".revisions.default;
};
compiler = {
version = "8.4.4";
nix-name = "ghc844";
packages = {
"ghc-prim" = "0.5.2.0";
"stm" = "2.4.5.1";
"rts" = "1.0";
"base" = "4.11.1.0";
"array" = "0.5.2.0";
"integer-gmp" = "1.0.2.0";
};
};
}
15 changes: 15 additions & 0 deletions test/builder-haddock/test-haddock.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
cabal-version: 2.2
name: test-haddock
version: 0.1.0.0
license: NONE
author: Rodney Lorrimar
maintainer: [email protected]

library
exposed-modules: TestHaddock
other-modules: Paths_test_haddock
-- other-extensions:
build-depends: base ^>=4.11.1.0
, stm
-- hs-source-dirs:
default-language: Haskell2010
Loading