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