nix-helpers: c40be93aba7b1d7c2a1a48e7792486f0894b02d5
1: {
2: bash,
3: coreutils,
4: lib,
5: makeSetupHook,
6: nixListToBashArray,
7: repo1609,
8: runCommand,
9: stdenv,
10: patchShebang,
11: writeScript,
12: }:
13:
14: with builtins;
15: with lib;
16: with rec {
17: # Load makeWrapper from 16.09 so that it has known behaviour w.r.t. quoting,
18: # etc.
19: makeWrapper = makeSetupHook {
20: name = "make-wrapper";
21: } "${repo1609}/pkgs/build-support/setup-hooks/make-wrapper.sh";
22: };
23: {
24: file ? null,
25: name,
26: patchShebangs ? true,
27: paths ? [ ],
28: script ? null,
29: vars ? { },
30: }:
31: assert
32: file != null
33: || script != null
34: || abort "wrap needs 'file' or 'script' argument";
35: with rec {
36: # If we're given a string, write it to a file. We put that file in a
37: # directory since Python scripts can take a while to start if they live
38: # directly in the Nix store (presumably from scanning for modules).
39: inDir =
40: runCommand "${name}-unwrapped"
41: {
42: f = writeScript "${name}-raw" (
43: if patchShebangs then patchShebang { string = script; } else script
44: );
45: }
46: ''
47: mkdir "$out"
48: cp "$f" "$out/"${escapeShellArg name}
49: '';
50:
51: newFile = "${inDir}/${name}";
52:
53: f =
54: if file == null then
55: newFile
56: else if patchShebangs then
57: patchShebang { inherit file name; }
58: else
59: file;
60:
61: # Whether any extra env vars or paths are actually needed
62: needEnv = if paths == [ ] && vars == { } then "false" else "true";
63:
64: # Store each path in a variable pathVarN
65: pathData = nixListToBashArray {
66: name = "pathVars";
67: args = paths;
68: };
69:
70: # Store each name in a variable varNamesN and the corresponding value in a
71: # variable varValsN. Their order is arbitrary, but must match up.
72: varNames = attrNames vars;
73: varNameData = nixListToBashArray {
74: name = "varNames";
75: args = varNames;
76: };
77: varValData = nixListToBashArray {
78: name = "varVals";
79: args = map (n: getAttr n vars) varNames;
80: };
81: };
82: runCommand name
83: (
84: pathData.env
85: // varNameData.env
86: // varValData.env
87: // {
88: inherit f needEnv;
89: buildInputs = [ makeWrapper ];
90: }
91: )
92: ''
93: # Shortcut if no extra env, etc. is needed
94: $needEnv || {
95: ln -s "$f" "$out"
96: exit
97: }
98:
99: ARGS=()
100:
101: ${pathData.code}
102: for P in "''${pathVars[@]}"
103: do
104: # Add $P/bin to $PATH
105: ARGS=("''${ARGS[@]}" "--prefix" "PATH" ":" "$P/bin")
106:
107: # We want 'paths' to act like 'buildInputs', so we also add any paths
108: # from 'propagated build inputs'
109: REMAINING=("$P/nix-support/propagated-native-build-inputs" "$P/nix-support/propagated-build-inputs" )
110: while [[ "''${#REMAINING[@]}" -gt 0 ]]
111: do
112: PROPS="''${REMAINING[0]}"
113: REMAINING=("''${REMAINING[@]:1:''${#REMAINING[@]}}" )
114: if [[ -e "$PROPS" ]]
115: then
116: while read -r PROP
117: do
118: ARGS=("''${ARGS[@]}" "--prefix" "PATH" ":" "$PROP/bin")
119: MORE="$PROP/nix-support/propagated-native-build-inputs"
120: if [[ -e "$MORE" ]]
121: then
122: REMAINING=("''${REMAINING[@]}" "$MORE")
123: fi
124: MORE="$PROP/nix-support/propagated-build-inputs"
125: if [[ -e "$MORE" ]]
126: then
127: REMAINING=("''${REMAINING[@]}" "$MORE")
128: fi
129: done < <(tr ' ' '\n' < "$PROPS")
130: fi
131: done
132: done
133:
134: ${varNameData.code}
135: ${varValData.code}
136:
137: # Loop through the indices of each name/value; this is slightly awkward
138: # since 'seq' likes to count from 1, but bash arrays start at 0.
139: for NPLUSONE in $(seq 1 "''${#varNames[@]}")
140: do
141: N=$(( NPLUSONE - 1 ))
142:
143: # makeWrapper doesn't escape properly, so spaces, quote marks, dollar
144: # signs, etc. will cause errors. Given a value FOO, makeWrapper will
145: # write out a script containing "FOO" (i.e. it wraps the text in
146: # double quotes). Double quotes aren't safe in Bash, since they splice
147: # in variables for dollar signs, etc. Plus, makeWrapper isn't actually
148: # doing any escaping: if our text contains a ", then it will appear
149: # verbatim and break the surrounding quotes.
150: # To work around this we do the following:
151: # - Escape all single quotes in our value using sed; this is made
152: # more awkward since we're using single-quoted Nix strings...
153: # - Surround this escaped value in single quotes, hence making a
154: # fully escaped text value which won't mess up any content
155: # - Surround this single-quoted-and-escaped value in double quotes.
156: # These "cancel out" the double quotes added by makeWrapper, i.e.
157: # instead of FOO -> "FOO", we do "FOO" -> ""FOO"", and hence the
158: # value FOO (in this case, our single-quoted-escaped-value) appears
159: # OUTSIDE the double quotes, and is hence free to use single quotes
160:
161: # Pro tip to any readers: try to avoid unintended string
162: # interpretation wherever you can. Instead of "quoting variables where
163: # necessary", you should always quote all variables; instead of
164: # embedding raw strings into generated scripts and sprinkling around
165: # some quote marks, you should always escape them properly (in Bash,
166: # this is done by escaping single quotes wrapping in single quotes);
167: # never treat double quotes as an escaping mechanism.
168:
169:
170: # These vars make escaping slightly less crazy (Bash single-quote
171: # escaping requires adjacent single-quotes, but we're in a Nix string
172: # that's enclosed in double single-quotes... sigh)
173: BS='\'
174: T="'"
175:
176: ESC=$(echo "''${varVals[$N]}" | sed -e "s/$T/$T$BS$BS$T$T/g")
177:
178: ARGS=("''${ARGS[@]}" "--set" "''${varNames[$N]}" "\"'$ESC'\"")
179: done
180:
181: makeWrapper "$f" "$out" "''${ARGS[@]}"
182: ''
Generated by git2html.