@@ -25,39 +25,59 @@ let
2525
2626 selectedPackages = packages hsPkgs;
2727 additionalPackages = additional hsPkgs;
28− selectedComponents = components hsPkgs;
28+ directlySelectedComponents = components hsPkgs;
2929
30− # The configs of all the selected components
31− selectedConfigs = map (c: c.config) selectedComponents
32− ++ lib.optionals packageSetupDeps (map (p: p.setup.config) selectedPackages);
33−
34− name = if lib.length selectedPackages == 1
35− then "ghc-shell-for-${(lib.head selectedPackages).identifier.name}"
36− else "ghc-shell-for-packages";
37−
38− # Given a `packages = [ a b ]` we construct a shell with the dependencies of `a` and `b`.
30+ # Given `directlySelectedComponents = [ a b ]`, we construct a shell that includes all of their dependencies
3931 #
40− # But if `a` depends on `b`, we don't want to include `b`, because
32+ # But we want to exclude `a` if it is a transitive dependecy of `b`
33+ # because:
4134 # - cabal will end up ignoring that built version;
4235 # - The user has indicated that's what they're working on, so they probably don't want to have to build
4336 # it first (and it will change often).
44− # Generally we never want to include any of (the components of) the selected packages as dependencies.
37+ # Generally we never want to include any of `directlySelectedComponents` as dependencies.
38+ #
39+ # We do this by defining a set of `selectedComponents`, where `x` is in `selectedComponents` if and only if:
40+ # - `x` is in `directlySelectedComponents`
41+ # - `x` is a transitive dependency of something in `directlySelectedComponents`
42+ # and `x` transitively depends on something in `directlySelectedComponents`
43+ # We use the dependencies of `selectedComponents` filtering out members of `selectedComponents`
4544 #
4645 # Furthermore, if `a` depends on `b`, `a` will include the library component of `b` in its `buildInputs`
4746 # (to make `propagatedBuildInputs` of `pkgconfig-depends` work). So we also need to filter those
4847 # (the pkgconfig depends of `b` will still be included in the
4948 # system shell's `buildInputs` via `b`'s own `buildInputs`).
50− # We have to do this slightly differently because we will be looking at the actual components rather
51− # than the packages.
5249
53− # Given a list of `depends`, removes those which are components of packages which were selected as part of the shell.
50+
51+ # all packages that are indirectly depended on by `directlySelectedComponents`
52+ # including `directlySelectedComponents`
53+ transitiveDependenciesComponents =
54+ builtins.listToAttrs
55+ (builtins.map (x: lib.nameValuePair (x.name) x)
56+ (haskellLib.flatLibDepends {depends = directlySelectedComponents;}));
57+
58+ selectedComponentsBitmap =
59+ lib.mapAttrs
60+ (_: x: (builtins.any
61+ (dep: selectedComponentsBitmap."${(haskellLib.dependToLib dep).name}") x.config.depends))
62+ transitiveDependenciesComponents
63+ // builtins.listToAttrs (map (x: lib.nameValuePair x.name true) directlySelectedComponents); # base case
64+
65+ selectedComponents =
66+ lib.filter (x: selectedComponentsBitmap."${x.name}") (lib.attrValues transitiveDependenciesComponents);
67+
68+ # Given a list of `depends`, removes those which are selected components
5469 removeSelectedInputs =
55− # All the components of the selected packages: we shouldn't add any of these as dependencies
56− let selectedPackageComponents = map (x: x.name) selectedComponents;
57− in lib.filter (input:
58− !(builtins.elem ((haskellLib.dependToLib input).name or null) selectedPackageComponents));
70+ lib.filter (input: !(selectedComponentsBitmap."${((haskellLib.dependToLib input).name or null)}" or false));
71+
72+ # The configs of all the selected components
73+ selectedConfigs = map (c: c.config) selectedComponents
74+ ++ lib.optionals packageSetupDeps (map (p: p.setup.config) selectedPackages);
75+
76+ name = if lib.length selectedPackages == 1
77+ then "ghc-shell-for-${(lib.head selectedPackages).identifier.name}"
78+ else "ghc-shell-for-packages";
5979
60− # We need to remove any dependencies which are selected packages (see above).
80+ # We need to remove any dependencies which would bring in selected components (see above).
6181 packageInputs = removeSelectedInputs (lib.concatMap (cfg: cfg.depends) selectedConfigs)
6282 ++ additionalPackages;
6383