Skip to content
Merged
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
34 changes: 23 additions & 11 deletions backend/src/hatchling/builders/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@

TIME_TUPLE = tuple[int, int, int, int, int, int]

# The Linux kernel only reads the first BINPRM_BUF_SIZE (256) bytes of a shebang
# line, so anything longer cannot be a functional shebang and is left untouched.
MAX_SHEBANG_LENGTH = 256


class FileSelectionOptions(NamedTuple):
include: list[str]
Expand Down Expand Up @@ -162,6 +166,10 @@ def add_shared_file(self, shared_file: IncludedFile) -> tuple[str, str, str]:
shared_file.distribution_path = f"{self.shared_data_directory}/data/{shared_file.distribution_path}"
return self.add_file(shared_file)

def add_shared_script(self, shared_script: IncludedFile) -> tuple[str, str, str]:
shared_script.distribution_path = f"{self.shared_data_directory}/scripts/{shared_script.distribution_path}"
return self.add_file(shared_script)

def add_extra_metadata_file(self, extra_metadata_file: IncludedFile) -> tuple[str, str, str]:
extra_metadata_file.distribution_path = (
f"{self.metadata_directory}/extra_metadata/{extra_metadata_file.distribution_path}"
Expand Down Expand Up @@ -681,24 +689,28 @@ def add_shared_scripts(self, archive: WheelArchive, records: RecordFile, build_d

for shared_script in self.recurse_explicit_files(shared_scripts):
with open(shared_script.path, "rb") as f:
Comment thread
cjames23 marked this conversation as resolved.
content = BytesIO()
for line in f:
# Ignore leading blank lines
if not line.strip():
continue
prefix = f.read(2)

match = shebang.match(line)
if match is None:
content.write(line)
# A shebang is only honored on the first line starting at the very
# first byte, so anything else is kept as is.
if prefix != b"#!":
record = archive.add_shared_script(shared_script)
else:
line = prefix + f.readline(MAX_SHEBANG_LENGTH - len(prefix))
if len(line) == MAX_SHEBANG_LENGTH and not line.endswith(b"\n"):
# The line is too long to be a functional shebang.
record = archive.add_shared_script(shared_script)
elif (match := shebang.match(line)) is None:
record = archive.add_shared_script(shared_script)
else:
content = BytesIO()
content.write(b"#!python")
if remaining := match.group(1):
content.write(remaining)
content.write(f.read())

content.write(f.read())
break
record = archive.write_shared_script(shared_script, content.getvalue())

record = archive.write_shared_script(shared_script, content.getvalue())
records.write(record)

def add_sboms(self, archive: WheelArchive, records: RecordFile, build_data: dict[str, Any]) -> None:
Expand Down
10 changes: 0 additions & 10 deletions tests/backend/builders/test_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2088,7 +2088,6 @@ def test_default_shared_scripts(self, hatch, platform, helpers, temp_dir, config
(shared_data_path / "other_script.sh").write_text(
helpers.dedent(
"""

#!/bin/sh arg1 arg2
echo "Hello, World!"
"""
Expand All @@ -2097,7 +2096,6 @@ def test_default_shared_scripts(self, hatch, platform, helpers, temp_dir, config
(shared_data_path / "python_script.sh").write_text(
helpers.dedent(
"""

#!/usr/bin/env python3.11 arg1 arg2
print("Hello, World!")
"""
Expand All @@ -2106,7 +2104,6 @@ def test_default_shared_scripts(self, hatch, platform, helpers, temp_dir, config
(shared_data_path / "pythonw_script.sh").write_text(
helpers.dedent(
"""

#!/usr/bin/pythonw3.11 arg1 arg2
print("Hello, World!")
"""
Expand All @@ -2115,7 +2112,6 @@ def test_default_shared_scripts(self, hatch, platform, helpers, temp_dir, config
(shared_data_path / "pypy_script.sh").write_text(
helpers.dedent(
"""

#!/usr/bin/env pypy
print("Hello, World!")
"""
Expand All @@ -2124,7 +2120,6 @@ def test_default_shared_scripts(self, hatch, platform, helpers, temp_dir, config
(shared_data_path / "pypyw_script.sh").write_text(
helpers.dedent(
"""

#!pypyw3.11 arg1 arg2
print("Hello, World!")
"""
Expand Down Expand Up @@ -2199,7 +2194,6 @@ def test_default_shared_scripts_from_build_data(self, hatch, platform, helpers,
(shared_data_path / "other_script.sh").write_text(
helpers.dedent(
"""

#!/bin/sh arg1 arg2
echo "Hello, World!"
"""
Expand All @@ -2208,7 +2202,6 @@ def test_default_shared_scripts_from_build_data(self, hatch, platform, helpers,
(shared_data_path / "python_script.sh").write_text(
helpers.dedent(
"""

#!/usr/bin/env python3.11 arg1 arg2
print("Hello, World!")
"""
Expand All @@ -2217,7 +2210,6 @@ def test_default_shared_scripts_from_build_data(self, hatch, platform, helpers,
(shared_data_path / "pythonw_script.sh").write_text(
helpers.dedent(
"""

#!/usr/bin/pythonw3.11 arg1 arg2
print("Hello, World!")
"""
Expand All @@ -2226,7 +2218,6 @@ def test_default_shared_scripts_from_build_data(self, hatch, platform, helpers,
(shared_data_path / "pypy_script.sh").write_text(
helpers.dedent(
"""

#!/usr/bin/env pypy
print("Hello, World!")
"""
Expand All @@ -2235,7 +2226,6 @@ def test_default_shared_scripts_from_build_data(self, hatch, platform, helpers,
(shared_data_path / "pypyw_script.sh").write_text(
helpers.dedent(
"""

#!pypyw3.11 arg1 arg2
print("Hello, World!")
"""
Expand Down
Loading