@@ -25,39 +25,59 @@ let
26 selectedPackages = packages hsPkgs;
26 selectedPackages = packages hsPkgs;
27 additionalPackages = additional hsPkgs;
27 additionalPackages = additional hsPkgs;
28− selectedComponents = components hsPkgs;
28+ directlySelectedComponents = components hsPkgs;
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);
34− name = if lib.length selectedPackages == 1
35− then "ghc-shell-for-${(lib.head selectedPackages).identifier.name}"
36− else "ghc-shell-for-packages";
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
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`
41 # - cabal will end up ignoring that built version;
34 # - cabal will end up ignoring that built version;
42 # - The user has indicated that's what they're working on, so they probably don't want to have to build
35 # - The user has indicated that's what they're working on, so they probably don't want to have to build
43 # it first (and it will change often).
36 # 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.
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`
46 # Furthermore, if `a` depends on `b`, `a` will include the library component of `b` in its `buildInputs`
45 # Furthermore, if `a` depends on `b`, `a` will include the library component of `b` in its `buildInputs`
47 # (to make `propagatedBuildInputs` of `pkgconfig-depends` work). So we also need to filter those
46 # (to make `propagatedBuildInputs` of `pkgconfig-depends` work). So we also need to filter those
48 # (the pkgconfig depends of `b` will still be included in the
47 # (the pkgconfig depends of `b` will still be included in the
49 # system shell's `buildInputs` via `b`'s own `buildInputs`).
48 # 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+ # all packages that are indirectly depended on by `directlySelectedComponents`
52+ # including `directlySelectedComponents`
53+ transitiveDependenciesComponents =
55+ (builtins.map (x: lib.nameValuePair (x.name) x)
56+ (haskellLib.flatLibDepends {depends = directlySelectedComponents;}));
58+ selectedComponentsBitmap =
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
66+ lib.filter (x: selectedComponentsBitmap."${x.name}") (lib.attrValues transitiveDependenciesComponents);
53− # Given a list of `depends`, removes those which are components of packages which were selected as part of the shell.
68+ # Given a list of `depends`, removes those which are selected components
54 removeSelectedInputs =
69 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));
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);
76+ name = if lib.length selectedPackages == 1
77+ then "ghc-shell-for-${(lib.head selectedPackages).identifier.name}"
78+ else "ghc-shell-for-packages";
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).
61 packageInputs = removeSelectedInputs (lib.concatMap (cfg: cfg.depends) selectedConfigs)
81 packageInputs = removeSelectedInputs (lib.concatMap (cfg: cfg.depends) selectedConfigs)
62 ++ additionalPackages;
82 ++ additionalPackages;