From e410a191a1e6cb041cc62d14d9823b91d054b41c Mon Sep 17 00:00:00 2001 From: Bas van Dijk Date: Wed, 30 Aug 2017 14:40:54 +0200 Subject: [PATCH] haskell: add the checkUnusedPackages function including docs --- doc/languages-frameworks/haskell.md | 56 ++++++++++++++++++++++++ pkgs/development/haskell-modules/lib.nix | 18 +++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/doc/languages-frameworks/haskell.md b/doc/languages-frameworks/haskell.md index 930bd2616156..8efc60f1e17a 100644 --- a/doc/languages-frameworks/haskell.md +++ b/doc/languages-frameworks/haskell.md @@ -867,6 +867,62 @@ use the following to get the `scientific` package build with `integer-simple`: nix-build -A haskell.packages.integer-simple.ghc802.scientific ``` +### Quality assurance + +The `haskell.lib` library includes a number of functions for checking for +various imperfections in Haskell packages. It's useful to apply these functions +to your own Haskell packages and integrate that in a Continuous Integration +server like [hydra](https://nixos.org/hydra/) to assure your packages maintain a +minimum level of quality. This section discusses some of these functions. + +#### buildStrictly + +Applying `haskell.lib.buildStrictly` to a Haskell package enables the `-Wall` +and `-Werror` GHC options to turn all warnings into build failures. Additionally +the source of your package is gotten from first invoking `cabal sdist` to ensure +all needed files are listed in the Cabal file. + +#### checkUnusedPackages + +Applying `haskell.lib.checkUnusedPackages` to a Haskell package invokes +the [packunused](http://hackage.haskell.org/package/packunused) tool on the +package. `packunused` complains when it finds packages listed as build-depends +in the Cabal file which are redundant. For example: + +``` +$ nix-build -E 'let pkgs = import {}; in pkgs.haskell.lib.checkUnusedPackages {} pkgs.haskellPackages.scientific' +these derivations will be built: + /nix/store/3lc51cxj2j57y3zfpq5i69qbzjpvyci1-scientific-0.3.5.1.drv +... +detected package components +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + - library + - testsuite(s): test-scientific + - benchmark(s): bench-scientific* + +(component names suffixed with '*' are not configured to be built) + +library +~~~~~~~ + +The following package dependencies seem redundant: + + - ghc-prim-0.5.0.0 + +testsuite(test-scientific) +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +no redundant packages dependencies found + +builder for ‘/nix/store/3lc51cxj2j57y3zfpq5i69qbzjpvyci1-scientific-0.3.5.1.drv’ failed with exit code 1 +error: build of ‘/nix/store/3lc51cxj2j57y3zfpq5i69qbzjpvyci1-scientific-0.3.5.1.drv’ failed +``` + +As you can see, `packunused` finds out that although the testsuite component has +no redundant dependencies the library component of `scientific-0.3.5.1` depends +on `ghc-prim` which is unused in the library. + ## Other resources - The Youtube video [Nix Loves Haskell](https://www.youtube.com/watch?v=BsBhi_r-OeE) diff --git a/pkgs/development/haskell-modules/lib.nix b/pkgs/development/haskell-modules/lib.nix index 43723b807741..6da19794f6f4 100644 --- a/pkgs/development/haskell-modules/lib.nix +++ b/pkgs/development/haskell-modules/lib.nix @@ -1,5 +1,5 @@ # TODO(@Ericson2314): Remove `pkgs` param, which is only used for -# `buildStackProject` and `justStaticExecutables` +# `buildStackProject`, `justStaticExecutables` and `checkUnusedPackages` { pkgs, lib }: rec { @@ -108,6 +108,22 @@ rec { buildStrictly = pkg: buildFromSdist (appendConfigureFlag pkg "--ghc-option=-Wall --ghc-option=-Werror"); + checkUnusedPackages = + { ignoreEmptyImports ? false + , ignoreMainModule ? false + , ignorePackages ? [] + } : drv : + overrideCabal (appendConfigureFlag drv "--ghc-option=-ddump-minimal-imports") (_drv: { + postBuild = with lib; + let args = concatStringsSep " " ( + optional ignoreEmptyImports "--ignore-empty-imports" ++ + optional ignoreMainModule "--ignore-main-module" ++ + map (pkg: "--ignore-package ${pkg}") ignorePackages + ); + in "${pkgs.haskellPackages.packunused}/bin/packunused" + + optionalString (args != "") " ${args}"; + }); + buildStackProject = pkgs.callPackage ./generic-stack-builder.nix { }; triggerRebuild = drv: i: overrideCabal drv (drv: { postUnpack = ": trigger rebuild ${toString i}"; });