Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 20 additions & 28 deletions pkgs/build-support/setup-hooks/patch-shebangs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,31 +68,6 @@ patchShebangs() {
return 0
fi

# like sponge from moreutils but in pure bash
_sponge() {
local content
local target
local restoreReadOnly
content=""
target="$1"

# Make file writable if it is read-only
if [[ ! -w "$target" ]]; then
chmod +w "$target"
restoreReadOnly=true
fi

while IFS= read -r line || [[ -n "$line" ]]; do
content+="$line"$'\n'
done
printf '%s' "$content" > "$target"

# Restore read-only if it was read-only before
if [[ -n "${restoreReadOnly:-}" ]]; then
chmod -w "$target"
fi
}

local f
while IFS= read -r -d $'\0' f; do
isScript "$f" || continue
Expand Down Expand Up @@ -151,14 +126,31 @@ patchShebangs() {

# Preserve times, see: https://github.com/NixOS/nixpkgs/pull/33281
timestamp=$(stat --printf "%y" "$f")
sed -e "1 s|.*|#\!$escapedInterpreterLine|" "$f" | _sponge "$f"

# Manually create temporary file instead of using sed -i
# (sed -i on $out/x creates tmpfile /nix/store/x which fails on macos + sandbox)
tmpFile=$(mktemp -t patchShebangs.XXXXXXXXXX)
sed -e "1 s|.*|#\!$escapedInterpreterLine|" "$f" > "$tmpFile"

# Make original file writable if it is read-only
local restoreReadOnly
if [[ ! -w "$f" ]]; then
chmod +w "$f"
restoreReadOnly=true
fi

# Replace the original file's content with the patched content
# (preserving permissions)
cat "$tmpFile" > "$f"
rm "$tmpFile"
if [[ -n "${restoreReadOnly:-}" ]]; then
chmod -w "$f"
fi

touch --date "$timestamp" "$f"
fi
fi
done < <(find "$@" -type f -perm -0100 -print0)

unset -f _sponge
}

patchShebangsAuto () {
Expand Down
39 changes: 39 additions & 0 deletions pkgs/test/stdenv/patch-shebangs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,44 @@ let
// {
meta = { };
};

preserves-binary-data =
(derivation {
name = "preserves-binary-data";
system = stdenv.buildPlatform.system;
builder = "${stdenv.__bootPackages.stdenv.__bootPackages.bashNonInteractive}/bin/bash";
initialPath = [
stdenv.__bootPackages.stdenv.__bootPackages.coreutils
];
strictDeps = false;
args = [
"-c"
''
set -euo pipefail
. ${../../stdenv/generic/setup.sh}
. ${../../build-support/setup-hooks/patch-shebangs.sh}
mkdir -p $out/bin
# Create a script with binary data after the shebang
echo "#!/bin/bash" > $out/bin/test
echo "echo 'script start'" >> $out/bin/test
# Add some binary data (null bytes and other non-printable chars)
printf '\x00\x01\x02\xff\xfe' >> $out/bin/test
echo >> $out/bin/test
echo "echo 'script end'" >> $out/bin/test
chmod +x $out/bin/test
patchShebangs $out/bin/test
# Verify binary data is still present by checking file size and content
if ! printf '\x00\x01\x02\xff\xfe' | cmp -s - <(sed -n '3p' $out/bin/test | tr -d '\n'); then
echo "Binary data corrupted during patching"
exit 1
fi
''
];
assertion = "grep '^#!${stdenv.shell}' $out/bin/test > /dev/null";
})
// {
meta = { };
};
};
in
stdenv.mkDerivation {
Expand All @@ -219,6 +257,7 @@ stdenv.mkDerivation {
read-only-script
preserves-read-only
preserves-timestamp
preserves-binary-data
;
};
buildCommand = ''
Expand Down