haskellPackages.shellFor: improve documentation
This commit is contained in:
parent
0fa596936b
commit
17eee57642
|
@ -258,6 +258,7 @@ in package-set { inherit pkgs stdenv callPackage; } self // {
|
||||||
# packages themselves. Using nix-shell on this derivation will
|
# packages themselves. Using nix-shell on this derivation will
|
||||||
# give you an environment suitable for developing the listed
|
# give you an environment suitable for developing the listed
|
||||||
# packages with an incremental tool like cabal-install.
|
# packages with an incremental tool like cabal-install.
|
||||||
|
#
|
||||||
# In addition to the "packages" arg and "withHoogle" arg, anything that
|
# In addition to the "packages" arg and "withHoogle" arg, anything that
|
||||||
# can be passed into stdenv.mkDerivation can be included in the input attrset
|
# 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 {
|
# (import ./.).shellFor {
|
||||||
# packages = p: [p.frontend p.backend p.common];
|
# packages = p: [p.frontend p.backend p.common];
|
||||||
# withHoogle = true;
|
# withHoogle = true;
|
||||||
# buildInputs = [ pkgs.python ];
|
# buildInputs = [ pkgs.python pkgs.cabal-install ];
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# -- cabal.project
|
# -- 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 "cabal new-build all"
|
||||||
# bash$ nix-shell --run "python"
|
# 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
|
let
|
||||||
combinedPackageFor = packages:
|
# A list of the packages we want to build a development shell for.
|
||||||
let
|
#
|
||||||
selected = packages self;
|
# This is a list of Haskell package derivations.
|
||||||
|
selected = packages self;
|
||||||
|
|
||||||
pname = if pkgs.lib.length selected == 1
|
# This is a list of attribute sets, where the each attribute set
|
||||||
then (pkgs.lib.head selected).name
|
# corresponds to the build inputs one of the packages input to shellFor.
|
||||||
else "packages";
|
#
|
||||||
|
# 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;
|
||||||
|
|
||||||
# If `packages = [ a b ]` and `a` depends on `b`, don't build `b`,
|
# A predicate that takes a derivation as input, and tests whether it is
|
||||||
# because cabal will end up ignoring that built version, assuming
|
# the same as any of the `selected` packages.
|
||||||
# new-style commands.
|
#
|
||||||
combinedPackages = pkgs.lib.filter
|
# Returns true if the input derivation is not in the list of `selected`
|
||||||
(input: pkgs.lib.all (p: input.outPath or null != p.outPath) 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;
|
||||||
|
|
||||||
# Returns an attrset containing a combined list packages' inputs for each
|
# A function that takes a list of list of derivations, filters out all
|
||||||
# stage of the build process
|
# the `selected` packages from each list, and concats the results.
|
||||||
packageInputs = pkgs.lib.zipAttrsWith
|
#
|
||||||
(_: pkgs.lib.concatMap combinedPackages)
|
# zipperCombinedPkgs :: [[Derivation]] -> [Derivation]
|
||||||
(map (p: p.getCabalDeps) selected);
|
#
|
||||||
|
# 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;
|
||||||
|
|
||||||
genericBuilderArgs = {
|
# Zip `cabalDepsForSelected` into a single attribute list, combining
|
||||||
inherit pname;
|
# the derivations in all the individual attributes.
|
||||||
version = "0";
|
#
|
||||||
license = null;
|
# Example:
|
||||||
} // packageInputs;
|
# 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;
|
||||||
|
|
||||||
in self.mkDerivation genericBuilderArgs;
|
# 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" ];
|
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 [];
|
nativeBuildInputs = old.nativeBuildInputs ++ mkDerivationArgs.nativeBuildInputs or [];
|
||||||
buildInputs = old.buildInputs ++ mkDerivationArgs.buildInputs or [];
|
buildInputs = old.buildInputs ++ mkDerivationArgs.buildInputs or [];
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue