From 73f3733a2f0d698db8f3354fd743577bd1b12e1c Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Wed, 30 Jan 2019 15:25:17 +1000 Subject: [PATCH 1/9] Add an "all" component --- builder/comp-builder.nix | 12 +++++++----- lib/default.nix | 20 +++++++++++++++++--- modules/package.nix | 9 +++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/builder/comp-builder.nix b/builder/comp-builder.nix index c497b16950..187c50f657 100644 --- a/builder/comp-builder.nix +++ b/builder/comp-builder.nix @@ -17,7 +17,7 @@ , preCheck ? null, postCheck ? null , preInstall ? null, postInstall ? null -, doCheck ? component.doCheck || componentId.ctype == "test" +, doCheck ? component.doCheck || haskellLib.isTest componentId , doCrossCheck ? component.doCrossCheck || false , dontPatchELF ? true , dontStrip ? true @@ -27,7 +27,9 @@ }: let - fullName = "${name}-${componentId.ctype}-${componentId.cname}"; + fullName = if haskellLib.isAll componentId + then "${name}-all" + else "${name}-${componentId.ctype}-${componentId.cname}"; flagsAndConfig = field: xs: lib.optionalString (xs != []) '' echo ${lib.concatStringsSep " " (map (x: "--${field}=${x}") xs)} >> $out/configure-flags @@ -122,7 +124,7 @@ let finalConfigureFlags = lib.concatStringsSep " " ( [ "--prefix=$out" - "${componentId.ctype}:${componentId.cname}" + "${haskellLib.componentTarget componentId}" "$(cat ${configFiles}/configure-flags)" # GHC "--with-ghc=${ghc.targetPrefix}ghc" @@ -217,12 +219,12 @@ in stdenv.mkDerivation ({ installPhase = '' runHook preInstall $SETUP_HS copy ${lib.concatStringsSep " " component.setupInstallFlags} - ${lib.optionalString (haskellLib.isLibrary componentId) '' + ${lib.optionalString (haskellLib.isLibrary componentId || haskellLib.isAll componentId) '' $SETUP_HS register --gen-pkg-config=${name}.conf ${ghc.targetPrefix}ghc-pkg -v0 init $out/package.conf.d ${ghc.targetPrefix}ghc-pkg -v0 --package-db ${configFiles}/package.conf.d -f $out/package.conf.d register ${name}.conf ''} - ${lib.optionalString (componentId.ctype == "test") '' + ${lib.optionalString (haskellLib.isTest componentId || haskellLib.isAll componentId) '' mkdir -p $out/${name} if [ -f "dist/build/${componentId.cname}/${componentId.cname}" ]; then cp dist/build/${componentId.cname}/${componentId.cname} $out/${name}/ diff --git a/lib/default.nix b/lib/default.nix index 0dc05a94f7..99862f4cd4 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -3,6 +3,8 @@ with haskellLib; { + # Within the package components, these are the attribute names of + # nested attrsets. subComponentTypes = [ "sublibs" "foreignlibs" @@ -66,13 +68,25 @@ with haskellLib; applyComponents = f: config: let comps = config.components; - libComp = lib.mapAttrs (cname: f {ctype="lib"; cname=config.package.identifier.name;}) (removeAttrs comps subComponentTypes); + applyLibrary = cname: f { cname = config.package.identifier.name; ctype = "lib"; }; + applySubComp = ctype: cname: f { inherit cname; ctype = componentPrefix.${ctype}; }; + applyAllComp = f { cname = config.package.identifier.name; ctype = "all"; }; + libComp = lib.mapAttrs applyLibrary (removeAttrs comps (subComponentTypes ++ [ "all" ])); subComps = lib.mapAttrs - (ctype: lib.mapAttrs (cname: f {inherit cname; ctype=componentPrefix.${ctype};})) + (ctype: lib.mapAttrs (applySubComp ctype)) (builtins.intersectAttrs (lib.genAttrs subComponentTypes (_: null)) comps); - in subComps // libComp; + allComp = { all = applyAllComp comps.all; }; + in subComps // libComp // allComp; isLibrary = componentId: componentId.ctype == "lib"; + isAll = componentId: componentId.ctype == "all"; + isTest = componentId: componentId.ctype == "test"; + + # Format a componentId as it should appear as a target on the + # command line of the setup script. + componentTarget = componentId: + if componentId.ctype == "all" then "" + else "${componentId.ctype}:${componentId.cname}"; # 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. diff --git a/modules/package.nix b/modules/package.nix index 2b2a2a8d78..ae84ddbecd 100644 --- a/modules/package.nix +++ b/modules/package.nix @@ -173,6 +173,15 @@ in { type = attrsOf (componentType false); default = {}; }; + all = mkOption { + type = componentType false; + default = let + componentTypes = [ "library" "sublibs" "foreignlibs" "exes" "tests" "benchmarks" ]; + in { + depends = mkMerge (map (c: config.components.${c}.depends or []) componentTypes); + }; + defaultText = "The merged dependencies of all other components"; + }; }; name = mkOption { From 97a9034d4f869c0150db9c693e5312214dd3d393 Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Wed, 30 Jan 2019 15:25:33 +1000 Subject: [PATCH 2/9] tests: add build test of "all" component --- test/cabal-simple/default.nix | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/cabal-simple/default.nix b/test/cabal-simple/default.nix index 74a4e7d802..d5d8fdd8e6 100644 --- a/test/cabal-simple/default.nix +++ b/test/cabal-simple/default.nix @@ -33,13 +33,18 @@ in printf "checking whether executable runs... " >& 2 $exe - # fixme: linux-specific printf "checking that executable is dynamically linked to system libraries... " >& 2 '' + pkgs.lib.optionalString pkgs.stdenv.isLinux '' ldd $exe | grep libpthread '' + pkgs.lib.optionalString pkgs.stdenv.isDarwin '' otool -L $exe |grep .dylib '' + '' + + printf "Checking that \"all\" component has the programs... " >& 2 + all_exe="${packages.cabal-simple.components.all}/bin/cabal-simple" + test -f "$all_exe" + echo "$all_exe" >& 2 + touch $out ''; From 20226fa294f67ea58424300d84954570c5fd878e Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Wed, 30 Jan 2019 15:26:16 +1000 Subject: [PATCH 3/9] builder: Add nix-shell development environments --- builder/comp-builder.nix | 58 +++++++++++++++++---- builder/default.nix | 7 ++- builder/with-package-wrapper.nix | 77 ++++++++++++++++++++++++++++ doc/removing-with-package-wrapper.md | 66 ++++++++++++++++++++++++ modules/component-driver.nix | 9 ++++ modules/package.nix | 4 ++ 6 files changed, 208 insertions(+), 13 deletions(-) create mode 100644 builder/with-package-wrapper.nix create mode 100644 doc/removing-with-package-wrapper.md diff --git a/builder/comp-builder.nix b/builder/comp-builder.nix index 187c50f657..70c627ae92 100644 --- a/builder/comp-builder.nix +++ b/builder/comp-builder.nix @@ -1,4 +1,4 @@ -{ stdenv, buildPackages, ghc, lib, pkgconfig, writeText, runCommand, haskellLib, nonReinstallablePkgs }: +{ stdenv, buildPackages, ghc, lib, pkgconfig, writeText, runCommand, haskellLib, nonReinstallablePkgs, withPackage }: { componentId , component @@ -16,6 +16,7 @@ , preBuild ? null, postBuild ? null , preCheck ? null, postCheck ? null , preInstall ? null, postInstall ? null +, shellHook ? null , doCheck ? component.doCheck || haskellLib.isTest componentId , doCrossCheck ? component.doCrossCheck || false @@ -46,18 +47,30 @@ let in map ({val,...}: val) closure; exactDep = pdbArg: p: '' - if id=$(${ghc.targetPrefix}ghc-pkg -v0 ${pdbArg} field ${p} id --simple-output); then + if id=$(target-pkg ${pdbArg} field ${p} id --simple-output); then echo "--dependency=${p}=$id" >> $out/configure-flags fi - if ver=$(${ghc.targetPrefix}ghc-pkg -v0 ${pdbArg} field ${p} version --simple-output); then + if ver=$(target-pkg ${pdbArg} field ${p} version --simple-output); then echo "constraint: ${p} == $ver" >> $out/cabal.config echo "constraint: ${p} installed" >> $out/cabal.config fi ''; + envDep = pdbArg: p: '' + if id=$(target-pkg ${pdbArg} field ${p} id --simple-output); then + echo "package-id $id" >> $out/ghc-environment + fi + ''; + configFiles = runCommand "${fullName}-config" { nativeBuildInputs = [ghc]; } ('' mkdir -p $out - ${ghc.targetPrefix}ghc-pkg -v0 init $out/package.conf.d + + # Calls ghc-pkg for the target platform + target-pkg() { + ${ghc.targetPrefix}ghc-pkg "$@" + } + + target-pkg init $out/package.conf.d ${lib.concatStringsSep "\n" (lib.mapAttrsToList flagsAndConfig { "extra-lib-dirs" = map (p: "${lib.getLib p}/lib") component.libs; @@ -69,11 +82,11 @@ let # Note: we need to use --global-package-db with ghc-pkg to prevent it # from looking into the implicit global package db when registering the package. ${lib.concatMapStringsSep "\n" (p: '' - ${ghc.targetPrefix}ghc-pkg -v0 describe ${p} | ${ghc.targetPrefix}ghc-pkg -v0 --force --global-package-db $out/package.conf.d register - || true + target-pkg describe ${p} | target-pkg --force --global-package-db $out/package.conf.d register - || true '') nonReinstallablePkgs} ${lib.concatMapStringsSep "\n" (p: '' - ${ghc.targetPrefix}ghc-pkg -v0 --package-db ${p}/package.conf.d dump | ${ghc.targetPrefix}ghc-pkg -v0 --force --package-db $out/package.conf.d register - + target-pkg --package-db ${p}/package.conf.d dump | target-pkg --force --package-db $out/package.conf.d register - '') flatDepends} # Note: we pass `clear` first to ensure that we never consult the implicit global package db. @@ -81,6 +94,14 @@ let echo ${lib.concatStringsSep " " (lib.mapAttrsToList (fname: val: "--flags=${lib.optionalString (!val) "-" + fname}") flags)} >> $out/configure-flags + # Provide a GHC environment file + cat > $out/ghc-environment <> $out/configure-flags echo "allow-newer: ${package.identifier.name}:*" >> $out/cabal.config @@ -117,9 +138,9 @@ let sed -i "s,dynamic-library-dirs: .*,dynamic-library-dirs: $dynamicLinksDir," $f done '' + '' - ${ghc.targetPrefix}ghc-pkg -v0 --package-db $out/package.conf.d recache + target-pkg --package-db $out/package.conf.d recache '' + '' - ${ghc.targetPrefix}ghc-pkg -v0 --package-db $out/package.conf.d check + target-pkg --package-db $out/package.conf.d check ''); finalConfigureFlags = lib.concatStringsSep " " ( @@ -147,6 +168,16 @@ let ++ component.configureFlags ); + executableToolDepends = lib.concatMap (c: if c.isHaskell or false + then builtins.attrValues (c.components.exes or {}) + else [c]) component.build-tools; + + # Unfortunately, we need to wrap ghc commands for cabal builds to + # work in the nix-shell. See ../doc/removing-with-package-wrapper.md. + shellWrappers = withPackage { + inherit package configFiles; + }; + in stdenv.mkDerivation ({ name = fullName; @@ -156,6 +187,7 @@ in stdenv.mkDerivation ({ inherit (package) identifier; config = component; inherit configFiles; + env = shellWrappers; }; meta = { @@ -169,6 +201,7 @@ in stdenv.mkDerivation ({ }; CABAL_CONFIG = configFiles + /cabal.config; + GHC_ENVIRONMENT = configFiles + /ghc-environment; LANG = "en_US.UTF-8"; # GHC needs the locale configured during the Haddock phase. LC_ALL = "en_US.UTF-8"; @@ -181,9 +214,7 @@ in stdenv.mkDerivation ({ nativeBuildInputs = [ghc] ++ lib.optional (component.pkgconfig != []) pkgconfig - ++ lib.concatMap (c: if c.isHaskell or false - then builtins.attrValues (c.components.exes or {}) - else [c]) component.build-tools; + ++ executableToolDepends; SETUP_HS = setup + /bin/Setup; @@ -235,6 +266,11 @@ in stdenv.mkDerivation ({ ''} runHook postInstall ''; + + shellHook = '' + export PATH="${shellWrappers}/bin:$PATH" + ${toString shellHook} + ''; } # 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; } diff --git a/builder/default.nix b/builder/default.nix index fda1e27438..a049745ebd 100644 --- a/builder/default.nix +++ b/builder/default.nix @@ -1,4 +1,4 @@ -{ pkgs, buildPackages, stdenv, lib, haskellLib, ghc, buildGHC, fetchurl, writeText, runCommand, pkgconfig, nonReinstallablePkgs }: +{ pkgs, buildPackages, stdenv, lib, haskellLib, ghc, buildGHC, fetchurl, writeText, runCommand, pkgconfig, nonReinstallablePkgs, withPackage }: { flags , package @@ -22,6 +22,8 @@ , preInstall , postInstall +, shellHook + , ... }@config: @@ -67,11 +69,12 @@ let ''; }; - comp-builder = haskellLib.weakCallPackage pkgs ./comp-builder.nix { inherit ghc haskellLib nonReinstallablePkgs; }; + comp-builder = haskellLib.weakCallPackage pkgs ./comp-builder.nix { inherit ghc haskellLib nonReinstallablePkgs withPackage; }; 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 + shellHook ; }; diff --git a/builder/with-package-wrapper.nix b/builder/with-package-wrapper.nix new file mode 100644 index 0000000000..19c73a5135 --- /dev/null +++ b/builder/with-package-wrapper.nix @@ -0,0 +1,77 @@ +# This is a simplified version of the ghcWithPackages wrapper in +# nixpkgs, adapted to work with the package database of a single +# component. +{ lib, stdenv, ghc, runCommand, lndir, makeWrapper +}: + +{ package +, configFiles +, postBuild ? "" +}: + +let + isGhcjs = ghc.isGhcjs or false; + ghcCommand' = if isGhcjs then "ghcjs" else "ghc"; + ghcCommand = "${ghc.targetPrefix}${ghcCommand'}"; + ghcCommandCaps= lib.toUpper ghcCommand'; + libDir = "$out/lib/${ghcCommand}-${ghc.version}"; + docDir = "$out/share/doc/ghc/html"; + packageCfgDir = "${libDir}/package.conf.d"; + +in runCommand "${ghc.name}-with-${package.identifier.name}" { + preferLocalBuild = true; + passthru = { + inherit (ghc) version meta; + baseGhc = ghc; + inherit package; + }; +} ( + '' + . ${makeWrapper}/nix-support/setup-hook + + # Start with a ghc... + mkdir -p $out/bin + ${lndir}/bin/lndir -silent ${ghc} $out + + # ...and replace package database with the one from target package config. + rm -rf ${libDir} + mkdir -p ${libDir} + ln -s ${configFiles}/package.conf.d ${packageCfgDir} + + # Wrap compiler executables with correct env variables. + # The NIX_ variables are used by the patched Paths_ghc module. + # The GHC_ENVIRONMENT variable forces ghc to use the build + # dependencies of the component. + + for prg in ${ghcCommand} ${ghcCommand}i ${ghcCommand}-${ghc.version} ${ghcCommand}i-${ghc.version} runghc runhaskell; do + if [[ -x "${ghc}/bin/$prg" ]]; then + rm -f $out/bin/$prg + makeWrapper ${ghc}/bin/$prg $out/bin/$prg \ + --set "NIX_${ghcCommandCaps}" "$out/bin/${ghcCommand}" \ + --set "NIX_${ghcCommandCaps}PKG" "$out/bin/${ghcCommand}-pkg" \ + --set "NIX_${ghcCommandCaps}_DOCDIR" "${docDir}" \ + --set "NIX_${ghcCommandCaps}_LIBDIR" "${libDir}" \ + --set "${ghcCommandCaps}_ENVIRONMENT" "${configFiles}/ghc-environment" + fi + done + + # Point ghc-pkg to the package database of the component using the + # GHC_PACKAGE_PATH variable. + + for prg in ${ghcCommand}-pkg ${ghcCommand}-pkg-${ghc.version}; do + if [[ -x "${ghc}/bin/$prg" ]]; then + rm -f $out/bin/$prg + makeWrapper ${ghc}/bin/$prg $out/bin/$prg \ + --set "${ghcCommandCaps}_PACKAGE_PATH" "${configFiles}/package.conf.d" + fi + done + + # fixme: check if this is needed + # haddock was referring to the base ghc, https://github.com/NixOS/nixpkgs/issues/36976 + if [[ -x "${ghc}/bin/haddock" ]]; then + rm -f $out/bin/haddock + makeWrapper ${ghc}/bin/haddock $out/bin/haddock \ + --set "NIX_${ghcCommandCaps}_LIBDIR" "${libDir}" + fi + '' +) diff --git a/doc/removing-with-package-wrapper.md b/doc/removing-with-package-wrapper.md new file mode 100644 index 0000000000..f4af02ea39 --- /dev/null +++ b/doc/removing-with-package-wrapper.md @@ -0,0 +1,66 @@ +# `ghcWithPackages` wrapper removal + +The current [Nixpkgs Haskell infrastructure][nixpkgs-haskell] and `haskell.nix` both +provide a `ghcWithPackages` derivation which contains shell script +wrappers that wrap `ghc` and `ghc-pkg`. + +In the Nixpkgs Haskell infrastructure, the wrapper scripts are used +for building Haskell packages. However, in `haskell.nix`, the wrappers +are only used for development environments. + +The wrapper scripts provide a `ghc` command that "knows" about the +package set and has all Haskell package dependencies available to it. + +We would like to remove the wrapper scripts, but it's currently not +possible to configure all build tools using environment variables +alone. + +## Plain `ghc` + +When using `ghc` or `ghci` by itself, the `GHC_ENVIRONMENT` variable +can point to a configuration file containing an exact package +set. This works quite well. + +## `ghc-pkg` + +The package tool `ghc-pkg` does not recognize `GHC_ENVIRONMENT`, but +does recognize a `GHC_PACKAGE_PATH` pointing to a `package.conf.d`. + +This works well. However, the `cabal` command will refuse to start if +`GHC_PACKAGE_PATH` is set. + +## `Setup.hs` + +When invoking `Setup.hs configure`, the package database is provided +with the `--package-db` argument and exact dependencies in the package +set can be provided as `--dependency` arguments. + +The `haskell.nix` component builder uses `Setup.hs` with these +command-line options to build Haskell packages. + +## `cabal new-build` + +Cabal-install will observe the `CABAL_CONFIG` environment variable, +which points to a cabal config file. This config file can provide a +`package-db` value, but it can't specify exact versions of packages. + +Cabal is designed to solve dependencies, not simply take the package +set which is given to it. + +Therefore, `cabal` does not use `GHC_ENVIRONMENT`, but instead creates +its own environment file. It will not accept `--dependency` arguments. + +As far as I know, the best way to force `cabal` to take a pre-computed +package set is to use a `new-freeze` file. However there is no +environment variable (or config file entry) which can specify a path +to a freeze file. + +Specifying a `package-db` path in the cabal config file is not enough +for it to successfully resolve dependencies. + +As mentioned before, `cabal` does not work when `GHC_PACKAGE_PATH` is +set. The best way to work around this is to wrap `ghc` and `ghc-pkg` +in shell scripts. + + +[nixpkgs-haskell]: https://nixos.org/nixpkgs/manual/#users-guide-to-the-haskell-infrastructure diff --git a/modules/component-driver.nix b/modules/component-driver.nix index 6e10f7eab3..316a343954 100644 --- a/modules/component-driver.nix +++ b/modules/component-driver.nix @@ -6,7 +6,16 @@ let ghc = config.ghc.package; buildGHC = buildModules.config.ghc.package; inherit (config) nonReinstallablePkgs; + inherit withPackage; }; + + withPackage = import ../builder/with-package-wrapper.nix { + inherit lib; + inherit (pkgs) stdenv runCommand makeWrapper; + inherit (pkgs.xorg) lndir; + ghc = config.ghc.package; + }; + in { diff --git a/modules/package.nix b/modules/package.nix index ae84ddbecd..ca3c411a32 100644 --- a/modules/package.nix +++ b/modules/package.nix @@ -270,6 +270,10 @@ in { type = nullOr string; default = null; }; + shellHook = mkOption { + type = nullOr string; + default = null; + }; doCheck = mkOption { type = bool; default = false; From 8642facf1e11ec00be760404e1883d0aa781d1ca Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Wed, 30 Jan 2019 15:26:54 +1000 Subject: [PATCH 4/9] tests: Add unit tests for library functions --- test/default.nix | 6 ++++++ test/unit.nix | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 test/unit.nix diff --git a/test/default.nix b/test/default.nix index 1f8cd49035..0b0b5faf87 100644 --- a/test/default.nix +++ b/test/default.nix @@ -13,9 +13,15 @@ let # The new Haskell infra applied to nix representation of Hackage haskell = import ../. hackage; + haskellLib = let hl = import ../lib { inherit lib; haskellLib = hl; }; in hl; + in { cabal-simple = callPackage ./cabal-simple { inherit haskell; }; cabal-22 = callPackage ./cabal-22 { inherit haskell; }; + + # Run unit tests with: nix-instantiate --eval --strict -A unit + # An empty list means success. + unit = callPackage ./unit.nix { inherit haskellLib; }; } ## possible test cases diff --git a/test/unit.nix b/test/unit.nix new file mode 100644 index 0000000000..1f0531866b --- /dev/null +++ b/test/unit.nix @@ -0,0 +1,54 @@ +{ lib, haskellLib }: + +let + emptyConfig = { + components = { + benchmarks = { }; + exes = { }; + foreignlibs = { }; + library = "library"; + sublibs = { }; + tests = { }; + all = "all"; + }; + package.identifier.name = "empty"; + }; + + componentsConfig = { + components = { + benchmarks = { bbb = "bbb"; }; + exes = { eee = "eee"; }; + foreignlibs = { fff = "fff"; }; + library = "library"; + sublibs = { }; + tests = { ttt = "ttt"; }; + all = "all"; + }; + package.identifier.name = "nnn"; + }; + +in +lib.runTests { + # identity function for applyComponents + test-applyComponents-id = { + expr = haskellLib.applyComponents (componentId: component: component) emptyConfig; + expected = emptyConfig.components; + }; + + # map a component to its component name and check these are correct + test-applyComponents-library = { + expr = haskellLib.applyComponents (componentId: component: componentId.cname) emptyConfig; + expected = emptyConfig.components // { library = "empty"; all = "empty"; }; + }; + + test-applyComponents-components = { + expr = haskellLib.applyComponents (componentId: component: component) componentsConfig; + expected = componentsConfig.components; + }; + + # testing that the tests work + testId = { + expr = lib.id 1; + expected = 1; + }; +} From ce0f5e03930affddc25d75044478fc430897c121 Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Wed, 30 Jan 2019 15:28:02 +1000 Subject: [PATCH 5/9] tests: Add test cases for dev environments --- test/default.nix | 1 + test/with-packages/Point.hs | 12 +++ test/with-packages/Setup.hs | 2 + test/with-packages/TestWithPackages.hs | 6 ++ test/with-packages/default.nix | 68 ++++++++++++++ test/with-packages/plan.nix | 99 +++++++++++++++++++++ test/with-packages/test-with-packages.cabal | 15 ++++ test/with-packages/test-with-packages.nix | 36 ++++++++ 8 files changed, 239 insertions(+) create mode 100644 test/with-packages/Point.hs create mode 100644 test/with-packages/Setup.hs create mode 100644 test/with-packages/TestWithPackages.hs create mode 100644 test/with-packages/default.nix create mode 100644 test/with-packages/plan.nix create mode 100644 test/with-packages/test-with-packages.cabal create mode 100644 test/with-packages/test-with-packages.nix diff --git a/test/default.nix b/test/default.nix index 0b0b5faf87..506dbadcc1 100644 --- a/test/default.nix +++ b/test/default.nix @@ -18,6 +18,7 @@ let in { cabal-simple = callPackage ./cabal-simple { inherit haskell; }; cabal-22 = callPackage ./cabal-22 { inherit haskell; }; + with-packages = callPackage ./with-packages { inherit haskell; }; # Run unit tests with: nix-instantiate --eval --strict -A unit # An empty list means success. diff --git a/test/with-packages/Point.hs b/test/with-packages/Point.hs new file mode 100644 index 0000000000..25b583c10e --- /dev/null +++ b/test/with-packages/Point.hs @@ -0,0 +1,12 @@ +{-# LANGUAGE TemplateHaskell #-} +module Main where + +import Control.Lens + +data Point = Point { _x :: Double, _y :: Double } +makeLenses ''Point + +main :: IO () +main = print (point^.x + point^.y) + where + point = Point { _x = 40.0, _y = 2.0 } diff --git a/test/with-packages/Setup.hs b/test/with-packages/Setup.hs new file mode 100644 index 0000000000..9a994af677 --- /dev/null +++ b/test/with-packages/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/test/with-packages/TestWithPackages.hs b/test/with-packages/TestWithPackages.hs new file mode 100644 index 0000000000..f8852cd8a7 --- /dev/null +++ b/test/with-packages/TestWithPackages.hs @@ -0,0 +1,6 @@ +-- | Haddock test stuff +module TestWithPackages (hello) where + +-- | Standard hello text. +hello :: String +hello = "Hello, world!" diff --git a/test/with-packages/default.nix b/test/with-packages/default.nix new file mode 100644 index 0000000000..b24fb1f5d5 --- /dev/null +++ b/test/with-packages/default.nix @@ -0,0 +1,68 @@ +{ 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-with-packages.cabal > test-with-packages.nix + pkg-def = import ./plan.nix; + pkg-def-overlays = [ + { test-with-packages = ./test-with-packages.nix; } + ]; + modules = [ + # overrides to fix the build + { + packages.transformers-compat.components.library.doExactConfig = true; + } + ]; + }; + + packages = pkgSet.config.hsPkgs; + + # Add cabal as a buildInput for a haskell derivation. Useful for nix-shell. + addCabalInstall = drv: drv.overrideAttrs (oldAttrs: { + buildInputs = (oldAttrs.buildInputs or []) ++ [ pkgs.cabal-install ]; + }); + +in + stdenv.mkDerivation { + name = "with-packages-test"; + + buildCommand = let + package = packages.test-with-packages; + inherit (package.components) library; + in '' + ######################################################################## + # test with-packages + + printf "checking that the 'all' component works... " >& 2 + echo ${package.components.all} + # echo >& 2 + + printf "checking that the package env has the dependencies... " >& 2 + ${package.components.all.env}/bin/runghc ${./Point.hs} + echo >& 2 + + printf "checking that components.library.env has the dependencies... " >& 2 + ${library.env}/bin/runghc ${./Point.hs} + # echo >& 2 + + touch $out + ''; + + meta.platforms = platforms.all; +} // { + # Used for debugging with nix repl + inherit packages pkgSet; + + # Used for testing externally with nix-shell (../tests.sh). + # This just adds cabal-install to the existing shells. + test-shell = addCabalInstall packages.test-with-packages.components.all; +} diff --git a/test/with-packages/plan.nix b/test/with-packages/plan.nix new file mode 100644 index 0000000000..49823506b8 --- /dev/null +++ b/test/with-packages/plan.nix @@ -0,0 +1,99 @@ +hackage: + { + packages = { + "void".revision = hackage."void"."0.7.2".revisions.default; + "semigroupoids".revision = hackage."semigroupoids"."5.2.2".revisions.default; + "free".revision = hackage."free"."5.0.2".revisions.default; + "exceptions".revision = hackage."exceptions"."0.10.0".revisions.default; + "binary".revision = hackage."binary"."0.8.5.1".revisions.default; + "ghc-prim".revision = hackage."ghc-prim"."0.5.2.0".revisions.default; + "bifunctors".revision = hackage."bifunctors"."5.5.3".revisions.default; + "stm".revision = hackage."stm"."2.4.5.1".revisions.default; + "mtl".revision = hackage."mtl"."2.2.2".revisions.default; + "rts".revision = hackage."rts"."1.0".revisions.default; + "adjunctions".revision = hackage."adjunctions"."4.4".revisions.default; + "invariant".revision = hackage."invariant"."0.5.1".revisions.default; + "distributive".revision = hackage."distributive"."0.5.3".revisions.default; + "parallel".revision = hackage."parallel"."3.2.2.0".revisions.default; + "deepseq".revision = hackage."deepseq"."1.4.3.0".revisions.default; + "semigroups".revision = hackage."semigroups"."0.18.5".revisions.default; + "transformers-compat".revision = hackage."transformers-compat"."0.6.2".revisions.default; + "template-haskell".revision = hackage."template-haskell"."2.13.0.0".revisions.default; + "vector".revision = hackage."vector"."0.12.0.1".revisions.default; + "call-stack".revision = hackage."call-stack"."0.1.0".revisions.default; + "primitive".revision = hackage."primitive"."0.6.3.0".revisions.default; + "profunctors".revision = hackage."profunctors"."5.2.2".revisions.default; + "tagged".revision = hackage."tagged"."0.8.5".revisions.default; + "lens".revision = hackage."lens"."4.16.1".revisions.default; + "containers".revision = hackage."containers"."0.5.11.0".revisions.default; + "reflection".revision = hackage."reflection"."2.1.4".revisions.default; + "bytestring".revision = hackage."bytestring"."0.10.8.2".revisions.default; + "StateVar".revision = hackage."StateVar"."1.1.1.1".revisions.default; + "contravariant".revision = hackage."contravariant"."1.4.1".revisions.default; + "text".revision = hackage."text"."1.2.3.1".revisions.default; + "unordered-containers".revision = hackage."unordered-containers"."0.2.9.0".revisions.default; + "base".revision = hackage."base"."4.11.1.0".revisions.default; + "comonad".revision = hackage."comonad"."5.0.4".revisions.default; + "transformers".revision = hackage."transformers"."0.5.5.0".revisions.default; + "hashable".revision = hackage."hashable"."1.2.7.0".revisions.default; + "transformers-base".revision = hackage."transformers-base"."0.4.5.2".revisions.default; + "filepath".revision = hackage."filepath"."1.4.2".revisions.default; + "kan-extensions".revision = hackage."kan-extensions"."5.2".revisions.default; + "pretty".revision = hackage."pretty"."1.1.3.6".revisions.default; + "ghc-boot-th".revision = hackage."ghc-boot-th"."8.4.4".revisions.default; + "base-orphans".revision = hackage."base-orphans"."0.7".revisions.default; + "th-abstraction".revision = hackage."th-abstraction"."0.2.8.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 = { + "void" = "0.7.2"; + "semigroupoids" = "5.2.2"; + "free" = "5.0.2"; + "exceptions" = "0.10.0"; + "binary" = "0.8.5.1"; + "ghc-prim" = "0.5.2.0"; + "bifunctors" = "5.5.3"; + "stm" = "2.4.5.1"; + "mtl" = "2.2.2"; + "rts" = "1.0"; + "adjunctions" = "4.4"; + "invariant" = "0.5.1"; + "distributive" = "0.5.3"; + "parallel" = "3.2.2.0"; + "deepseq" = "1.4.3.0"; + "semigroups" = "0.18.5"; + "transformers-compat" = "0.6.2"; + "template-haskell" = "2.13.0.0"; + "vector" = "0.12.0.1"; + "call-stack" = "0.1.0"; + "primitive" = "0.6.3.0"; + "profunctors" = "5.2.2"; + "tagged" = "0.8.5"; + "lens" = "4.16.1"; + "containers" = "0.5.11.0"; + "reflection" = "2.1.4"; + "bytestring" = "0.10.8.2"; + "StateVar" = "1.1.1.1"; + "contravariant" = "1.4.1"; + "text" = "1.2.3.1"; + "unordered-containers" = "0.2.9.0"; + "base" = "4.11.1.0"; + "comonad" = "5.0.4"; + "transformers" = "0.5.5.0"; + "hashable" = "1.2.7.0"; + "transformers-base" = "0.4.5.2"; + "filepath" = "1.4.2"; + "kan-extensions" = "5.2"; + "pretty" = "1.1.3.6"; + "ghc-boot-th" = "8.4.4"; + "base-orphans" = "0.7"; + "th-abstraction" = "0.2.8.0"; + "array" = "0.5.2.0"; + "integer-gmp" = "1.0.2.0"; + }; + }; + } diff --git a/test/with-packages/test-with-packages.cabal b/test/with-packages/test-with-packages.cabal new file mode 100644 index 0000000000..b2b416358b --- /dev/null +++ b/test/with-packages/test-with-packages.cabal @@ -0,0 +1,15 @@ +cabal-version: 2.2 +name: test-with-packages +version: 0.1.0.0 +license: NONE +author: Rodney Lorrimar +maintainer: rodney.lorrimar@iohk.io + +library + exposed-modules: TestWithPackages + -- other-modules: + -- other-extensions: + build-depends: base ^>=4.11.1.0 + , lens + -- hs-source-dirs: + default-language: Haskell2010 diff --git a/test/with-packages/test-with-packages.nix b/test/with-packages/test-with-packages.nix new file mode 100644 index 0000000000..9b2a96953f --- /dev/null +++ b/test/with-packages/test-with-packages.nix @@ -0,0 +1,36 @@ +{ system +, compiler +, flags +, pkgs +, hsPkgs +, pkgconfPkgs +, ... }: + { + flags = {}; + package = { + specVersion = "2.2"; + identifier = { + name = "test-with-packages"; + version = "0.1.0.0"; + }; + license = "NONE"; + copyright = ""; + maintainer = "rodney.lorrimar@iohk.io"; + author = "Rodney Lorrimar"; + homepage = ""; + url = ""; + synopsis = ""; + description = ""; + buildType = "Simple"; + }; + components = { + "library" = { + depends = [ + (hsPkgs.base) + (hsPkgs.lens) + ]; + }; + }; + } // rec { + src = pkgs.lib.mkDefault ./.; + } From a8adc34e27c23c6b297bda8b720a64b42e121ef1 Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Wed, 30 Jan 2019 15:36:08 +1000 Subject: [PATCH 6/9] tests: add shell script which runs all tests --- .travis.yml | 6 +----- test/tests.sh | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) create mode 100755 test/tests.sh diff --git a/.travis.yml b/.travis.yml index 9e6bf5f2b9..77d953e77f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,8 +19,4 @@ before_script: script: - nix-env -if https://github.com/cachix/cachix/tarball/master --extra-substituters https://cachix.cachix.org --trusted-public-keys 'cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= cachix.cachix.org-1:eWNHQldwUO7G2VkjpnjDbWwy4KQ/HNxht7H4SSoMckM=' - cachix use nix-tools -- nix-build - -I nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/${CHANNEL}.tar.gz - test/default.nix - --cores 0 - -j2 +- NIX_PATH=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/${CHANNEL}.tar.gz NIX_BUILD_ARGS="--cores 0 --max-jobs 2" ./test/tests.sh diff --git a/test/tests.sh b/test/tests.sh new file mode 100755 index 0000000000..ed3a1643b0 --- /dev/null +++ b/test/tests.sh @@ -0,0 +1,39 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i bash -p bash jq nix + +set -euo pipefail + +NIX_BUILD_ARGS="${NIX_BUILD_ARGS:-}" + +cd $(dirname $0) + +printf "*** Running the nix-build tests...\n" >& 2 +nix-build $NIX_BUILD_ARGS --no-out-link --keep-going ./default.nix +echo >& 2 + +printf "*** Running the unit tests... " >& 2 +res=$(nix-instantiate --eval --json --strict ./default.nix -A unit) +num_failed=$(jq length <<< "$res") +if [ $num_failed -eq 0 ]; then + printf "PASSED\n" >& 2 +else + printf "$num_failed FAILED\n" >& 2 + jq . <<< "$res" + exit 1 +fi + +printf "*** Checking that a nix-shell works for runghc...\n" >& 2 +nix-shell $NIX_BUILD_ARGS \ + --pure ./default.nix \ + -A with-packages.test-shell \ + --run 'runghc with-packages/Point.hs' +echo >& 2 + +printf "*** Checking that a nix-shell works for cabal...\n" >& 2 +nix-shell $NIX_BUILD_ARGS \ + --pure ./default.nix \ + -A with-packages.test-shell \ + --run 'echo CABAL_CONFIG=$CABAL_CONFIG && type -p ghc && cd with-packages && rm -rf dist-newstyle .ghc-environment* && cabal new-build' +echo >& 2 + +printf "\n*** Finished successfully\n" >& 2 From 1a86a645e7cf799c99e67d7b3807b8f53ea71f65 Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Thu, 31 Jan 2019 12:39:56 +1000 Subject: [PATCH 7/9] tests: update hackage.nix revision --- test/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/default.nix b/test/default.nix index 506dbadcc1..1015e047bf 100644 --- a/test/default.nix +++ b/test/default.nix @@ -6,8 +6,8 @@ let # all packages from hackage as nix expressions hackage = import (fetchFromGitHub { owner = "angerman"; repo = "hackage.nix"; - rev = "66c28064da46525711722b75b4adb2ac878897d3"; - sha256 = "12ffzzjgirwzha3ngxbniccgn19406iryxspq19kgi4kz9lz6bpr"; + rev = "5223a45e08b1b0d738fdd292b39e49f39f21536f"; + sha256 = "09r662kn2qs444fmqni9jamaxnrk9jrg6whqmxbwhfgd5vy3yynq"; name = "hackage-exprs-source"; }); # The new Haskell infra applied to nix representation of Hackage From 78629caa98836d8a8547d09b41468ec80ac97415 Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Thu, 31 Jan 2019 12:40:25 +1000 Subject: [PATCH 8/9] tests: add more dependencies to the cabal-simple project --- test/cabal-22/default.nix | 1 - test/cabal-simple/cabal-simple.cabal | 5 ++ test/cabal-simple/cabal-simple.nix | 13 +++- test/cabal-simple/default.nix | 2 +- test/cabal-simple/plan.nix | 92 ++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 4 deletions(-) diff --git a/test/cabal-22/default.nix b/test/cabal-22/default.nix index 31bcede296..31cd0ecc25 100644 --- a/test/cabal-22/default.nix +++ b/test/cabal-22/default.nix @@ -31,7 +31,6 @@ in printf "checking whether executable runs... " >& 2 "$exe" - # fixme: linux-specific printf "checking that executable is dynamically linked to system libraries... " >& 2 '' + pkgs.lib.optionalString pkgs.stdenv.isLinux '' ldd $exe | grep libpthread diff --git a/test/cabal-simple/cabal-simple.cabal b/test/cabal-simple/cabal-simple.cabal index 6d3fd6277c..49a9aa559b 100644 --- a/test/cabal-simple/cabal-simple.cabal +++ b/test/cabal-simple/cabal-simple.cabal @@ -19,6 +19,9 @@ library -- other-modules: -- other-extensions: build-depends: base >=4.11 && <4.12 + , extra + , safe + , aeson -- hs-source-dirs: default-language: Haskell2010 @@ -27,5 +30,7 @@ executable cabal-simple -- other-modules: -- other-extensions: build-depends: base >=4.11 && <4.12 + , extra + , optparse-applicative -- hs-source-dirs: default-language: Haskell2010 diff --git a/test/cabal-simple/cabal-simple.nix b/test/cabal-simple/cabal-simple.nix index d5d82687cc..220111fc3f 100644 --- a/test/cabal-simple/cabal-simple.nix +++ b/test/cabal-simple/cabal-simple.nix @@ -25,11 +25,20 @@ }; components = { "library" = { - depends = [ (hsPkgs.base) ]; + depends = [ + (hsPkgs.base) + (hsPkgs.extra) + (hsPkgs.safe) + (hsPkgs.aeson) + ]; }; exes = { "cabal-simple" = { - depends = [ (hsPkgs.base) ]; + depends = [ + (hsPkgs.base) + (hsPkgs.extra) + (hsPkgs.optparse-applicative) + ]; }; }; }; diff --git a/test/cabal-simple/default.nix b/test/cabal-simple/default.nix index d5d8fdd8e6..99fcb8c15c 100644 --- a/test/cabal-simple/default.nix +++ b/test/cabal-simple/default.nix @@ -49,7 +49,7 @@ in ''; meta.platforms = platforms.all; -} // { inherit (packages) cabal-simple; } +} // { inherit (packages) cabal-simple; inherit pkgSet; } ## steps to generate local files # 1. cabal-to-nix cabal-simple.cabal > cabal-simple.nix diff --git a/test/cabal-simple/plan.nix b/test/cabal-simple/plan.nix index c52a1669a2..dead4b6b3f 100644 --- a/test/cabal-simple/plan.nix +++ b/test/cabal-simple/plan.nix @@ -1,18 +1,110 @@ hackage: { packages = { + "binary".revision = hackage."binary"."0.8.5.1".revisions.default; "ghc-prim".revision = hackage."ghc-prim"."0.5.2.0".revisions.default; + "extra".revision = hackage."extra"."1.6.14".revisions.default; + "stm".revision = hackage."stm"."2.4.5.1".revisions.default; + "unix".revision = hackage."unix"."2.7.2.2".revisions.default; "rts".revision = hackage."rts"."1.0".revisions.default; + "clock".revision = hackage."clock"."0.7.2".revisions.default; + "clock".flags.llvm = false; + "scientific".revision = hackage."scientific"."0.3.6.2".revisions.default; + "scientific".flags.integer-simple = false; + "scientific".flags.bytestring-builder = false; + "deepseq".revision = hackage."deepseq"."1.4.3.0".revisions.default; + "random".revision = hackage."random"."1.1".revisions.default; + "uuid-types".revision = hackage."uuid-types"."1.0.3".revisions.default; + "optparse-applicative".revision = hackage."optparse-applicative"."0.14.3.0".revisions.default; + "dlist".revision = hackage."dlist"."0.8.0.5".revisions.default; + "directory".revision = hackage."directory"."1.3.1.5".revisions.default; + "transformers-compat".revision = hackage."transformers-compat"."0.6.2".revisions.default; + "transformers-compat".flags.five = false; + "transformers-compat".flags.generic-deriving = true; + "transformers-compat".flags.two = false; + "transformers-compat".flags.five-three = true; + "transformers-compat".flags.mtl = true; + "transformers-compat".flags.four = false; + "transformers-compat".flags.three = false; + "template-haskell".revision = hackage."template-haskell"."2.13.0.0".revisions.default; + "vector".revision = hackage."vector"."0.12.0.2".revisions.default; + "vector".flags.unsafechecks = false; + "vector".flags.internalchecks = false; + "vector".flags.wall = false; + "vector".flags.boundschecks = true; + "primitive".revision = hackage."primitive"."0.6.4.0".revisions.default; + "time-locale-compat".revision = hackage."time-locale-compat"."0.1.1.5".revisions.default; + "time-locale-compat".flags.old-locale = false; + "safe".revision = hackage."safe"."0.3.17".revisions.default; + "base-compat".revision = hackage."base-compat"."0.10.5".revisions.default; + "ansi-terminal".revision = hackage."ansi-terminal"."0.8.2".revisions.default; + "ansi-terminal".flags.example = false; + "tagged".revision = hackage."tagged"."0.8.6".revisions.default; + "tagged".flags.transformers = true; + "tagged".flags.deepseq = true; + "containers".revision = hackage."containers"."0.5.11.0".revisions.default; + "integer-logarithms".revision = hackage."integer-logarithms"."1.0.2.2".revisions.default; + "integer-logarithms".flags.check-bounds = false; + "integer-logarithms".flags.integer-gmp = true; + "bytestring".revision = hackage."bytestring"."0.10.8.2".revisions.default; + "ansi-wl-pprint".revision = hackage."ansi-wl-pprint"."0.6.8.2".revisions.default; + "ansi-wl-pprint".flags.example = false; + "StateVar".revision = hackage."StateVar"."1.1.1.1".revisions.default; + "contravariant".revision = hackage."contravariant"."1.5".revisions.default; + "contravariant".flags.semigroups = true; + "contravariant".flags.tagged = true; + "contravariant".flags.statevar = true; + "contravariant".flags.safe = false; + "text".revision = hackage."text"."1.2.3.1".revisions.default; + "unordered-containers".revision = hackage."unordered-containers"."0.2.9.0".revisions.default; + "unordered-containers".flags.debug = false; "base".revision = hackage."base"."4.11.1.0".revisions.default; + "time".revision = hackage."time"."1.8.0.2".revisions.default; + "transformers".revision = hackage."transformers"."0.5.5.0".revisions.default; + "hashable".revision = hackage."hashable"."1.2.7.0".revisions.default; + "hashable".flags.sse2 = true; + "hashable".flags.integer-gmp = true; + "hashable".flags.sse41 = false; + "hashable".flags.examples = false; + "attoparsec".revision = hackage."attoparsec"."0.13.2.2".revisions.default; + "attoparsec".flags.developer = false; + "colour".revision = hackage."colour"."2.3.4".revisions.default; + "filepath".revision = hackage."filepath"."1.4.2".revisions.default; + "process".revision = hackage."process"."1.6.3.0".revisions.default; + "pretty".revision = hackage."pretty"."1.1.3.6".revisions.default; + "aeson".revision = hackage."aeson"."1.4.2.0".revisions.default; + "aeson".flags.cffi = false; + "aeson".flags.fast = false; + "aeson".flags.bytestring-builder = false; + "aeson".flags.developer = false; + "ghc-boot-th".revision = hackage."ghc-boot-th"."8.4.4".revisions.default; + "th-abstraction".revision = hackage."th-abstraction"."0.2.10.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 = { + "binary" = "0.8.5.1"; "ghc-prim" = "0.5.2.0"; + "stm" = "2.4.5.1"; + "unix" = "2.7.2.2"; "rts" = "1.0"; + "deepseq" = "1.4.3.0"; + "directory" = "1.3.1.5"; + "template-haskell" = "2.13.0.0"; + "containers" = "0.5.11.0"; + "bytestring" = "0.10.8.2"; + "text" = "1.2.3.1"; "base" = "4.11.1.0"; + "time" = "1.8.0.2"; + "transformers" = "0.5.5.0"; + "filepath" = "1.4.2"; + "process" = "1.6.3.0"; + "pretty" = "1.1.3.6"; + "ghc-boot-th" = "8.4.4"; + "array" = "0.5.2.0"; "integer-gmp" = "1.0.2.0"; }; }; From 57049091b32db76ca133cece94827e51ef1f0b13 Mon Sep 17 00:00:00 2001 From: Rodney Lorrimar Date: Thu, 31 Jan 2019 12:40:55 +1000 Subject: [PATCH 9/9] Fix dependency merging of "all" component --- modules/package.nix | 35 +++++++++++++++++++--------------- test/tests.sh | 7 +++++++ test/with-packages/default.nix | 17 +++++++++++++++-- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/modules/package.nix b/modules/package.nix index ca3c411a32..ba8e643ae8 100644 --- a/modules/package.nix +++ b/modules/package.nix @@ -19,6 +19,8 @@ with lib; with types; let + haskellLib = let hl = import ../lib { inherit lib; haskellLib = hl; }; in hl; + # This is just like listOf, except that it filters out all null elements. listOfFilteringNulls = elemType: listOf elemType // { # Mostly copied from nixpkgs/lib/types.nix @@ -97,11 +99,11 @@ in { }; components = let - componentType = check: submodule { + componentType = defaults: submodule { options = { depends = mkOption { type = listOfFilteringNulls unspecified; - default = []; + default = defaults.depends or []; }; libs = mkOption { type = listOfFilteringNulls (nullOr package); @@ -141,7 +143,7 @@ in { }; doCheck = mkOption { type = bool; - default = check; + default = defaults.doCheck or false; }; doCrossCheck = mkOption { type = bool; @@ -151,35 +153,38 @@ in { }; in { library = mkOption { - type = componentType false; + type = componentType {}; }; sublibs = mkOption { - type = attrsOf (componentType false); + type = attrsOf (componentType {}); default = {}; }; foreignlibs = mkOption { - type = attrsOf (componentType false); + type = attrsOf (componentType {}); default = {}; }; exes = mkOption { - type = attrsOf (componentType false); + type = attrsOf (componentType {}); default = {}; }; tests = mkOption { - type = attrsOf (componentType config.doCheck); + type = attrsOf (componentType { inherit (config) doCheck; }); default = {}; }; benchmarks = mkOption { - type = attrsOf (componentType false); + type = attrsOf (componentType {}); default = {}; }; - all = mkOption { - type = componentType false; - default = let - componentTypes = [ "library" "sublibs" "foreignlibs" "exes" "tests" "benchmarks" ]; - in { - depends = mkMerge (map (c: config.components.${c}.depends or []) componentTypes); + all = let + subComponentsDepends = sub: concatLists + (mapAttrsToList (_: c: c.depends or []) config.components.${sub} or {}); + default = { + depends = config.components.library.depends ++ + concatMap subComponentsDepends haskellLib.subComponentTypes; }; + in mkOption { + type = componentType default; + inherit default; defaultText = "The merged dependencies of all other components"; }; }; diff --git a/test/tests.sh b/test/tests.sh index ed3a1643b0..44a99b6485 100755 --- a/test/tests.sh +++ b/test/tests.sh @@ -36,4 +36,11 @@ nix-shell $NIX_BUILD_ARGS \ --run 'echo CABAL_CONFIG=$CABAL_CONFIG && type -p ghc && cd with-packages && rm -rf dist-newstyle .ghc-environment* && cabal new-build' echo >& 2 +printf "*** Checking that a nix-shell works for cabal (doExactConfig component)...\n" >& 2 +nix-shell $NIX_BUILD_ARGS \ + --pure ./default.nix \ + -A with-packages.test-shell-dec \ + --run 'echo CABAL_CONFIG=$CABAL_CONFIG && echo GHC_ENVIRONMENT=$GHC_ENVIRONMENT && cd with-packages && rm -rf dist-newstyle .ghc-environment* && cabal new-build' +echo >& 2 + printf "\n*** Finished successfully\n" >& 2 diff --git a/test/with-packages/default.nix b/test/with-packages/default.nix index b24fb1f5d5..90623e26e8 100644 --- a/test/with-packages/default.nix +++ b/test/with-packages/default.nix @@ -21,6 +21,14 @@ let { packages.transformers-compat.components.library.doExactConfig = true; } + + # vary component config for tests + { + packages.test-with-packages.components = { + all.doExactConfig = false; # the default + library.doExactConfig = true; # not the default + }; + } ]; }; @@ -43,8 +51,10 @@ in # test with-packages printf "checking that the 'all' component works... " >& 2 - echo ${package.components.all} - # echo >& 2 + echo ${package.components.all} >& 2 + + printf "checking that the 'library' component works... " >& 2 + echo ${package.components.library} >& 2 printf "checking that the package env has the dependencies... " >& 2 ${package.components.all.env}/bin/runghc ${./Point.hs} @@ -65,4 +75,7 @@ in # Used for testing externally with nix-shell (../tests.sh). # This just adds cabal-install to the existing shells. test-shell = addCabalInstall packages.test-with-packages.components.all; + + # A variant of test-shell with the component option doExactConfig enabled + test-shell-dec = addCabalInstall packages.test-with-packages.components.library; }