on iko/ghcjs-patch-master help sign in
move package-set.nix from stackage.nix into haskell.nix
fe5c13dMoritz Angermann
@@ -1 +1,4 @@
1+hackage: let haskell = {
1−hackage: { compat = import ./compat hackage; }
2+ compat = import ./compat hackage;
3+ mkPkgSet = pkgs: pkg-def: import ./package-set.nix { inherit pkg-def pkgs hackage haskell; };
4+}; in haskell
package-set.nixnew file+131
@@ -0,0 +1,131 @@
1+{ pkg-def
2+, pkgs ? import <nixpkgs> {}
3+, hackage ? import <hackage>
4+, haskell ? import <haskell> }:
5+
6+{ extraDeps ? hsPkgs: {} }:
7+let
8+
9+ # packages that we must never try to reinstall.
10+ nonReinstallablePkgs = [ "rts" "ghc" "ghc-prim" "integer-gmp" "integer-simple" "base"
11+ "array" "deepseq" "pretty" "ghc-boot-th" "template-haskell"];
12+
13+ hackagePkgs = with pkgs.lib;
14+ let shippedPkgs = filterAttrs (n: _: builtins.elem n nonReinstallablePkgs)
15+ (mapAttrs (name: version: { ${version} = null; })
16+ (pkg-def {}).compiler.packages);
17+ in recursiveUpdate hackage.exprs shippedPkgs;
18+
19+ # We may depend on packages shipped with ghc, or need to rebuild them.
20+ ghcPackages = pkgs.lib.mapAttrs (name: version: hackagePkgs.${name}.${version}
21+ ) (pkg-def {}).compiler.packages;
22+
23+ # Thus the final package set in our augmented (extrDeps) lts set is the following:
24+ ltsPkgs = ghcPackages
25+ // (pkg-def hackagePkgs).packages
26+ // extraDeps hackagePkgs;
27+
28+ driver = haskell.compat.driver;
29+ host-map = haskell.compat.host-map;
30+
31+ # compiler this lts set is built against.
32+ compiler = pkgs.haskell.packages.${(pkg-def {}).compiler.nix-name};
33+
34+ # This is a tiny bit better than doJailbreak.
35+ #
36+ # We essentially *know* the dependencies, and with the
37+ # full cabal file representation, we also know all the
38+ # flags. As such we can sidestep the solver.
39+ #
40+ # Pros:
41+ # - no need for doJailbreak
42+ # - no need for jailbreak-cabal to be built with
43+ # Cabal2 if the cabal file requires it.
44+ # - no reliance on --allow-newer, which only made
45+ # a very short lived appearance in Cabal.
46+ # (Cabal-2.0.0.2 -- Cabal-2.2.0.0)
47+ #
48+ # Cons:
49+ # - automatic flag resolution won't happen and will
50+ # have to be hard coded.
51+ #
52+ # Ideally we'd just inspect the haskell*Depends fields
53+ # we feed the builder. However because we null out the
54+ # lirbaries ghc ships (e.g. base, ghc, ...) this would
55+ # result in an incomplete --dependency=<name>=<name>-<version>
56+ # set and not lead to the desired outcome.
57+ #
58+ # If we could still have base, etc. not nulled, but
59+ # produce some virtual derivation, that might allow us
60+ # to just use the haskell*Depends fields to extract the
61+ # name and version for each dependency.
62+ #
63+ # Ref: https://github.com/haskell/cabal/issues/3163#issuecomment-185833150
64+ # ---
65+ # ghc-pkg should be ${ghcCommand}-pkg; and --package-db
66+ # should better be --${packageDbFlag}; but we don't have
67+ # those variables in scope.
68+ doExactConfig = pkgs: pkg: let targetPrefix = with pkgs.stdenv; lib.optionalString
69+ (hostPlatform != buildPlatform)
70+ "${hostPlatform.config}-";
71+
72+ in pkgs.haskell.lib.overrideCabal pkg (drv: {
73+ # TODO: need to run `ghc-pkg field <pkg> id` over all `--dependency`
74+ # values. Should we encode the `id` in the nix-pkg as well?
75+ preConfigure = (drv.preConfigure or "") + ''
76+ configureFlags+=" --exact-configuration"
77+ globalPackages=$(${targetPrefix}ghc-pkg list --global --simple-output)
78+ localPackages=$(${targetPrefix}ghc-pkg --package-db="$packageConfDir" list --simple-output)
79+ for pkg in $globalPackages; do
80+ pkgName=''${pkg%-*}
81+ if [ "$pkgName" != "rts" ]; then
82+ if [[ " ${pkgs.lib.concatStringsSep " " nonReinstallablePkgs} " =~ " $pkgName " ]]; then
83+ configureFlags+=" --dependency="''${pkg%-*}=$pkg
84+ fi
85+ fi
86+ done
87+ for pkg in $localPackages; do
88+ configureFlags+=" --dependency="''${pkg%-*}=$pkg
89+ done
90+ #echo "<<< <<< <<<"
91+ #echo ''${configureFlags}
92+ configureFlags=$(for flag in ''${configureFlags};do case "X''${flag}" in
93+ X--dependency=*)
94+ pkgId=$(${targetPrefix}ghc-pkg --package-db="$packageConfDir" field ''${flag##*=} id || ${targetPrefix}ghc-pkg --global field ''${flag##*=} id)
95+ echo ''${flag%=*}=$(echo $pkgId | awk -F' ' '{ print $2 }')
96+ ;;
97+ *) echo ''${flag};;
98+ esac; done)
99+ #echo "--- --- ---"
100+ #echo ''${configureFlags}
101+ #echo ">>> >>> >>>"
102+'';
103+ });
104+
105+ toGenericPackage = stackPkgs: args: name: path:
106+ if path == null then null else
107+ let expr = driver { cabalexpr = import path;
108+ pkgs = pkgs // { haskellPackages = stackPkgs; };
109+ inherit (host-map pkgs.stdenv) os arch;
110+ version = compiler.ghc.version; };
111+ # Use `callPackage` from the `compiler` here, to get the
112+ # right compiler.
113+ in compiler.callPackage expr args;
114+
115+in let stackPackages = pkgs: self:
116+ (let p = (pkgs.lib.mapAttrs (toGenericPackage self {}) ltsPkgs);
117+ # for all packages do the `exactConfig` logic. That is, we
118+ # *know* that that our package-db contains only a single valid
119+ # set of proper packages. So we can sidestep cabals solver.
120+ in (pkgs.lib.mapAttrs (_: v: if v == null
121+ then null
122+ else doExactConfig pkgs v) p)
123+ // (with pkgs.haskell.lib;
124+ { doctest = null;
125+ hsc2hs = null;
126+ buildPackages = pkgs.buildPackages.haskellPackages; }));
127+ in compiler.override {
128+ initialPackages = { pkgs, stdenv, callPackage }: self: (stackPackages pkgs self);
129+ configurationCommon = { ... }: self: super: {};
130+ compilerConfig = self: super: {};
131+ }