haskell-te: f5d9b0b4404b6f45ddb4c063be4ce0cc5b488b7e
1: { bash, checkStderr, fail, haskellPackages, haskellPkgNameVersion,
2: haveVar, hsNameVersion, jq, lib, mkBin, python, runCommand, withDeps,
3: writeScript }:
4: with builtins;
5: with lib;
6:
7: with rec {
8: inherit (haskellPackages) cabal-install;
9:
10: # Runs AstPlugin. Requires GHC_PKG to point at a pkg-db containing all of
11: # the required dependencies, plus AstPlugin
12: runAstPluginRaw = mkBin {
13: name = "runAstPluginRaw";
14: paths = [ bash ];
15: script = ''
16: #!${bash}/bin/bash
17: set -e
18:
19: OPTS="-package-db=$GHC_PKG -package AstPlugin -fplugin=AstPlugin.Plugin"
20:
21: # NOTE: GHC plugin writes JSON to stderr
22: cabal --ghc-options="$OPTS" build
23: '';
24: };
25:
26: # Extract the JSON from runAstPlugin's stderr
27: getJson = mkBin {
28: name = "getJson";
29: paths = [ python ];
30: script = ''
31: #!/usr/bin/env python
32: from os import getenv
33: from subprocess import PIPE, Popen
34: from sys import stdout, stderr
35:
36: # Run the given command, capturing stdout and stderr
37: p = Popen([getenv('CMD')], stdout=PIPE, stderr=PIPE)
38: sout, serr = p.communicate()
39:
40: # We want any lines beginning with '{' to go to stdout, all else to stderr
41: isJson = lambda l: l.startswith('{')
42: notJson = lambda l: not isJson(l)
43:
44: stderr.write(sout + '\n')
45: stderr.write('\n'.join(filter(notJson, serr.split('\n'))))
46: stdout.write('\n'.join(filter(isJson, serr.split('\n'))))
47: '';
48: };
49:
50: testGetJson = runCommand "testGetJson"
51: {
52: __noChroot = true;
53: buildInputs = [ fail getJson ];
54: script1 = writeScript "script1" ''
55: #!${bash}/bin/bash
56: set -e
57: echo stdout1
58: echo stderr1 1>&2
59: echo '{stdout2}'
60: echo '{stderr2}' 1>&2
61: echo stdout3
62: echo stderr3 1>&2
63: '';
64: }
65: ''
66: set -e
67: set -o pipefail
68:
69: X=$(CMD="$script1" getJson) || fail "Couldn't run getJson"
70: [[ "x$X" = 'x{stderr2}' ]] || fail "Got unexpected output '$X'"
71:
72: echo pass > "$out"
73: '';
74:
75: runAstPlugin = withDeps [ testGetJson ] (mkBin {
76: name = "runAstPlugin";
77: paths = [ getJson haveVar jq runAstPluginRaw ];
78: vars = { CMD = "runAstPluginRaw"; };
79: script = ''
80: #!${bash}/bin/bash
81: set -e
82: set -o pipefail
83:
84: haveVar nameVersion
85:
86: getJson | jq -c --argjson nv "$nameVersion" '. + $nv' | jq -s '.'
87: '';
88: });
89:
90: main = mkBin {
91: name = "dumpToNix";
92: paths = [ bash cabal-install checkStderr fail haskellPkgNameVersion
93: runAstPlugin ];
94: script = ''
95: #!${bash}/bin/bash
96: set -e
97: set -o pipefail
98:
99: nameVersion=$(haskellPkgNameVersion "$1")
100: export nameVersion
101:
102: [[ -n "$pName" ]] || pName=$(echo "$nameVersion" | jq -r '.package')
103: export pName
104:
105: cp -r "$1" ./pkgDir
106: chmod +w -R ./pkgDir
107:
108: export HOME="$PWD"
109: cd ./pkgDir
110:
111: function packageMissing {
112: for P in "$pName" AstPlugin
113: do
114: "$1" list "$P" | grep '(no packages)' > /dev/null && return 0
115: done
116: return 1
117: }
118:
119: GHC_PKG=""
120: if packageMissing "ghc-pkg"
121: then
122: echo "Didn't find '$pName' in ghc-pkg DB, trying others" 1>&2
123:
124: # Not found in DB. Maybe broken nix-shell nesting, try elsewhere in PATH.
125: while read -r DIR
126: do
127: # Ignore entries which don't contain ghc-pkg
128: [[ -e "$DIR/ghc-pkg" ]] || continue
129:
130: # Ignore ghc-pkg entries which don't contain AstPlugin or $pName
131: packageMissing "$DIR/ghc-pkg" && continue
132:
133: # If we're here, we've found a ghc-pkg with AstPlugin and $pName
134: GHC_PKG=$("$DIR/ghc-pkg" list | head -n 1 | tr -d ':')
135:
136: echo "Found ghc-pkg DB at '$GHC_PKG'" 1>&2
137: break
138: done < <(echo "$PATH" | tr ':' '\n' | grep ghc)
139:
140: if [[ -z "$GHC_PKG" ]]
141: then
142: echo "Couldn't find ghc-pkg for AstPlugin & '$pName'" 1>&2
143: exit 1
144: fi
145: else
146: GHC_PKG=$(ghc-pkg list | head -n 1 | tr -d ':')
147: fi
148:
149: export GHC_PKG
150:
151: cabal configure --package-db="$GHC_PKG" 1>&2
152: runAstPlugin 2> >(checkStderr)
153: '';
154: };
155: };
156:
157: {
158: inherit main;
159:
160: dumpToNix = { pkgDir }:
161: with rec {
162: mkDeps = hsPkgs:
163: with {
164: pkgDeps = if hsPkgs ? "${pName}"
165: then [ hsPkgs."${pName}" ]
166: else [ (hsPkgs.callPackage pkgDir {}) ];
167: };
168: [ hsPkgs.AstPlugin hsPkgs.mlspec hsPkgs.mlspec-helper hsPkgs.QuickCheck
169: hsPkgs.quickspec ] ++ pkgDeps;
170:
171: nameVersion = runCommand "hs-name-version.json"
172: {
173: inherit pName;
174: buildInputs = [ hsNameVersion ];
175: }
176: ''
177: hsNameVersion "$pName" > "$out"
178: '';
179:
180: # Look for a .cabal file and extract the "name:" field
181: pName = (haskellPackages.callPackage pkgDir {}).name;
182:
183: hPkgs = (haskellPackages.ghcWithPackages mkDeps).override {
184: ignoreCollisions = true;
185: };
186: };
187: runCommand "dumpToNix"
188: {
189: inherit nameVersion pkgDir pName;
190: buildInputs = [ main hPkgs ];
191: }
192: ''
193: dumpToNix "$pkgDir" > "$out"
194: '';
195: }
Generated by git2html.