about summary refs log tree commit diff
path: root/pkgs/development/haskell-modules/make-package-set.nix
diff options
context:
space:
mode:
author(cdep)illabout <cdep.illabout@gmail.com>2020-11-03 16:45:15 +0900
committerPeter Simons <simons@cryp.to>2020-11-06 21:37:05 +0100
commit17eee57642f0cd010176767a873c42d34167cde4 (patch)
treebb5d8d43aed12a79c55d9d74f1f17282635aeccc /pkgs/development/haskell-modules/make-package-set.nix
parent0fa596936b0bf07b34530599dcd35aae0d1ba21e (diff)
downloadnixlib-17eee57642f0cd010176767a873c42d34167cde4.tar
nixlib-17eee57642f0cd010176767a873c42d34167cde4.tar.gz
nixlib-17eee57642f0cd010176767a873c42d34167cde4.tar.bz2
nixlib-17eee57642f0cd010176767a873c42d34167cde4.tar.lz
nixlib-17eee57642f0cd010176767a873c42d34167cde4.tar.xz
nixlib-17eee57642f0cd010176767a873c42d34167cde4.tar.zst
nixlib-17eee57642f0cd010176767a873c42d34167cde4.zip
haskellPackages.shellFor: improve documentation
Diffstat (limited to 'pkgs/development/haskell-modules/make-package-set.nix')
-rw-r--r--pkgs/development/haskell-modules/make-package-set.nix166
1 files changed, 136 insertions, 30 deletions
diff --git a/pkgs/development/haskell-modules/make-package-set.nix b/pkgs/development/haskell-modules/make-package-set.nix
index 1418cfef0574..c5604aa41962 100644
--- a/pkgs/development/haskell-modules/make-package-set.nix
+++ b/pkgs/development/haskell-modules/make-package-set.nix
@@ -258,6 +258,7 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
     # packages themselves. Using nix-shell on this derivation will
     # give you an environment suitable for developing the listed
     # packages with an incremental tool like cabal-install.
+    #
     # In addition to the "packages" arg and "withHoogle" arg, anything that
     # can be passed into stdenv.mkDerivation can be included in the input attrset
     #
@@ -274,7 +275,7 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
     #     (import ./.).shellFor {
     #       packages = p: [p.frontend p.backend p.common];
     #       withHoogle = true;
-    #       buildInputs = [ pkgs.python ];
+    #       buildInputs = [ pkgs.python pkgs.cabal-install ];
     #     }
     #
     #     -- cabal.project
@@ -285,38 +286,143 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
     #
     #     bash$ nix-shell --run "cabal new-build all"
     #     bash$ nix-shell --run "python"
-    shellFor = { packages, withHoogle ? false, ... } @ args:
+    shellFor =
+      { # Packages to create this development shell for.  These are usually
+        # your local packages.
+        packages
+      , # Whether or not to generated a Hoogle database for all the
+        # dependencies.
+        withHoogle ? false
+      , ...
+      } @ args:
       let
-        combinedPackageFor = packages:
-          let
-            selected = packages self;
-
-            pname = if pkgs.lib.length selected == 1
-              then (pkgs.lib.head selected).name
-              else "packages";
-
-            # If `packages = [ a b ]` and `a` depends on `b`, don't build `b`,
-            # because cabal will end up ignoring that built version, assuming
-            # new-style commands.
-            combinedPackages = pkgs.lib.filter
-              (input: pkgs.lib.all (p: input.outPath or null != p.outPath) selected);
-
-            # Returns an attrset containing a combined list packages' inputs for each
-            # stage of the build process
-            packageInputs = pkgs.lib.zipAttrsWith
-              (_: pkgs.lib.concatMap combinedPackages)
-              (map (p: p.getCabalDeps) selected);
-
-            genericBuilderArgs = {
-              inherit pname;
-              version = "0";
-              license = null;
-            } // packageInputs;
-
-          in self.mkDerivation genericBuilderArgs;
+        # A list of the packages we want to build a development shell for.
+        #
+        # This is a list of Haskell package derivations.
+        selected = packages self;
+
+        # This is a list of attribute sets, where the each attribute set
+        # corresponds to the build inputs one of the packages input to shellFor.
+        #
+        # Each attribute has keys like buildDepends, executableHaskellDepends,
+        # testPkgconfigDepends, etc.  The values for the keys of the attribute
+        # set are lists of dependencies.
+        #
+        # Example:
+        #   cabalDepsForSelected
+        #   => [
+        #        # This may be the attribute set corresponding to the `backend`
+        #        # package in the example above.
+        #        { buildDepends = [ gcc ... ];
+        #          libraryHaskellDepends = [ lens conduit ... ];
+        #          ...
+        #        }
+        #        # This may be the attribute set corresponding to the `common`
+        #        # package in the example above.
+        #        { testHaskellDepends = [ tasty hspec ... ];
+        #          libraryHaskellDepends = [ lens aeson ];
+        #          benchmarkHaskellDepends = [ criterion ... ];
+        #          ...
+        #        }
+        #        ...
+        #      ]
+        cabalDepsForSelected = map (p: p.getCabalDeps) selected;
+
+        # A predicate that takes a derivation as input, and tests whether it is
+        # the same as any of the `selected` packages.
+        #
+        # Returns true if the input derivation is not in the list of `selected`
+        # packages.
+        #
+        # isNotSelected :: Derivation -> Bool
+        #
+        # Example:
+        #
+        #   isNotSelected common [ frontend backend common ]
+        #   => false
+        #
+        #   isNotSelected lens [ frontend backend common ]
+        #   => true
+        isNotSelected = input: pkgs.lib.all (p: input.outPath or null != p.outPath) selected;
+
+        # A function that takes a list of list of derivations, filters out all
+        # the `selected` packages from each list, and concats the results.
+        #
+        #   zipperCombinedPkgs :: [[Derivation]] -> [Derivation]
+        #
+        # Example:
+        #   zipperCombinedPkgs [ [ lens conduit ] [ aeson frontend ] ]
+        #   => [ lens conduit aeson ]
+        #
+        # Note: The reason this isn't just the function `pkgs.lib.concat` is
+        # that we need to be careful to remove dependencies that are in the
+        # `selected` packages.
+        #
+        # For instance, in the above example, if `common` is a dependency of
+        # `backend`, then zipperCombinedPkgs needs to be careful to filter out
+        # `common`, because cabal will end up ignoring that built version,
+        # assuming new-style commands.
+        zipperCombinedPkgs = vals:
+          pkgs.lib.concatMap
+            (drvList: pkgs.lib.filter isNotSelected drvList)
+            vals;
+
+        # Zip `cabalDepsForSelected` into a single attribute list, combining
+        # the derivations in all the individual attributes.
+        #
+        # Example:
+        #   packageInputs
+        #   => # Assuming the value of cabalDepsForSelected is the same as
+        #      # the example in cabalDepsForSelected:
+        #      { buildDepends = [ gcc ... ];
+        #        libraryHaskellDepends = [ lens conduit aeson ... ];
+        #        testHaskellDepends = [ tasty hspec ... ];
+        #        benchmarkHaskellDepends = [ criterion ... ];
+        #        ...
+        #      }
+        #
+        # See the Note in `zipperCombinedPkgs` for what gets filtered out from
+        # each of these dependency lists.
+        packageInputs =
+          pkgs.lib.zipAttrsWith (_name: zipperCombinedPkgs) cabalDepsForSelected;
+
+        # A attribute set to pass to `haskellPackages.mkDerivation`.
+        #
+        # The important thing to note here is that all the fields from
+        # packageInputs are set correctly.
+        genericBuilderArgs = {
+          pname =
+            if pkgs.lib.length selected == 1
+            then (pkgs.lib.head selected).name
+            else "packages";
+          version = "0";
+          license = null;
+        }
+        // packageInputs;
+
+        # This is a pseudo Haskell package derivation that contains all the
+        # dependencies for the packages in `selected`.
+        #
+        # This is a derivation created with `haskellPackages.mkDerivation`.
+        #
+        # pkgWithCombinedDeps :: HaskellDerivation
+        pkgWithCombinedDeps = self.mkDerivation genericBuilderArgs;
+
+        # The derivation returned from `envFunc` for `pkgWithCombinedDeps`.
+        #
+        # This is a derivation that can be run with `nix-shell`.  It provides a
+        # GHC with a package database with all the dependencies of our
+        # `selected` packages.
+        #
+        # This is a derivation created with `stdenv.mkDerivation` (not
+        # `haskellPackages.mkDerivation`).
+        #
+        # pkgWithCombinedDepsDevDrv :: Derivation
+        pkgWithCombinedDepsDevDrv = pkgWithCombinedDeps.envFunc { inherit withHoogle; };
 
         mkDerivationArgs = builtins.removeAttrs args [ "packages" "withHoogle" ];
-      in ((combinedPackageFor packages).envFunc { inherit withHoogle; }).overrideAttrs (old: mkDerivationArgs // {
+
+      in pkgWithCombinedDepsDevDrv.overrideAttrs (old: mkDerivationArgs // {
         nativeBuildInputs = old.nativeBuildInputs ++ mkDerivationArgs.nativeBuildInputs or [];
         buildInputs = old.buildInputs ++ mkDerivationArgs.buildInputs or [];
       });