@@ -1,170 +1,37 @@
1−{ pkgs ? import <nixpkgs> {}
2−, planFunc ? import ../stackage/lts-11.4.nix
3−, hackage ? import ../hackage
4−, driver ? ./nix/component-driver.nix
5−}:
6−
7−{ extraDeps ? hsPkgs: {} }:
8−(pkgs.lib.fix (self: with self; {
9− inherit (pkgs) lib stdenv;
10−
11− # obtain the compiler from the haskell packages.
12− # this should allow us to use `config` overrides
13− # in the nixpkgs setup, and properly override the
14− # complier as needed.
15− ghc = pkgs.haskell.compiler.${plan.compiler.nix-name};
16−
17− # this is *not* the hasekllLib from nixpkgs; it is rather our own
18− # library from haskell.nix
19− haskellLib = import ./lib { inherit lib haskellLib; };
20−
21− # hackage looks like the following:
22− # { "package-name" =
23− # { "a.b.c.d" =
24− # rec { sha256 = $pkgVersionSha256;
25− # revisions =
26− # { r0 = { outPath = ./hackage/...; revNum = 0; sha256 = $revisionSha256; };
27− # default = revisions.r0; };
28− # };
29− # };
30− # };
31− # }
32−
33−
34− # However it's more convenient to deal with the leaf nodes, and as such
35− # push the `sha256` of the package/version into the revision and keep the
36− # revision.sha256 as revisionSha256; as well as making the revision content
37− # addressable by it's revision hash.
38− #
39− # Thus we transform hackage into hackageConfigs, which will look like:
40− # { "package-name" =
41− # { "a.b.c.d" =
42− # rec { sha256 = $packageVersionSha256;
43− # revisions =
44− # { r0 = { outPath = ./hackage/...;
45− # sha256 = $packageVersionSha256;
46− # revision = $revNum;
47− # revisionSha256 = $revisionSha256; };
48− # default = revisions.r0;
49− # $revisionSha256 = revisions.r0; };
50− # };
51− # };
52− # };
53− # }
54−
55− hackageConfigs =
56− lib.flip lib.mapAttrs hackage
57− (pname: lib.mapAttrs
58− (vnum: version: version // {
59− revisions =
60− let
61− rev2Config = rev: {
62− inherit (version) sha256;
63− inherit (rev) outPath;
64− revision = rev.revNum;
65− revisionSha256 = rev.sha256;
66− };
67− f = rev: acc: acc // {
68− # If there's a collision (e.g. a revision was
69− # reverted), pick the one with the smaller
70− # revNum. They're identical, but if the smaller one is
71− # r0 then we don't have to download a cabal file.
72− ${rev.sha256} = if lib.hasAttr rev.sha256 acc && acc.${rev.sha256}.revNum < rev.revNum
73− then acc.${rev.sha256}
74− else rev;
75− };
76− contentAddressedRevs = lib.foldr f {} (builtins.attrValues version.revisions);
77− in lib.mapAttrs (_: rev2Config) (version.revisions // contentAddressedRevs);
78− }));
79−
80− # The planFunc (that is, a package set description like an LTS set
81− # or a plan.nix (derived from plan.json)) will then producde a structure
82− # that looks like:
83− #
84− # { packages = { "package" = { revision = hackageConfigs.$package.$version.revisions.default;
85− # flags = { flag1 = true; flag2 = false; ... }; };
86− # ... };
87− # compiler = { version = "X.Y.Z"; nix-name ="ghcXYZ";
88− # # packages that come bundled with the compiler
89− # packages = { "bytestring" = "a.b.c.d"; ... }; };
90− # }
91−
92− # package descriptions in hackage will look like:
93− # { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs }:
94− # { flags = { flag1 = false; flags2 = true; ... };
95− # package = { specVersion = "X.Y"; identifier = { name = "..."; version = "a.b.c.d"; };
96− # license = "..."; copyright = "..."; maintainer = "..."; author = "...";
97− # homepage = "..."; url = "..."; synopsis = "..."; description = "...";
98− # buildType = "Simple"; # or Custom, Autoconf, ...
99− # };
100− # components = {
101− # "..." = { depends = [ (hsPkgs.base) ... ]; };
102− # exes = { "..." = { depends = ... };
103− # "..." = { depends = ... }; };
104− # tests = { "..." = { depends = ... }; ... };
105− # };
106−
107− # The package descriptions depend on pkgs, which are used to resolve system package dependencies
108− # as well as pkgconfPkgs, which are used to resolve pkgconfig name to nixpkgs names. We simply
109− # augment the existing pkgs set with the specific mappings:
110− adjustedPkgs = pkgs // (import ./lib/system-nixpkgs-map.nix pkgs);
111− pkgconfPkgs = pkgs // (import ./lib/pkgconf-nixpkgs-map.nix pkgs);
112−
113− # it also crucially depends on system, and compiler, both of which need to be resolved to the
114− # current system being targetted.
115− hostMap = import ./lib/host-map.nix pkgs.stdenv;
116− cabal = import ./lib/cabal-os-arch-comp.nix;
117−
118− compiler = cabal.compiler // {
119− isGhc = true;
120− version = lib.mapAttrs (_: f: v: f (builtins.compareVersions plan.compiler.version v)) {
121− eq = c: c == 0;
122− gt = c: c > 0;
123− ge = c: c >= 0;
124− lt = c: c < 0;
125− le = c: c <= 0;
126− };
127− };
128− system = cabal.os // { "is${hostMap.os}" = true; }
129− // cabal.arch // { "is${hostMap.arch}" = true; };
130−
131− # Therefore the arguments we pass to the package are
132− pkgArgs = { inherit compiler system pkgconfPkgs; pkgs = adjustedPkgs; };
133−
134− # we can never reinstall the following set of packages:
135− nonReinstallables
136− = [ "rts" "ghc" "base" "ghc-prim" "array" "integer-gmp" "integer-simple"
137− "deepseq" "pretty" "ghc-boot-th" "template-haskell" "terminfo" ];
138− # Thus the final plan will contain
139− # { packages = hsPkgs: { "package" = { flags = ...; package = ...; components = ...; }; ... };
140− # compiler = ... };
141−
142− plan =
143− let p = planFunc hackageConfigs;
144− in p // {
145− packages = hsPkgs:
146− (lib.mapAttrs (pname: { revision, flags ? {} }: self:
147− # Set the flags with the rhs of the recursiveUpdate, but
148− # pass the final choice in flags using open recursion
149− # (provided with a refernece to self).
150− #
151− # NB: we can import revision, because revision.outPath is
152− # an importable path. Magic!
153− lib.recursiveUpdate (import revision (pkgArgs // { inherit hsPkgs; inherit (self) flags; })) {
154− inherit flags;
155− inherit (revision) sha256 revision revisionSha256;
156− }
157− )
158− p.packages)
159− // (lib.mapAttrs (pname: path: self:
160− import path (pkgArgs // { inherit hsPkgs; inherit (self) flags; })
161− )
162− extraDeps)
163− // (builtins.foldl' (acc: x: acc // { "${x}" = null; }) {} nonReinstallables)
164− ;
165− };
166−
167− hsPkgs = with haskellLib; weakCallPackage pkgs driver {
168− inherit haskellLib ghc weakCallPackage plan;
169− };
170−}))
1+{ hackage, pkgs, pkg-def, modules ? [] }: pkgs.lib.evalModules {
2+ modules = modules ++ [
3+ ({ lib, ... }: {
4+ # Provide all modules with haskellLib, pkgs, and pkgconfPkgs arguments
5+ _module.args = {
6+ # this is *not* the hasekllLib from nixpkgs; it is rather our own
7+ # library from haskell.nix
8+ haskellLib = let hl = import ./lib { inherit lib; haskellLib = hl; }; in hl;
9+
10+ # The package descriptions depend on pkgs, which are used to resolve system package dependencies
11+ # as well as pkgconfPkgs, which are used to resolve pkgconfig name to nixpkgs names. We simply
12+ # augment the existing pkgs set with the specific mappings:
13+ pkgs = pkgs // (import ./lib/system-nixpkgs-map.nix pkgs);
14+ pkgconfPkgs = pkgs // (import ./lib/pkgconf-nixpkgs-map.nix pkgs);
15+ };
16+
17+ # Set the hackage DB for modules/hackage.nix
18+ hackage.db = hackage;
19+
20+ # Set the plan for modules/plan.nix
21+ plan.pkg-def = pkg-def;
22+ })
23+
24+ # Supplies metadata
25+ ./modules/cabal.nix
26+
27+ # Converts config.packages into config.hsPkgs
28+ # Replace this with compat-driver.nix to use nixpkgs haskell build infra
29+ ./modules/component-driver.nix
30+
31+ # Converts config.hackage.db to config.hackage.configs
32+ ./modules/hackage.nix
33+
34+ # Converts config.hackage.configs and pkg-def to config.packages
35+ ./modules/plan.nix
36+ ];
37+}