mirror of
https://github.com/ilyakooo0/haskell.nix.git
synced 2024-09-11 06:55:40 +03:00
Allows project to be easily extended. (#1467)
* Allows project to be easily extended. * Add common project overlays
This commit is contained in:
parent
f1bb3aa2f2
commit
b66b0445eb
@ -167,6 +167,7 @@ Then feeding its result into [mkCabalProjectPkgSet](#mkcabalprojectpkgset) passi
|
||||
| `ghcWithPackages` | Function | [`ghcWithPackages`](#ghcwithpackages) |
|
||||
| `projectCross` | Attrset | Like `pkgs.pkgsCross.<system>` from nixpkgs `p.projectCross.<system>` returns the project results for cross compilation (where system is a member of nixpkgs lib.systems.examples). So `p.projectCross.ghcjs.hsPkgs` is the same as `hsPkgs` but compiled with ghcjs |
|
||||
| `appendModule` | Function | Re-eval the project with an extra module (or module list). |
|
||||
| `extend` and `appendOverlays` | Function | Modify a project, or add attributes, through overlays: `p.extend(final: prev: { })`. The overlays are carried-over `projectCross` and `appendModule` invocations. |
|
||||
|
||||
## project, cabalProject and stackProject
|
||||
|
||||
|
@ -340,4 +340,8 @@ in {
|
||||
# Converts from a `compoent.depends` value to a library derivation.
|
||||
# In the case of sublibs the `depends` value should already be the derivation.
|
||||
dependToLib = d: d.components.library or d;
|
||||
|
||||
projectOverlays = import ./project-overlays.nix {
|
||||
inherit lib haskellLib;
|
||||
};
|
||||
}
|
||||
|
114
lib/project-overlays.nix
Normal file
114
lib/project-overlays.nix
Normal file
@ -0,0 +1,114 @@
|
||||
{
|
||||
lib
|
||||
, haskellLib
|
||||
}: {
|
||||
devshell = final: prev: {
|
||||
devshell = let
|
||||
cabal-install = final.pkgs.buildPackages.haskell-nix.cabal-install.${final.args.compiler-nix-name};
|
||||
inherit (final.pkgs.buildPackages) runCommand runtimeShell;
|
||||
cabalWrapper = runCommand "cabal" { inherit (cabal-install) meta; } ''
|
||||
mkdir -p $out/bin
|
||||
cat << EOF > $out/bin/cabal
|
||||
#!${runtimeShell}
|
||||
set -euo pipefail
|
||||
|
||||
find_up() {
|
||||
while [[ \$PWD != / ]] ; do
|
||||
if [[ -e "\$1" ]]; then
|
||||
echo "\$PWD"
|
||||
return
|
||||
fi
|
||||
cd ..
|
||||
done
|
||||
}
|
||||
|
||||
toplevel=\$(find_up "cabal.project")
|
||||
|
||||
if [[ -n "\$toplevel" ]]; then
|
||||
cabal_project="\$toplevel/cabal.project"
|
||||
nix_cabal_project=\$toplevel/.nix-cabal.project
|
||||
extra_cabal_opts=("--project-file=\$nix_cabal_project")
|
||||
awk '
|
||||
# Add comment with explanation of file
|
||||
BEGIN {
|
||||
print "-- Generated from '"\$cabal_project"' by the wrapper script"
|
||||
print "-- ${placeholder "out"}/cabal"
|
||||
print "-- Add this file to your .gitignore\n"
|
||||
}
|
||||
|
||||
# Matches all section starts
|
||||
/^[^ ]/ {
|
||||
# Remember the section name (they can span multiple lines)
|
||||
section = \$0
|
||||
}
|
||||
# Matches every line
|
||||
// {
|
||||
# Only print the line if it is not in the section we want to omit
|
||||
if (section != "source-repository-package")
|
||||
print \$0
|
||||
}
|
||||
' "\$cabal_project" > "\$nix_cabal_project"
|
||||
else
|
||||
extra_cabal_opts=()
|
||||
fi
|
||||
|
||||
cabal=${placeholder "out"}/bin/.cabal
|
||||
>&2 echo "\$cabal \''${extra_cabal_opts[@]} \$@"
|
||||
exec "\$cabal" "\''${extra_cabal_opts[@]}" "\$@"
|
||||
EOF
|
||||
cp -rn ${cabal-install}/* $out/
|
||||
cp ${cabal-install}/bin/cabal $out/bin/.cabal
|
||||
chmod +x $out/bin/*
|
||||
'';
|
||||
in {
|
||||
packages = final.shell.nativeBuildInputs;
|
||||
env = lib.mapAttrsToList lib.nameValuePair {
|
||||
inherit (final.shell) CABAL_CONFIG NIX_GHC_LIBDIR;
|
||||
};
|
||||
commands = [
|
||||
{
|
||||
package = cabalWrapper;
|
||||
category = "development";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
projectComponents = final: prev: let
|
||||
packages = haskellLib.selectProjectPackages final.hsPkgs;
|
||||
# used to materialize `packages-exes.nix` (project packages and exes list) to avoid some evaluations:
|
||||
packagesExes = lib.genAttrs
|
||||
(lib.attrNames final.packages)
|
||||
(name: lib.attrNames final.hsPkgs.${name}.components.exes);
|
||||
collectExes = packagesExes: lib.listToAttrs (lib.concatLists (lib.mapAttrsToList
|
||||
(p: map (exe: lib.nameValuePair exe final.hsPkgs.${p}.components.exes.${exe})) packagesExes));
|
||||
in {
|
||||
# local project packages:
|
||||
packages = haskellLib.selectProjectPackages final.hsPkgs;
|
||||
# set of all exes (as first level entries):
|
||||
exes = collectExes packagesExes;
|
||||
# set of all exes (as first level entries), mapped from a materialized set of packages and exes set (generated via `generatePackagesExes`):
|
||||
exesFrom = packagesExesMat: collectExes (import packagesExesMat);
|
||||
# `tests` are the test suites which have been built.
|
||||
tests = haskellLib.collectComponents' "tests" final.packages;
|
||||
# `benchmarks` (only built, not run).
|
||||
benchmarks = haskellLib.collectComponents' "benchmarks" final.packages;
|
||||
# `checks` collect results of executing the tests:
|
||||
checks = haskellLib.collectChecks' final.packages;
|
||||
|
||||
generatePackagesExesMat = let
|
||||
nixFile = builtins.toFile "packages-exes.nix" (lib.generators.toPretty {} packagesExes);
|
||||
in final.pkgs.buildPackages.writeShellScript "generate-packages-exes" ''
|
||||
set -euo pipefail
|
||||
|
||||
TARGET="$1"
|
||||
TARGET_DIR="$(dirname "$TARGET")"
|
||||
|
||||
mkdir -p "$TARGET_DIR"
|
||||
rm -rf "$TARGET"
|
||||
cp -r ${nixFile} "$TARGET"
|
||||
chmod -R +w "$TARGET"
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
@ -546,12 +546,19 @@ final: prev: {
|
||||
};
|
||||
in project);
|
||||
|
||||
|
||||
# Take `hsPkgs` from the `rawProject` and update all the packages and
|
||||
# components so they have a `.project` attribute and as well as
|
||||
# a `.package` attribute on the components.
|
||||
addProjectAndPackageAttrs = rawProject:
|
||||
final.lib.fix (project':
|
||||
addProjectAndPackageAttrs = let
|
||||
# helper function similar to nixpkgs 'makeExtensible' but that keep track
|
||||
# of extension function so that it can be reused to extend another project:
|
||||
makeExtensible = f: rattrs: final.lib.fix (final.lib.extends f (self: rattrs self // {
|
||||
__overlay__ = f;
|
||||
extend = f: makeExtensible (final.lib.composeExtensions self.__overlay__ f) rattrs;
|
||||
appendOverlays = extraOverlays: self.extend (final.lib.composeManyExtensions ([self.__overlay__] ++ extraOverlays));
|
||||
}));
|
||||
in rawProject:
|
||||
makeExtensible (final: prev: {}) (project':
|
||||
let project = project' // { recurseForDerivations = false; };
|
||||
in rawProject // rec {
|
||||
# It is often handy to be able to get nix pkgs from the project.
|
||||
@ -601,17 +608,21 @@ final: prev: {
|
||||
# `projectCross.<system>` where system is a member of nixpkgs lib.systems.examples.
|
||||
# See https://nixos.wiki/wiki/Cross_Compiling
|
||||
projectCross = (final.lib.mapAttrs (_: pkgs:
|
||||
rawProject.projectFunction pkgs.haskell-nix rawProject.projectModule
|
||||
(rawProject.projectFunction pkgs.haskell-nix rawProject.projectModule)
|
||||
# Re-apply overlay from original project:
|
||||
.extend project.__overlay__
|
||||
) final.pkgsCross) // { recurseForDerivations = false; };
|
||||
|
||||
# re-eval this project with an extra module (or module list).
|
||||
appendModule = extraProjectModule: rawProject.projectFunction final.haskell-nix
|
||||
appendModule = extraProjectModule: (rawProject.projectFunction final.haskell-nix
|
||||
((if builtins.isList rawProject.projectModule
|
||||
then rawProject.projectModule
|
||||
else [rawProject.projectModule])
|
||||
++ (if builtins.isList extraProjectModule
|
||||
then extraProjectModule
|
||||
else [extraProjectModule]));
|
||||
else [extraProjectModule])))
|
||||
# Re-apply overlay from original project:
|
||||
.extend project.__overlay__;
|
||||
|
||||
# Add support for passing in `crossPlatforms` argument.
|
||||
# crossPlatforms is an easy way to include the inputs for a basic
|
||||
|
Loading…
Reference in New Issue
Block a user