nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 lib,
3 stdenv,
4 pkgs,
5}:
6
7# since the tests are using a early stdenv, the stdenv will have dontPatchShebangs=1, so it has to be unset
8# https://github.com/NixOS/nixpkgs/blob/768a982bfc9d29a6bd3beb963ed4b054451ce3d0/pkgs/stdenv/linux/default.nix#L148-L153
9
10# strictDeps has to be disabled because the shell isn't in buildInputs
11
12let
13 earlyBash =
14 stdenv.__bootPackages.stdenv.__bootPackages.bashNonInteractive or pkgs.bashNonInteractive;
15 earlyCoreutils = stdenv.__bootPackages.stdenv.__bootPackages.coreutils or pkgs.coreutils;
16 earlyDiffutils = stdenv.__bootPackages.stdenv.__bootPackages.diffutils or pkgs.diffutils;
17 earlyFindutils = stdenv.__bootPackages.stdenv.__bootPackages.findutils or pkgs.findutils;
18 earlySed = stdenv.__bootPackages.stdenv.__bootPackages.gnused or pkgs.gnused;
19
20 tests = {
21 bad-shebang = stdenv.mkDerivation {
22 name = "bad-shebang";
23 strictDeps = false;
24 dontUnpack = true;
25 installPhase = ''
26 mkdir -p $out/bin
27 echo "#!/bin/bash" > $out/bin/test
28 echo "echo -n hello" >> $out/bin/test
29 chmod +x $out/bin/test
30 dontPatchShebangs=
31 '';
32 passthru = {
33 assertion = "grep '^#!${stdenv.shell}' $out/bin/test > /dev/null";
34 };
35 };
36
37 ignores-nix-store = stdenv.mkDerivation {
38 name = "ignores-nix-store";
39 strictDeps = false;
40 dontUnpack = true;
41 installPhase = ''
42 mkdir -p $out/bin
43 echo "#!$NIX_STORE/path/to/bash" > $out/bin/test
44 echo "echo -n hello" >> $out/bin/test
45 chmod +x $out/bin/test
46 dontPatchShebangs=
47 '';
48 passthru = {
49 assertion = "grep \"^#!$NIX_STORE/path/to/bash\" $out/bin/test > /dev/null";
50 };
51 };
52
53 updates-nix-store = stdenv.mkDerivation {
54 name = "updates-nix-store";
55 strictDeps = false;
56 dontUnpack = true;
57 installPhase = ''
58 mkdir -p $out/bin
59 echo "#!$NIX_STORE/path/to/bash" > $out/bin/test
60 echo "echo -n hello" >> $out/bin/test
61 chmod +x $out/bin/test
62 patchShebangs --update $out/bin/test
63 dontPatchShebangs=1
64 '';
65 passthru = {
66 assertion = "grep '^#!${stdenv.shell}' $out/bin/test > /dev/null";
67 };
68 };
69
70 split-string = stdenv.mkDerivation {
71 name = "split-string";
72 strictDeps = false;
73 dontUnpack = true;
74 installPhase = ''
75 mkdir -p $out/bin
76 echo "#!/usr/bin/env -S bash --posix" > $out/bin/test
77 echo "echo -n hello" >> $out/bin/test
78 chmod +x $out/bin/test
79 dontPatchShebangs=
80 '';
81 passthru = {
82 assertion = "grep -v '^#!${pkgs.coreutils}/bin/env -S ${stdenv.shell} --posix' $out/bin/test > /dev/null";
83 };
84 };
85
86 without-trailing-newline = stdenv.mkDerivation {
87 name = "without-trailing-newline";
88 strictDeps = false;
89 dontUnpack = true;
90 installPhase = ''
91 mkdir -p $out/bin
92 printf "#!/bin/bash" > $out/bin/test
93 chmod +x $out/bin/test
94 dontPatchShebangs=
95 '';
96 passthru = {
97 assertion = "grep '^#!${stdenv.shell}' $out/bin/test > /dev/null";
98 };
99 };
100
101 dont-patch-builtins = stdenv.mkDerivation {
102 name = "dont-patch-builtins";
103 strictDeps = false;
104 dontUnpack = true;
105 installPhase = ''
106 mkdir -p $out/bin
107 echo "#!/usr/bin/builtin" > $out/bin/test
108 chmod +x $out/bin/test
109 dontPatchShebangs=
110 '';
111 passthru = {
112 assertion = "grep '^#!/usr/bin/builtin' $out/bin/test > /dev/null";
113 };
114 };
115
116 read-only-script =
117 (derivation {
118 name = "read-only-script";
119 system = stdenv.buildPlatform.system;
120 builder = lib.getExe earlyBash;
121 initialPath = [
122 earlyBash
123 earlyCoreutils
124 earlyDiffutils
125 earlyFindutils
126 earlySed
127 ];
128 strictDeps = false;
129 args = [
130 "-c"
131 ''
132 set -euo pipefail
133 . ${../../stdenv/generic/setup.sh}
134 . ${../../build-support/setup-hooks/patch-shebangs.sh}
135 mkdir -p $out/bin
136 echo "#!/bin/bash" > $out/bin/test
137 echo "echo -n hello" >> $out/bin/test
138 chmod 555 $out/bin/test
139 patchShebangs $out/bin/test
140 ''
141 ];
142 assertion = "grep '^#!${lib.getExe earlyBash}' $out/bin/test > /dev/null";
143 })
144 // {
145 meta = { };
146 };
147
148 preserves-read-only =
149 (derivation {
150 name = "preserves-read-only";
151 system = stdenv.buildPlatform.system;
152 builder = lib.getExe earlyBash;
153 initialPath = [
154 earlyBash
155 earlyCoreutils
156 earlyFindutils
157 earlySed
158 ];
159 strictDeps = false;
160 args = [
161 "-c"
162 ''
163 set -euo pipefail
164 . ${../../stdenv/generic/setup.sh}
165 . ${../../build-support/setup-hooks/patch-shebangs.sh}
166 mkdir -p $out/bin
167 echo "#!/bin/bash" > $out/bin/test
168 echo "echo -n hello" >> $out/bin/test
169 chmod 555 $out/bin/test
170 original_perms=$(stat -c %a $out/bin/test)
171 patchShebangs $out/bin/test
172 new_perms=$(stat -c %a $out/bin/test)
173 if ! [ "$original_perms" = "$new_perms" ]; then
174 echo "Permissions changed from $original_perms to $new_perms"
175 exit 1
176 fi
177 ''
178 ];
179 assertion = "grep '^#!${lib.getExe earlyBash}' $out/bin/test > /dev/null";
180 })
181 // {
182 meta = { };
183 };
184
185 # Preserve times, see: https://github.com/NixOS/nixpkgs/pull/33281
186 preserves-timestamp =
187 (derivation {
188 name = "preserves-timestamp";
189 system = stdenv.buildPlatform.system;
190 builder = lib.getExe earlyBash;
191 initialPath = [
192 earlyBash
193 earlyCoreutils
194 earlyDiffutils
195 earlyFindutils
196 earlySed
197 ];
198 strictDeps = false;
199 args = [
200 "-c"
201 ''
202 set -euo pipefail
203 . ${../../stdenv/generic/setup.sh}
204 . ${../../build-support/setup-hooks/patch-shebangs.sh}
205 mkdir -p $out/bin
206 echo "#!/bin/bash" > $out/bin/test
207 echo "echo -n hello" >> $out/bin/test
208 chmod +x $out/bin/test
209 # Set a specific timestamp (2000-01-01 00:00:00)
210 touch -t 200001010000 $out/bin/test
211 original_timestamp=$(stat -c %Y $out/bin/test)
212 patchShebangs $out/bin/test
213 new_timestamp=$(stat -c %Y $out/bin/test)
214 if ! [ "$original_timestamp" = "$new_timestamp" ]; then
215 echo "Timestamp changed from $original_timestamp to $new_timestamp"
216 exit 1
217 fi
218 ''
219 ];
220 assertion = "grep '^#!${lib.getExe earlyBash}' $out/bin/test > /dev/null";
221 })
222 // {
223 meta = { };
224 };
225
226 preserves-binary-data =
227 (derivation {
228 name = "preserves-binary-data";
229 system = stdenv.buildPlatform.system;
230 builder = lib.getExe earlyBash;
231 initialPath = [
232 earlyBash
233 earlyCoreutils
234 earlyDiffutils
235 earlyFindutils
236 earlySed
237 ];
238 strictDeps = false;
239 args = [
240 "-c"
241 ''
242 set -euo pipefail
243 . ${../../stdenv/generic/setup.sh}
244 . ${../../build-support/setup-hooks/patch-shebangs.sh}
245 mkdir -p $out/bin
246 # Create a script with binary data after the shebang
247 echo "#!/bin/bash" > $out/bin/test
248 echo "echo 'script start'" >> $out/bin/test
249 # Add some binary data (null bytes and other non-printable chars)
250 printf '\x00\x01\x02\xff\xfe' >> $out/bin/test
251 echo >> $out/bin/test
252 echo "echo 'script end'" >> $out/bin/test
253 chmod +x $out/bin/test
254 patchShebangs $out/bin/test
255 # Verify binary data is still present by checking file size and content
256 if ! printf '\x00\x01\x02\xff\xfe' | cmp -s - <(sed -n '3p' $out/bin/test | tr -d '\n'); then
257 echo "Binary data corrupted during patching"
258 exit 1
259 fi
260 ''
261 ];
262 assertion = "grep '^#!${lib.getExe earlyBash}' $out/bin/test > /dev/null";
263 })
264 // {
265 meta = { };
266 };
267 };
268in
269stdenv.mkDerivation {
270 name = "test-patch-shebangs";
271 passthru = {
272 inherit (tests)
273 bad-shebang
274 ignores-nix-store
275 updates-nix-store
276 split-string
277 without-trailing-newline
278 dont-patch-builtins
279 read-only-script
280 preserves-read-only
281 preserves-timestamp
282 preserves-binary-data
283 ;
284 };
285 buildCommand = ''
286 validate() {
287 local name=$1
288 local testout=$2
289 local assertion=$3
290
291 echo -n "... $name: " >&2
292
293 local rc=0
294 (out=$testout eval "$assertion") || rc=1
295
296 if [ "$rc" -eq 0 ]; then
297 echo "yes" >&2
298 else
299 echo "no" >&2
300 fi
301
302 return "$rc"
303 }
304
305 echo "checking whether patchShebangs works properly... ">&2
306
307 fail=
308 ${lib.concatStringsSep "\n" (
309 lib.mapAttrsToList (_: test: ''
310 validate "${test.name}" "${test}" ${lib.escapeShellArg test.assertion} || fail=1
311 '') tests
312 )}
313
314 if [ "$fail" ]; then
315 echo "failed"
316 exit 1
317 else
318 echo "succeeded"
319 touch $out
320 fi
321 '';
322}