@@ -4,19 +4,71 @@
4, driver ? ./nix/component-driver.nix
4, driver ? ./nix/component-driver.nix
7+{ extraDeps ? hsPkgs: {} }:
7(pkgs.lib.fix (self: with self; {
8(pkgs.lib.fix (self: with self; {
8 inherit (pkgs) lib stdenv;
9 inherit (pkgs) lib stdenv;
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.
9 ghc = pkgs.haskell.compiler.${plan.compiler.nix-name};
15 ghc = pkgs.haskell.compiler.${plan.compiler.nix-name};
11 # Avoid pkgs.callPackage for now. It does a lot of nonsense with OOP
17 # Avoid pkgs.callPackage for now. It does a lot of nonsense with OOP
12 # style programming that we should avoid until we know we want it.
18 # style programming that we should avoid until we know we want it.
20+ # weakCallPackage: call a function or (importable expression)
23+ # weakCallPackage scope f args
24+ # will call f (scope // args)
26+ # weakCallpackage scope ./path args
27+ # will call the expression at ./path with (scope // args)
13 weakCallPackage = scope: f: args:
29 weakCallPackage = scope: f: args:
14 let f' = if lib.isFunction f then f else import f;
30 let f' = if lib.isFunction f then f else import f;
15 args' = scope // args;
31 args' = scope // args;
16 in f' (builtins.intersectAttrs (builtins.functionArgs f') args');
32 in f' (builtins.intersectAttrs (builtins.functionArgs f') args');
34+ # this is *not* the hasekllLib from nixpkgs; it is rather our own
35+ # library from haskell.nix
18 haskellLib = import ./lib { inherit lib haskellLib; };
36 haskellLib = import ./lib { inherit lib haskellLib; };
38+ # hackage looks like the following:
41+ # rec { sha256 = $pkgVersionSha256;
43+ # { r0 = { outPath = ./hackage/...; revNum = 0; sha256 = $revisionSha256; };
44+ # default = revisions.r0; };
51+ # However it's more convenient to deal with the leaf nodes, and as such
52+ # push the `sha256` of the package/version into the revision and keep the
53+ # revision.sha256 as revisionSha256; as well as making the revision content
54+ # addressable by it's revision hash.
56+ # Thus we transform hackage into hackageConfigs, which will look like:
59+ # rec { sha256 = $packageVersionSha256;
61+ # { r0 = { outPath = ./hackage/...;
62+ # sha256 = $packageVersionSha256;
63+ # revision = $revNum;
64+ # revisionSha256 = $revisionSha256; };
65+ # default = revisions.r0;
66+ # $revisionSha256 = revisions.r0; };
20 hackageConfigs =
72 hackageConfigs =
21 lib.flip lib.mapAttrs hackage
73 lib.flip lib.mapAttrs hackage
22 (pname: lib.mapAttrs
74 (pname: lib.mapAttrs
@@ -41,26 +93,43 @@
41 contentAddressedRevs = lib.foldr f {} (builtins.attrValues version.revisions);
93 contentAddressedRevs = lib.foldr f {} (builtins.attrValues version.revisions);
42 in lib.mapAttrs (_: rev2Config) (version.revisions // contentAddressedRevs);
94 in lib.mapAttrs (_: rev2Config) (version.revisions // contentAddressedRevs);
45− let p = planFunc hackageConfigs;
50− inherit hsPkgs compiler system pkgconfPkgs;
53− in lib.mapAttrs (pname: { revision, flags ? {} }: self:
54− # Set the flags with the rhs of the recursiveUpdate, but
55− # pass the final choice in flags using open recursion.
56− lib.recursiveUpdate (import revision (args // { inherit (self) flags; })) {
58− inherit (revision) sha256 revision revisionSha256;
97+ # The planFunc (that is, a package set description like an LTS set
98+ # or a plan.nix (derived from plan.json)) will then producde a structure
101+ # { packages = { "package" = { revision = hackageConfigs.$package.$version.revisions.default;
102+ # flags = { flag1 = true; flag2 = false; ... }; };
104+ # compiler = { version = "X.Y.Z"; nix-name ="ghcXYZ";
105+ # # packages that come bundled with the compiler
106+ # packages = { "bytestring" = "a.b.c.d"; ... }; };
109+ # package descriptions in hackage will look like:
110+ # { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs }:
111+ # { flags = { flag1 = false; flags2 = true; ... };
112+ # package = { specVersion = "X.Y"; identifier = { name = "..."; version = "a.b.c.d"; };
113+ # license = "..."; copyright = "..."; maintainer = "..."; author = "...";
114+ # homepage = "..."; url = "..."; synopsis = "..."; description = "...";
115+ # buildType = "Simple"; # or Custom, Autoconf, ...
118+ # "..." = { depends = [ (hsPkgs.base) ... ]; };
119+ # exes = { "..." = { depends = ... };
120+ # "..." = { depends = ... }; };
121+ # tests = { "..." = { depends = ... }; ... };
124+ # The package descriptions depend on pkgs, which are used to resolve system package dependencies
125+ # as well as pkgconfPkgs, which are used to resolve pkgconfig name to nixpkgs names. We simply
126+ # augment the existing pkgs set with the specific mappings:
127+ adjustedPkgs = pkgs // (import ./lib/system-nixpkgs-map.nix pkgs);
128+ pkgconfPkgs = pkgs // (import ./lib/pkgconf-nixpkgs-map.nix pkgs);
130+ # it also crucially depends on system, and compiler, both of which need to be resolved to the
131+ # current system being targetted.
132+ hostMap = import ./lib/host-map.nix pkgs.stdenv;
64 cabal = import ./lib/cabal-os-arch-comp.nix;
133 cabal = import ./lib/cabal-os-arch-comp.nix;
66 compiler = cabal.compiler // {
135 compiler = cabal.compiler // {
@@ -73,17 +142,44 @@
73 le = c: c <= 0;
142 le = c: c <= 0;
77− hostMap = import ./lib/host-map.nix pkgs.stdenv;
78− in cabal.os // { "is${hostMap.os}" = true; }
145+ system = cabal.os // { "is${hostMap.os}" = true; }
79− // cabal.arch // { "is${hostMap.arch}" = true; };
146+ // cabal.arch // { "is${hostMap.arch}" = true; };
81− adjustedPkgs = pkgs // (import ./lib/system-nixpkgs-map.nix pkgs);
148+ # Therefore the arguments we pass to the package are
82− pkgconfPkgs = pkgs // (import ./lib/pkgsconf-nixpkgs-map.nix pkgs);
149+ pkgArgs = { inherit compiler system pkgconfPkgs; pkgs = adjustedPkgs; };
83− # hsPkgs = adjustedPkgs
150+
84− # // { buildPackages = hsPkgs; }
151+ # we can never reinstall the following set of packages:
85− # // lib.mapAttrs (_: _: null) (plan.compiler.packages // { hsc2hs = "0.68.2"; })
152+ nonReinstallables
86− # // lib.mapAttrs (_: driver) configs;
153+ = [ "rts" "ghc" "base" "ghc-prim" "array" "integer-gmp" "integer-simple"
154+ "deepseq" "pretty" "ghc-boot-th" "template-haskell" ];
155+ # Thus the final plan will contain
156+ # { packages = hsPkgs: { "package" = { flags = ...; package = ...; components = ...; }; ... };
160+ let p = planFunc hackageConfigs;
163+ (lib.mapAttrs (pname: { revision, flags ? {} }: self:
164+ # Set the flags with the rhs of the recursiveUpdate, but
165+ # pass the final choice in flags using open recursion
166+ # (provided with a refernece to self).
168+ # NB: we can import revision, because revision.outPath is
169+ # an importable path. Magic!
170+ lib.recursiveUpdate (import revision (pkgArgs // { inherit hsPkgs; inherit (self) flags; })) {
172+ inherit (revision) sha256 revision revisionSha256;
176+ // (lib.mapAttrs (pname: path: self:
177+ import path (pkgArgs // { inherit hsPkgs; inherit (self) flags; })
180+ // (builtins.foldl' (acc: x: acc // { "${x}" = null; }) {} nonReinstallables)
88 hsPkgs = weakCallPackage pkgs driver {
184 hsPkgs = weakCallPackage pkgs driver {
89 inherit haskellLib ghc weakCallPackage plan;
185 inherit haskellLib ghc weakCallPackage plan;