Drop compat

Fixes #24
This commit is contained in:
Moritz Angermann 2019-01-25 17:58:53 +08:00
parent c0cb0756df
commit 26e147db4a
6 changed files with 87 additions and 282 deletions

1
compat.nix Normal file
View File

@ -0,0 +1 @@
{ license-map = import ./cabal-licenses.nix; platform-map = import ./cabal-os-arch-comp.nix; host-map = import ./host-map.nix; }

View File

@ -1,2 +0,0 @@
hackage:
{ license-map = import ./cabal-licenses.nix; platform-map = import ./cabal-os-arch-comp.nix; host-map = import ./host-map.nix; driver = import ./driver.nix hackage; }

View File

@ -1,56 +0,0 @@
{ lib, expr, mkDerivation }:
let
# utilities
collectAttr = a: s: lib.lists.fold (e: acc: (if e ? ${a} then e.${a} else []) ++ acc) [] (builtins.attrValues s);
# resolver for cabal license to nix license
resolve = { license = lib: license: (import ../lib/cabal-licenses.nix lib).${license}; };
#in mkDerivation ({
# These are the keys that <pkg>.override can override.
# the ... is used to allow to override all potential
# other keys, that the builder understands.
# { mkDerivation, stdenv, flags ? {}, hsPkgs ? {}, ... }@args:
#let
pname = expr.package.identifier.name;
pversion = expr.package.identifier.version;
builderArgs = {
inherit pname;
version = pversion;
isLibrary = builtins.hasAttr pname expr.components;
isExecutable = builtins.hasAttr "exes" expr.components;
homepage = expr.package.homepage;
description = expr.package.synopsis;
license = resolve.license lib expr.package.license;
configureFlags = lib.mapAttrsToList (flag: enabled: (if enabled then "-f" else "-f-") + flag) expr.flags;
} // lib.optionalAttrs (expr ? revision) {
revision = "${toString expr.revision}";
editedCabalFile = expr.revisionSha256;
} // lib.optionalAttrs (expr ? sha256) {
inherit (expr) sha256;
} // lib.optionalAttrs (builtins.hasAttr pname expr.components) {
libraryHaskellDepends = expr.components.${pname}.depends or [];
libraryPkgconfigDepends = expr.components.${pname}.pkgconfig or [];
librarySystemDepends = (expr.components.${pname}.libs or []); # ++ lib.optionals (os == "Osx") (expr.components.${pname}.frameworks or []);
libraryToolDepends = expr.components.${pname}.build-tools or [];
} // lib.optionalAttrs (builtins.hasAttr "exes" expr.components) {
executableHaskellDepends = collectAttr "depends" expr.components.exes;
executableToolDepends = collectAttr "build-tools" expr.components.exes;
} // lib.optionalAttrs (builtins.hasAttr "tests" expr.components) {
testHaskellDepends = collectAttr "depends" expr.components.tests;
} // lib.optionalAttrs (builtins.hasAttr "benchmarks" expr.components) {
benchmarkHaskellDepends = collectAttr "depends" expr.components.benchmarks;
} // lib.optionalAttrs (expr ? src) {
inherit (expr) src;
} // lib.optionalAttrs (expr ? postUnpack) {
inherit (expr) postUnpack;
}
#// builtins.removeAttrs args [ "mkDerivation" "stdenv" "flags" "hsPkgs" ];
;
in mkDerivation (builderArgs)
#// lib.optionalAttrs (expr.cabal-generator or "" == "hpack")
# { preConfigure = "hpack;" + (builderArgs.preConfigure or "");
# libraryToolDepends = builderArgs.libraryToolDepends ++ [ pkgs.haskellPackages.hpack ]; })

View File

