@@ -0,0 +1,114 @@
1+{
2+ lib
3+, haskellLib
4+}: {
5+ devshell = final: prev: {
6+ devshell = let
7+ cabal-install = final.pkgs.buildPackages.haskell-nix.cabal-install.${final.args.compiler-nix-name};
8+ inherit (final.pkgs.buildPackages) runCommand runtimeShell;
9+ cabalWrapper = runCommand "cabal" { inherit (cabal-install) meta; } ''
10+ mkdir -p $out/bin
11+ cat << EOF > $out/bin/cabal
12+ #!${runtimeShell}
13+ set -euo pipefail
14+
15+ find_up() {
16+ while [[ \$PWD != / ]] ; do
17+ if [[ -e "\$1" ]]; then
18+ echo "\$PWD"
19+ return
20+ fi
21+ cd ..
22+ done
23+ }
24+
25+ toplevel=\$(find_up "cabal.project")
26+
27+ if [[ -n "\$toplevel" ]]; then
28+ cabal_project="\$toplevel/cabal.project"
29+ nix_cabal_project=\$toplevel/.nix-cabal.project
30+ extra_cabal_opts=("--project-file=\$nix_cabal_project")
31+ awk '
32+ # Add comment with explanation of file
33+ BEGIN {
34+ print "-- Generated from '"\$cabal_project"' by the wrapper script"
35+ print "-- ${placeholder "out"}/cabal"
36+ print "-- Add this file to your .gitignore\n"
37+ }
38+
39+ # Matches all section starts
40+ /^[^ ]/ {
41+ # Remember the section name (they can span multiple lines)
42+ section = \$0
43+ }
44+ # Matches every line
45+ // {
46+ # Only print the line if it is not in the section we want to omit
47+ if (section != "source-repository-package")
48+ print \$0
49+ }
50+ ' "\$cabal_project" > "\$nix_cabal_project"
51+ else
52+ extra_cabal_opts=()
53+ fi
54+
55+ cabal=${placeholder "out"}/bin/.cabal
56+ >&2 echo "\$cabal \''${extra_cabal_opts[@]} \$@"
57+ exec "\$cabal" "\''${extra_cabal_opts[@]}" "\$@"
58+ EOF
59+ cp -rn ${cabal-install}/* $out/
60+ cp ${cabal-install}/bin/cabal $out/bin/.cabal
61+ chmod +x $out/bin/*
62+ '';
63+ in {
64+ packages = final.shell.nativeBuildInputs;
65+ env = lib.mapAttrsToList lib.nameValuePair {
66+ inherit (final.shell) CABAL_CONFIG NIX_GHC_LIBDIR;
67+ };
68+ commands = [
69+ {
70+ package = cabalWrapper;
71+ category = "development";
72+ }
73+ ];
74+ };
75+ };
76+
77+ projectComponents = final: prev: let
78+ packages = haskellLib.selectProjectPackages final.hsPkgs;
79+ # used to materialize `packages-exes.nix` (project packages and exes list) to avoid some evaluations:
80+ packagesExes = lib.genAttrs
81+ (lib.attrNames final.packages)
82+ (name: lib.attrNames final.hsPkgs.${name}.components.exes);
83+ collectExes = packagesExes: lib.listToAttrs (lib.concatLists (lib.mapAttrsToList
84+ (p: map (exe: lib.nameValuePair exe final.hsPkgs.${p}.components.exes.${exe})) packagesExes));
85+ in {
86+ # local project packages:
87+ packages = haskellLib.selectProjectPackages final.hsPkgs;
88+ # set of all exes (as first level entries):
89+ exes = collectExes packagesExes;
90+ # set of all exes (as first level entries), mapped from a materialized set of packages and exes set (generated via `generatePackagesExes`):
91+ exesFrom = packagesExesMat: collectExes (import packagesExesMat);
92+ # `tests` are the test suites which have been built.
93+ tests = haskellLib.collectComponents' "tests" final.packages;
94+ # `benchmarks` (only built, not run).
95+ benchmarks = haskellLib.collectComponents' "benchmarks" final.packages;
96+ # `checks` collect results of executing the tests:
97+ checks = haskellLib.collectChecks' final.packages;
98+
99+ generatePackagesExesMat = let
100+ nixFile = builtins.toFile "packages-exes.nix" (lib.generators.toPretty {} packagesExes);
101+ in final.pkgs.buildPackages.writeShellScript "generate-packages-exes" ''
102+ set -euo pipefail
103+
104+ TARGET="$1"
105+ TARGET_DIR="$(dirname "$TARGET")"
106+
107+ mkdir -p "$TARGET_DIR"
108+ rm -rf "$TARGET"
109+ cp -r ${nixFile} "$TARGET"
110+ chmod -R +w "$TARGET"
111+ '';
112+ };
113+
114+}