@@ -15,6 +15,7 @@
1515 # worked on in the shell then we can pass a different `components` function
1616 # to select those.
1717, components ? ps: lib.concatMap haskellLib.getAllComponents (packages hsPkgs)
18+ # Additional packages to be added unconditionally
1819, additional ? _: []
1920, withHoogle ? true
2021, exactDeps ? false
@@ -24,39 +25,57 @@
2425let
2526 # TODO find out why hoogle index creation can be made to work for cross compilers
2627 withHoogle' = withHoogle && !haskellLib.isCrossHost;
27− selected = packages hsPkgs;
28+
29+ selectedPackages = packages hsPkgs;
30+ additionalPackages = additional hsPkgs;
2831 selectedComponents = components hsPkgs;
29− additionalSelected = additional hsPkgs;
30− selectedConfigs = map (c: c.config) selectedComponents;
3132
32− name = if lib.length selected == 1
33− then "ghc-shell-for-${(lib.head selected).identifier.name}"
33+ # The configs of all the selected components
34+ selectedConfigs = map (c: c.config) selectedComponents ++ map (p: p.setup.config) selectedPackages;
35+
36+ name = if lib.length selectedPackages == 1
37+ then "ghc-shell-for-${(lib.head selectedPackages).identifier.name}"
3438 else "ghc-shell-for-packages";
3539
36− # Removes the selected packages from a list of packages.
37− # If `packages = [ a b ]` and `a` depends on `b`, don't build `b`,
38− # because cabal will end up ignoring that built version;
39− removeSelected = lib.filter
40− (input: lib.all (cfg: (input.identifier or null) != cfg.identifier) selected);
41− # Also since a will include the library component of b in its buildInputs
42− # (to make `propagatedBuildInputs` of `pkgconfig-depends` work) those should
43− # also be excluded (the pkgconfig depends of b will still be included in the
44− # system shells buildInputs via b's own buildInputs).
45− removeSelectedInputs = lib.filter
46− (input: lib.all (cfg: input != cfg.components.library or null) selected);
47−
48− packageInputs =
49− removeSelected
50− (lib.concatMap (cfg: cfg.depends) selectedConfigs
51− ++ lib.concatMap (cfg: cfg.setup.config.depends or []) selected
52− )
53− ++ additionalSelected;
54−
55− # Add the system libraries and build tools of the selected haskell
56− # packages to the shell.
40+ # Given a `packages = [ a b ]` we construct a shell with the dependencies of `a` and `b`.
41+ #
42+ # But if `a` depends on `b`, we don't want to include `b`, because
43+ # - cabal will end up ignoring that built version;
44+ # - The user has indicated that's what they're working on, so they probably don't want to have to build
45+ # it first (and it will change often).
46+ # Generally we never want to include any of (the components of) the selected packages as dependencies.
47+ #
48+ # Furthermore, if `a` depends on `b`, `a` will include the library component of `b` in its `buildInputs`
49+ # (to make `propagatedBuildInputs` of `pkgconfig-depends` work). So we also need to filter those
50+ # (the pkgconfig depends of `b` will still be included in the
51+ # system shell's `buildInputs` via `b`'s own `buildInputs`).
52+ # We have to do this slightly differently because we will be looking at the actual components rather
53+ # than the packages.
54+
55+ # Given a list of packages, removes those which were selected as part of the shell.
56+ # We do this on the basis of their identifiers being the same, not direct equality (why?).
57+ removeSelectedPackages =
58+ # All the identifiers of the selected packages
59+ let selectedPackageIds = map (p: p.identifier) selectedPackages;
60+ in lib.filter (input: !(builtins.elem (input.identifier or null) selectedPackageIds));
61+
62+ # Given a list of derivations, removes those which are components of packages which were selected as part of the shell.
63+ removeSelectedInputs =
64+ # All the components of the selected packages: we shouldn't add any of these as dependencies
65+ let selectedPackageComponents = lib.concatMap haskellLib.getAllComponents selectedPackages;
66+ in lib.filter (input: !(builtins.elem input selectedPackageComponents));
67+
68+ # We need to remove any dependencies which are selected packages (see above).
69+ # `depends` contains packages so we use 'removeSelectedPackages`.
70+ packageInputs = removeSelectedPackages (lib.concatMap (cfg: cfg.depends) selectedConfigs) ++ additionalPackages;
71+
72+ # Add the system libraries and build tools of the selected haskell packages to the shell.
73+ # We need to remove any inputs which are selected components (see above).
74+ # `buildInputs`, `propagatedBuildInputs`, and `executableToolDepends` contain component
75+ # derivations, not packages, so we use `removeSelectedInputs`).
5776 systemInputs = removeSelectedInputs (lib.concatMap
5877 (c: c.buildInputs ++ c.propagatedBuildInputs) selectedComponents);
59− nativeBuildInputs = removeSelected
78+ nativeBuildInputs = removeSelectedInputs
6079 (lib.concatMap (c: c.executableToolDepends) selectedComponents);
6180
6281 # Set up a "dummy" component to use with ghcForComponent.