Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 50a8d606f352
Choose a base ref
...
head repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ff7f4a84f805
Choose a head ref
  • 3 commits
  • 1 file changed
  • 2 contributors

Commits on Nov 3, 2020

  1. Copy the full SHA
    6b8d245 View commit details

Commits on Nov 4, 2020

  1. haskellPackages.shellFor: fix spelling and grammar mistakes

    Co-authored-by: maralorn <malte.brandy@maralorn.de>
    cdepillabout and maralorn authored Nov 4, 2020
    Copy the full SHA
    564311c View commit details
  2. Merge pull request #102598 from cdepillabout/documentation-for-shellF…

    …or-rebased
    
    haskellPackages.shellFor: improve documentation
    cdepillabout authored Nov 4, 2020
    Copy the full SHA
    ff7f4a8 View commit details
Showing with 135 additions and 30 deletions.
  1. +135 −30 pkgs/development/haskell-modules/make-package-set.nix
165 changes: 135 additions & 30 deletions pkgs/development/haskell-modules/make-package-set.nix
Original file line number Diff line number Diff line change
@@ -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,142 @@ 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 generate 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 each attribute set
# corresponds to the build inputs of 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 [];
});