@ -14,18 +14,18 @@ let
else v) else v)
(pkg-def hackage); (pkg-def hackage);
in in
hackage: let haskell = { hackage: let haskell = rec {
# ghc hackage patches. # ghc hackage patches.
# these are patches that turn hackage packages into the same as the ones # these are patches that turn hackage packages into the same as the ones
# ghc ships with the supposedly same version. See GHC Track Issue: 16199 # ghc ships with the supposedly same version. See GHC Track Issue: 16199
ghcHackagePatches = import ./patches; ghcHackagePatches = import ./patches;
compat = import ./compat hackage; compat = import ./compat.nix;
mkPkgSet = pkgs: pkg-def: import ./package-set.nix { inherit pkgs hackage haskell; pkg-def = strip-pkg-def pkgs pkg-def; };
# The *new* pkg set is one that build components. mkPkgSet
# This also uses the module system for much greater extensibility.
# To make extend and override things, pass a modules argument to new-package-set.nix
mkNewPkgSet
= { pkgs, pkg-def, pkg-def-overlays ? [], modules ? [] }@args: = { pkgs, pkg-def, pkg-def-overlays ? [], modules ? [] }@args:
import ./new-package-set.nix (args // { inherit hackage; pkg-def = strip-pkg-def pkgs pkg-def; }); import ./package-set.nix (args // { inherit hackage; pkg-def = strip-pkg-def pkgs pkg-def; });
mkNewPkgSet = args: builtins.trace "DEPRECATED: use mkPkgSet instead of mkNewPkgSet" (mkPkgSet args);
}; in haskell }; in haskell

View File

@ -1,88 +0,0 @@
let f = { hackage, pkgs, pkg-def, pkg-def-overlays ? [], modules ? [] }: let
buildModules = f { inherit hackage pkg-def pkg-def-overlays modules; pkgs = pkgs.buildPackages; };
in pkgs.lib.evalModules {
modules = modules ++ [
({ lib, ... }: {
# Provide all modules with haskellLib, pkgs, and pkgconfPkgs arguments
_module.args = {
# this is *not* the hasekllLib from nixpkgs; it is rather our own
# library from haskell.nix
haskellLib = let hl = import ./lib { inherit lib; haskellLib = hl; }; in hl;
# 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:
pkgs = pkgs // (import ./lib/system-nixpkgs-map.nix pkgs);
pkgconfPkgs = pkgs // (import ./lib/pkgconf-nixpkgs-map.nix pkgs);
inherit buildModules;
};
# Set the hackage DB for modules/hackage.nix
hackage.db = hackage;
# Set the plan for modules/plan.nix
plan.pkg-def = hackage: with builtins;
# The desugar reason.
#
# it is quite combersome to write
# (hackage: { packages.x.revision = hackage...;
# packages.y.revision = import ./foo.nix; })
# where we'd rather write:
# (hackage: { x = hackage...; })
# or
# { y = ./foo.nix; }
# As such the desugarer desugars this short hand syntax.
let desugar = overlay:
let
isPath = x: builtins.typeOf x == "path";
# rewrite
# { ... }
# into
# { package = { ... }; }
inject-packages = o: if o ? "packages" then o else { packages = o; };
# rewrite
# x = pkg;
# into
# x.revision = pkg;
inject-revision = pkg: if pkg ? "revision" then pkg else { revision = pkg; };
# rewrite
# x.revision = ./some/path;
# into
# x.revision = import ./some/path;
expand-paths = pkg: if !(isPath pkg.revision) then pkg else { revision = import pkg.revision; };
# apply injection and expansion to the "packages" in overlay.
in lib.mapAttrs (k: v: if k != "packages"
then v
else lib.mapAttrs (_: pkg: (expand-paths (inject-revision pkg))) v)
(inject-packages overlay);
# fold any potential `pkg-def-overlays`
# onto the `pkg-def`.
#
# This means you can have a base definition (e.g. stackage)
# and augment it with custom packages to your liking.
in foldl' lib.recursiveUpdate
(pkg-def hackage)
(map (p: desugar (if builtins.isFunction p then p hackage else p)) pkg-def-overlays)
;
})
# Supplies metadata
./modules/cabal.nix
# Converts config.packages into config.hsPkgs
# Replace this with compat-driver.nix to use nixpkgs haskell build infra
./modules/component-driver.nix
# Converts config.hackage.db to config.hackage.configs
./modules/hackage.nix
# Converts config.hackage.configs and pkg-def to config.packages
./modules/plan.nix
# Configuration that applies to all plans
./modules/configuration-nix.nix
];
};
in f

View File

@ -1,138 +1,88 @@
{ pkg-def let f = { hackage, pkgs, pkg-def, pkg-def-overlays ? [], modules ? [] }: let
, pkgs ? import <nixpkgs> {} buildModules = f { inherit hackage pkg-def pkg-def-overlays modules; pkgs = pkgs.buildPackages; };
, hackage ? import <hackage> in pkgs.lib.evalModules {
, haskell ? import <haskell> }: modules = modules ++ [
({ lib, ... }: {
# Provide all modules with haskellLib, pkgs, and pkgconfPkgs arguments
_module.args = {
# this is *not* the hasekllLib from nixpkgs; it is rather our own
# library from haskell.nix
haskellLib = let hl = import ./lib { inherit lib; haskellLib = hl; }; in hl;
{ extraDeps ? hsPkgs: {} }: # The package descriptions depend on pkgs, which are used to resolve system package dependencies
let # 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:
pkgs = pkgs // (import ./lib/system-nixpkgs-map.nix pkgs);
pkgconfPkgs = pkgs // (import ./lib/pkgconf-nixpkgs-map.nix pkgs);
# packages that we must never try to reinstall. inherit buildModules;
nonReinstallablePkgs = [ "rts" "ghc" "ghc-prim" "integer-gmp" "integer-simple" "base" };
"array" "deepseq" "pretty" "ghc-boot-th" "template-haskell"];
hackagePkgs = with pkgs.lib; # Set the hackage DB for modules/hackage.nix
let shippedPkgs = filterAttrs (n: _: builtins.elem n nonReinstallablePkgs) hackage.db = hackage;
(mapAttrs (name: version: { ${version} = { revisions = { default = null; }; }; })
(pkg-def {}).compiler.packages);
in recursiveUpdate hackage shippedPkgs;
# We may depend on packages shipped with ghc, or need to rebuild them. # Set the plan for modules/plan.nix
ghcPackages = pkgs.lib.mapAttrs (name: version: hackagePkgs.${name}.${version} plan.pkg-def = hackage: with builtins;
) (pkg-def {}).compiler.packages; # The desugar reason.
#
# it is quite combersome to write
# (hackage: { packages.x.revision = hackage...;
# packages.y.revision = import ./foo.nix; })
# where we'd rather write:
# (hackage: { x = hackage...; })
# or
# { y = ./foo.nix; }
# As such the desugarer desugars this short hand syntax.
let desugar = overlay:
let
isPath = x: builtins.typeOf x == "path";
# rewrite
# { ... }
# into
# { package = { ... }; }
inject-packages = o: if o ? "packages" then o else { packages = o; };
# rewrite
# x = pkg;
# into
# x.revision = pkg;
inject-revision = pkg: if pkg ? "revision" then pkg else { revision = pkg; };
# rewrite
# x.revision = ./some/path;
# into
# x.revision = import ./some/path;
expand-paths = pkg: if !(isPath pkg.revision) then pkg else { revision = import pkg.revision; };
# apply injection and expansion to the "packages" in overlay.
in lib.mapAttrs (k: v: if k != "packages"
then v
else lib.mapAttrs (_: pkg: (expand-paths (inject-revision pkg))) v)
(inject-packages overlay);
# fold any potential `pkg-def-overlays`
# onto the `pkg-def`.
#
# This means you can have a base definition (e.g. stackage)
# and augment it with custom packages to your liking.
in foldl' lib.recursiveUpdate
(pkg-def hackage)
(map (p: desugar (if builtins.isFunction p then p hackage else p)) pkg-def-overlays)
;
# Thus the final package set in our augmented (extrDeps) lts set is the following: })
ltsPkgs = ghcPackages
// (pkg-def hackagePkgs).packages
// extraDeps hackagePkgs;
driver = haskell.compat.driver; # Supplies metadata
host-map = haskell.compat.host-map; ./modules/cabal.nix
# compiler this lts set is built against. # Converts config.packages into config.hsPkgs
compiler = pkgs.haskell.packages.${(pkg-def {}).compiler.nix-name}; # Replace this with compat-driver.nix to use nixpkgs haskell build infra
./modules/component-driver.nix
# This is a tiny bit better than doJailbreak. # Converts config.hackage.db to config.hackage.configs
# ./modules/hackage.nix
# We essentially *know* the dependencies, and with the
# full cabal file representation, we also know all the
# flags. As such we can sidestep the solver.
#
# Pros:
# - no need for doJailbreak
# - no need for jailbreak-cabal to be built with
# Cabal2 if the cabal file requires it.
# - no reliance on --allow-newer, which only made
# a very short lived appearance in Cabal.
# (Cabal-2.0.0.2 -- Cabal-2.2.0.0)
#
# Cons:
# - automatic flag resolution won't happen and will
# have to be hard coded.
#
# Ideally we'd just inspect the haskell*Depends fields
# we feed the builder. However because we null out the
# lirbaries ghc ships (e.g. base, ghc, ...) this would
# result in an incomplete --dependency=<name>=<name>-<version>
# set and not lead to the desired outcome.
#
# If we could still have base, etc. not nulled, but
# produce some virtual derivation, that might allow us
# to just use the haskell*Depends fields to extract the
# name and version for each dependency.
#
# Ref: https://github.com/haskell/cabal/issues/3163#issuecomment-185833150
# ---
# ghc-pkg should be ${ghcCommand}-pkg; and --package-db
# should better be --${packageDbFlag}; but we don't have
# those variables in scope.
doExactConfig = pkgs: pkg: let targetPrefix = with pkgs.stdenv; lib.optionalString
(hostPlatform != buildPlatform)
"${hostPlatform.config}-";
in pkgs.haskell.lib.overrideCabal pkg (drv: { # Converts config.hackage.configs and pkg-def to config.packages
# TODO: need to run `ghc-pkg field <pkg> id` over all `--dependency` ./modules/plan.nix
# values. Should we encode the `id` in the nix-pkg as well?
preConfigure = (drv.preConfigure or "") + ''
configureFlags+=" --exact-configuration"
globalPackages=$(${targetPrefix}ghc-pkg list --global --simple-output)
localPackages=$(${targetPrefix}ghc-pkg --package-db="$packageConfDir" list --simple-output)
for pkg in $globalPackages; do
pkgName=''${pkg%-*}
if [ "$pkgName" != "rts" ]; then
if [[ " ${pkgs.lib.concatStringsSep " " nonReinstallablePkgs} " =~ " $pkgName " ]]; then
configureFlags+=" --dependency="''${pkg%-*}=$pkg
fi
fi
done
for pkg in $localPackages; do
configureFlags+=" --dependency="''${pkg%-*}=$pkg
done
#echo "<<< <<< <<<"
#echo ''${configureFlags}
configureFlags=$(for flag in ''${configureFlags};do case "X''${flag}" in
X--dependency=*)
pkgId=$(${targetPrefix}ghc-pkg --package-db="$packageConfDir" field ''${flag##*=} id || ${targetPrefix}ghc-pkg --global field ''${flag##*=} id)
echo ''${flag%=*}=$(echo $pkgId | awk -F' ' '{ print $2 }')
;;
*) echo ''${flag};;
esac; done)
#echo "--- --- ---"
#echo ''${configureFlags}
#echo ">>> >>> >>>"
'';
});
toGenericPackage = stackPkgs: args: name: path: # Configuration that applies to all plans
let path' = pkgs.lib.traceVal path.revision.outPath # either a fixed revision from, say plan.nix ./modules/configuration-nix.nix
# or path.revisions.default.outPath # a package which doesn't have a revision specified; assume we want the default. ];
or path.revision };
or path; # or a direct path in f
in
if path' == null then null else
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
# right compiler.
in compiler.callPackage expr args;
in let stackPackages = pkgs: self:
(let p = (pkgs.lib.mapAttrs (toGenericPackage self {}) ltsPkgs);
# for all packages do the `exactConfig` logic. That is, we
# *know* that that our package-db contains only a single valid
# set of proper packages. So we can sidestep cabals solver.
in (pkgs.lib.mapAttrs (_: v: if v == null
then null
else doExactConfig pkgs v) p)
// (with pkgs.haskell.lib;
{ doctest = null;
hsc2hs = null;
buildPackages = pkgs.buildPackages.haskellPackages; }));
in compiler.override {
initialPackages = { pkgs, stdenv, callPackage }: self: (stackPackages pkgs self);
configurationCommon = { ... }: self: super: {};
compilerConfig = self: super: {};
}