make it work

This commit is contained in:
Moritz Angermann 2018-10-25 09:25:08 +08:00
parent 03610ebc16
commit f08973b609
6 changed files with 131 additions and 33 deletions

View File

@ -56,7 +56,7 @@ in stdenv.mkDerivation {
meta = {
homepage = package.homepage;
description = package.synopsis;
license = (import ./cabal-licenses.nix lib).${package.license};
license = (import ../lib/cabal-licenses.nix lib).${package.license};
};
CABAL_CONFIG = writeText

View File

@ -1,4 +1,6 @@
hackage: let haskell = {
compat = import ./compat hackage;
mkPkgSet = pkgs: pkg-def: import ./package-set.nix { inherit pkg-def pkgs hackage haskell; };
# The *new* pkg set is one that build components.
mkNewPkgSet = pkgs: pkg-def: import ./new-package-set.nix { inherit pkgs hackage; planFunc = pkg-def; };
}; in haskell

View File

@ -8,4 +8,4 @@ pkgs: {
libR = pkgs.R;
fftw3f = pkgs.fftwFloat;
fftw3 = pkgs.fftw;
};
}

View File

@ -4,19 +4,71 @@
, driver ? ./nix/component-driver.nix
}:
{ extraDeps ? hsPkgs: {} }:
(pkgs.lib.fix (self: with self; {
inherit (pkgs) lib stdenv;
# obtain the compiler from the haskell packages.
# this should allow us to use `config` overrides
# in the nixpkgs setup, and properly override the
# complier as needed.
ghc = pkgs.haskell.compiler.${plan.compiler.nix-name};
# Avoid pkgs.callPackage for now. It does a lot of nonsense with OOP
# style programming that we should avoid until we know we want it.
# weakCallPackage: call a function or (importable expression)
# with scope + args.
#
# weakCallPackage scope f args
# will call f (scope // args)
#
# weakCallpackage scope ./path args
# will call the expression at ./path with (scope // args)
#
weakCallPackage = scope: f: args:
let f' = if lib.isFunction f then f else import f;
args' = scope // args;
in f' (builtins.intersectAttrs (builtins.functionArgs f') args');
# this is *not* the hasekllLib from nixpkgs; it is rather our own
# library from haskell.nix
haskellLib = import ./lib { inherit lib haskellLib; };
# hackage looks like the following:
# { "package-name" =
# { "a.b.c.d" =
# rec { sha256 = $pkgVersionSha256;
# revisions =
# { r0 = { outPath = ./hackage/...; revNum = 0; sha256 = $revisionSha256; };
# default = revisions.r0; };
# };
# };
# };
# }
# However it's more convenient to deal with the leaf nodes, and as such
# push the `sha256` of the package/version into the revision and keep the
# revision.sha256 as revisionSha256; as well as making the revision content
# addressable by it's revision hash.
#
# Thus we transform hackage into hackageConfigs, which will look like:
# { "package-name" =
# { "a.b.c.d" =
# rec { sha256 = $packageVersionSha256;
# revisions =
# { r0 = { outPath = ./hackage/...;
# sha256 = $packageVersionSha256;
# revision = $revNum;
# revisionSha256 = $revisionSha256; };
# default = revisions.r0;
# $revisionSha256 = revisions.r0; };
# };
# };
# };
# }
hackageConfigs =
lib.flip lib.mapAttrs hackage
(pname: lib.mapAttrs
@ -41,26 +93,43 @@
contentAddressedRevs = lib.foldr f {} (builtins.attrValues version.revisions);
in lib.mapAttrs (_: rev2Config) (version.revisions // contentAddressedRevs);
}));
plan =
let p = planFunc hackageConfigs;
in p // {
packages = hsPkgs:
let
args = {
inherit hsPkgs compiler system pkgconfPkgs;
pkgs = adjustedPkgs;
};
in lib.mapAttrs (pname: { revision, flags ? {} }: self:
# Set the flags with the rhs of the recursiveUpdate, but
# pass the final choice in flags using open recursion.
lib.recursiveUpdate (import revision (args // { inherit (self) flags; })) {
inherit flags;
inherit (revision) sha256 revision revisionSha256;
}
)
p.packages;
};
# The planFunc (that is, a package set description like an LTS set
# or a plan.nix (derived from plan.json)) will then producde a structure
# that looks like:
#
# { packages = { "package" = { revision = hackageConfigs.$package.$version.revisions.default;
# flags = { flag1 = true; flag2 = false; ... }; };
# ... };
# compiler = { version = "X.Y.Z"; nix-name ="ghcXYZ";
# # packages that come bundled with the compiler
# packages = { "bytestring" = "a.b.c.d"; ... }; };
# }
# package descriptions in hackage will look like:
# { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs }:
# { flags = { flag1 = false; flags2 = true; ... };
# package = { specVersion = "X.Y"; identifier = { name = "..."; version = "a.b.c.d"; };
# license = "..."; copyright = "..."; maintainer = "..."; author = "...";
# homepage = "..."; url = "..."; synopsis = "..."; description = "...";
# buildType = "Simple"; # or Custom, Autoconf, ...
# };
# components = {
# "..." = { depends = [ (hsPkgs.base) ... ]; };
# exes = { "..." = { depends = ... };
# "..." = { depends = ... }; };
# tests = { "..." = { depends = ... }; ... };
# };
# The package descriptions depend on pkgs, which are used to resolve system package dependencies
# as well as pkgconfPkgs, which are used to resolve pkgconfig name to nixpkgs names. We simply
# augment the existing pkgs set with the specific mappings:
adjustedPkgs = pkgs // (import ./lib/system-nixpkgs-map.nix pkgs);
pkgconfPkgs = pkgs // (import ./lib/pkgconf-nixpkgs-map.nix pkgs);
# it also crucially depends on system, and compiler, both of which need to be resolved to the
# current system being targetted.
hostMap = import ./lib/host-map.nix pkgs.stdenv;
cabal = import ./lib/cabal-os-arch-comp.nix;
compiler = cabal.compiler // {
@ -73,17 +142,44 @@
le = c: c <= 0;
};
};
system = let
hostMap = import ./lib/host-map.nix pkgs.stdenv;
in cabal.os // { "is${hostMap.os}" = true; }
// cabal.arch // { "is${hostMap.arch}" = true; };
system = cabal.os // { "is${hostMap.os}" = true; }
// cabal.arch // { "is${hostMap.arch}" = true; };
adjustedPkgs = pkgs // (import ./lib/system-nixpkgs-map.nix pkgs);
pkgconfPkgs = pkgs // (import ./lib/pkgsconf-nixpkgs-map.nix pkgs);
# hsPkgs = adjustedPkgs
# // { buildPackages = hsPkgs; }
# // lib.mapAttrs (_: _: null) (plan.compiler.packages // { hsc2hs = "0.68.2"; })
# // lib.mapAttrs (_: driver) configs;
# Therefore the arguments we pass to the package are
pkgArgs = { inherit compiler system pkgconfPkgs; pkgs = adjustedPkgs; };
# we can never reinstall the following set of packages:
nonReinstallables
= [ "rts" "ghc" "base" "ghc-prim" "array" "integer-gmp" "integer-simple"
"deepseq" "pretty" "ghc-boot-th" "template-haskell" ];
# Thus the final plan will contain
# { packages = hsPkgs: { "package" = { flags = ...; package = ...; components = ...; }; ... };
# compiler = ... };
plan =
let p = planFunc hackageConfigs;
in p // {
packages = hsPkgs:
(lib.mapAttrs (pname: { revision, flags ? {} }: self:
# Set the flags with the rhs of the recursiveUpdate, but
# pass the final choice in flags using open recursion
# (provided with a refernece to self).
#
# NB: we can import revision, because revision.outPath is
# an importable path. Magic!
lib.recursiveUpdate (import revision (pkgArgs // { inherit hsPkgs; inherit (self) flags; })) {
inherit flags;
inherit (revision) sha256 revision revisionSha256;
}
)
p.packages)
// (lib.mapAttrs (pname: path: self:
import path (pkgArgs // { inherit hsPkgs; inherit (self) flags; })
)
extraDeps)
// (builtins.foldl' (acc: x: acc // { "${x}" = null; }) {} nonReinstallables)
;
};
hsPkgs = weakCallPackage pkgs driver {
inherit haskellLib ghc weakCallPackage plan;

View File

@ -6,6 +6,5 @@ let
in
lib.fix (self:
{ buildPackages = self; }
// lib.mapAttrs (_: _: null) plan.compiler.packages
// lib.mapAttrs (_: pkg: new-builder (lib.fix pkg)) (plan.packages self)
// lib.mapAttrs (_: pkg: if pkg == null then null else new-builder (lib.fix pkg)) (plan.packages self)
)

View File

@ -112,6 +112,7 @@ let
let expr = driver {
cabalexpr = import path';
pkgs = pkgs // { haskellPackages = stackPkgs; };
lib = pkgs.lib;
inherit (host-map pkgs.stdenv) os arch;
version = compiler.ghc.version; };
# Use `callPackage` from the `compiler` here, to get the