on iko/ghcjs-patch-master help sign in
Fix dependency filtering for `shellFor` (#819)
2db0b60Michael Peyton Jones
builder/shell-for.nix+46−27
@@ -15,6 +15,7 @@
15 # worked on in the shell then we can pass a different `components` function
15 # worked on in the shell then we can pass a different `components` function
16 # to select those.
16 # to select those.
17, components ? ps: lib.concatMap haskellLib.getAllComponents (packages hsPkgs)
17, components ? ps: lib.concatMap haskellLib.getAllComponents (packages hsPkgs)
18+ # Additional packages to be added unconditionally
18, additional ? _: []
19, additional ? _: []
19, withHoogle ? true
20, withHoogle ? true
20, exactDeps ? false
21, exactDeps ? false
@@ -24,39 +25,57 @@
24let
25let
25 # TODO find out why hoogle index creation can be made to work for cross compilers
26 # TODO find out why hoogle index creation can be made to work for cross compilers
26 withHoogle' = withHoogle && !haskellLib.isCrossHost;
27 withHoogle' = withHoogle && !haskellLib.isCrossHost;
28+
27− selected = packages hsPkgs;
29+ selectedPackages = packages hsPkgs;
30+ additionalPackages = additional hsPkgs;
28 selectedComponents = components hsPkgs;
31 selectedComponents = components hsPkgs;
29− additionalSelected = additional hsPkgs;
30− selectedConfigs = map (c: c.config) selectedComponents;
31
32
33+ # The configs of all the selected components
34+ selectedConfigs = map (c: c.config) selectedComponents ++ map (p: p.setup.config) selectedPackages;
35+
32− name = if lib.length selected == 1
36+ name = if lib.length selectedPackages == 1
33− then "ghc-shell-for-${(lib.head selected).identifier.name}"
37+ then "ghc-shell-for-${(lib.head selectedPackages).identifier.name}"
34 else "ghc-shell-for-packages";
38 else "ghc-shell-for-packages";
35
39
36− # Removes the selected packages from a list of packages.
40+ # Given a `packages = [ a b ]` we construct a shell with the dependencies of `a` and `b`.
41+ #
37− # If `packages = [ a b ]` and `a` depends on `b`, don't build `b`,
42+ # But if `a` depends on `b`, we don't want to include `b`, because
38− # because cabal will end up ignoring that built version;
43+ # - cabal will end up ignoring that built version;
39− removeSelected = lib.filter
44+ # - The user has indicated that's what they're working on, so they probably don't want to have to build
40− (input: lib.all (cfg: (input.identifier or null) != cfg.identifier) selected);
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+ #
41− # Also since a will include the library component of b in its buildInputs
48+ # Furthermore, if `a` depends on `b`, `a` will include the library component of `b` in its `buildInputs`
42− # (to make `propagatedBuildInputs` of `pkgconfig-depends` work) those should
49+ # (to make `propagatedBuildInputs` of `pkgconfig-depends` work). So we also need to filter those
43− # also be excluded (the pkgconfig depends of b will still be included in the
50+ # (the pkgconfig depends of `b` will still be included in the
44− # system shells buildInputs via b's own buildInputs).
51+ # system shell's `buildInputs` via `b`'s own `buildInputs`).
45− removeSelectedInputs = lib.filter
52+ # We have to do this slightly differently because we will be looking at the actual components rather
46− (input: lib.all (cfg: input != cfg.components.library or null) selected);
53+ # than the packages.
47−
54+
48− packageInputs =
55+ # Given a list of packages, removes those which were selected as part of the shell.
49− removeSelected
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`.
50− (lib.concatMap (cfg: cfg.depends) selectedConfigs
70+ packageInputs = removeSelectedPackages (lib.concatMap (cfg: cfg.depends) selectedConfigs) ++ additionalPackages;
51− ++ lib.concatMap (cfg: cfg.setup.config.depends or []) selected
71+
52− )
53− ++ additionalSelected;
54−
55− # Add the system libraries and build tools of the selected haskell
72+ # Add the system libraries and build tools of the selected haskell packages to the shell.
56− # 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`).
57 systemInputs = removeSelectedInputs (lib.concatMap
76 systemInputs = removeSelectedInputs (lib.concatMap
58 (c: c.buildInputs ++ c.propagatedBuildInputs) selectedComponents);
77 (c: c.buildInputs ++ c.propagatedBuildInputs) selectedComponents);
59− nativeBuildInputs = removeSelected
78+ nativeBuildInputs = removeSelectedInputs
60 (lib.concatMap (c: c.executableToolDepends) selectedComponents);
79 (lib.concatMap (c: c.executableToolDepends) selectedComponents);
61
80
62 # Set up a "dummy" component to use with ghcForComponent.
81 # Set up a "dummy" component to use with ghcForComponent.