Skip to content

Commit

Permalink
plumb sh-boot through to pex_binary (#19925)
Browse files Browse the repository at this point in the history
Addresses #19514
  • Loading branch information
cburroughs authored Jan 11, 2024
1 parent 100c4c7 commit b8c5fbf
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/python/pants/backend/python/goals/package_pex_binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
PexPlatformsField,
PexResolveLocalPlatformsField,
PexScriptField,
PexShBootField,
PexShebangField,
PexStripEnvField,
PexVenvHermeticScripts,
Expand Down Expand Up @@ -64,6 +65,7 @@ class PexBinaryFieldSet(PackageFieldSet, RunFieldSet):
emit_warnings: PexEmitWarningsField
ignore_errors: PexIgnoreErrorsField
inherit_path: PexInheritPathField
sh_boot: PexShBootField
shebang: PexShebangField
strip_env: PexStripEnvField
platforms: PexPlatformsField
Expand Down Expand Up @@ -92,6 +94,8 @@ def generate_additional_args(self, pex_binary_defaults: PexBinaryDefaults) -> Tu
args.append("--ignore-errors")
if self.inherit_path.value is not None:
args.append(f"--inherit-path={self.inherit_path.value}")
if self.sh_boot.value is True:
args.append("--sh-boot")
if self.shebang.value is not None:
args.append(f"--python-shebang={self.shebang.value}")
if self.strip_env.value is False:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,3 +418,37 @@ def execute_pex(address: Address, **extra_env) -> Results:
)
assert "bob" == non_hermetic_results.pythonpath
assert bob_sys_path_entry in non_hermetic_results.sys_path


def test_sh_boot_plumb(rule_runner: PythonRuleRunner) -> None:
rule_runner.write_files(
{
"src/py/project/app.py": dedent(
"""\
print("hello")
"""
),
"src/py/project/BUILD": dedent(
"""\
python_sources(name="lib")
pex_binary(
entry_point="app.py",
sh_boot=True
)
"""
),
}
)
tgt = rule_runner.get_target(Address("src/py/project"))
field_set = PexBinaryFieldSet.create(tgt)
result = rule_runner.request(BuiltPackage, [field_set])
assert len(result.artifacts) == 1
expected_pex_relpath = "src.py.project/project.pex"
assert expected_pex_relpath == result.artifacts[0].relpath

rule_runner.write_digest(result.digest)

executable = os.path.join(rule_runner.build_root, expected_pex_relpath)
with open(executable, "rb") as f:
shebang = f.readline().decode()
assert "#!/bin/sh" in shebang
24 changes: 24 additions & 0 deletions src/python/pants/backend/python/target_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,29 @@ class PexIgnoreErrorsField(BoolField):
help = "Should PEX ignore errors when it cannot resolve dependencies?"


class PexShBootField(BoolField):
alias = "sh_boot"
default = False
help = help_text(
"""
Should PEX create a modified ZIPAPP that uses `/bin/sh` to boot?
If you know the machines that the PEX will be distributed to have
POSIX compliant `/bin/sh` (almost all do, see:
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html);
then this is probably the way you want your PEX to boot. Instead of
launching via a Python shebang, the PEX will launch via a `#!/bin/sh`
shebang that executes a small script embedded in the head of the PEX
ZIPAPP that performs initial interpreter selection and re-execution of
the underlying PEX in a way that is often more robust than a Python
shebang and always faster on 2nd and subsequent runs since the sh
script has a constant overhead of O(1ms) whereas the Python overhead
to perform the same interpreter selection and re-execution is
O(100ms).
"""
)


class PexShebangField(StringField):
alias = "shebang"
help = help_text(
Expand Down Expand Up @@ -680,6 +703,7 @@ class PexVenvHermeticScripts(BoolField):
PexInheritPathField,
PexStripEnvField,
PexIgnoreErrorsField,
PexShBootField,
PexShebangField,
PexEmitWarningsField,
PexLayoutField,
Expand Down

0 comments on commit b8c5fbf

Please sign in to comment.