From d6aad2edfab7ecad2f25bbf2be5728288481ff8e Mon Sep 17 00:00:00 2001 From: John Sirois Date: Tue, 30 Jul 2024 23:10:32 -0700 Subject: [PATCH] Handle all output file names when building scies. (#2484) Previously, invoking `pex pex -c pex --venv --scie eager -o pex` to build the Pex PEX scie would error deep inside the science scie build process due to the name collision. Since the user has no control over the lift manifest, this was not able to be corrected. --- CHANGES.md | 9 +++++ pex/scie/science.py | 45 +++++++++++++++++++++---- pex/version.py | 2 +- tests/integration/scie/test_pex_scie.py | 30 +++++++++++++++++ 4 files changed, 78 insertions(+), 8 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 34a27e796..8ba91aec6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,14 @@ # Release Notes +## 2.13.1 + +This release fixes the `--scie` option to support building a Pex PEX +scie with something like `pex pex -c pex --venv --scie eager -o pex`. +Previously, due to the output filename of `pex` colliding with fixed +internal scie lift manifest file names, this would fail. + +* Handle all output file names when building scies. (#2484) + ## 2.13.0 This release improves error message detail when there are failures in diff --git a/pex/scie/science.py b/pex/scie/science.py index 509358941..054dda891 100644 --- a/pex/scie/science.py +++ b/pex/scie/science.py @@ -70,11 +70,40 @@ def _science_binary_url(suffix=""): SCIE_JUMP_VERSION = "1.1.1" +@attr.s(frozen=True) +class Filename(object): + name = attr.ib() # type: str + + @property + def placeholder(self): + # type: () -> str + return "{{{name}}}".format(name=self.name) + + +@attr.s(frozen=True) +class Filenames(object): + @classmethod + def avoid_collisions_with(cls, scie_name): + # type: (str) -> Filenames + return cls( + pex=Filename("_pex" if scie_name == "pex" else "pex"), + configure_binding=Filename( + "_configure-binding.py" + if scie_name == "configure-binding.py" + else "configure-binding.py" + ), + ) + + pex = attr.ib() # type: Filename + configure_binding = attr.ib() # type: Filename + + def create_manifests( configuration, # type: ScieConfiguration name, # type: str pex_info, # type: PexInfo layout, # type: Layout.Value + filenames, # type: Filenames ): # type: (...) -> Iterator[Manifest] @@ -84,7 +113,7 @@ def create_manifests( # interpreter executing the venv PEX. installed_pex_dir = "" elif layout is Layout.LOOSE: - installed_pex_dir = "{pex}" + installed_pex_dir = filenames.pex.placeholder else: production_assert(pex_info.pex_hash is not None) pex_hash = cast(str, pex_info.pex_hash) @@ -102,7 +131,7 @@ def create_manifests( "argv1": "{scie.env.PEX_BOOTSTRAP_URLS={scie.lift}}", }, "scie_jump": {"version": SCIE_JUMP_VERSION}, - "files": [{"name": "configure-binding.py"}, {"name": "pex"}], + "files": [{"name": filenames.configure_binding.name}, {"name": filenames.pex.name}], "commands": [ { "env": {"default": env_default}, @@ -126,7 +155,7 @@ def create_manifests( }, "name": "configure", "exe": "#{cpython:python}", - "args": ["{pex}", "{configure-binding.py}"], + "args": [filenames.pex.placeholder, filenames.configure_binding.placeholder], } ], } # type: Dict[str, Any] @@ -290,9 +319,10 @@ def build( pex_info = PexInfo.from_pex(pex_file) layout = Layout.identify(pex_file) use_platform_suffix = len(configuration.targets) > 1 + filenames = Filenames.avoid_collisions_with(name) errors = OrderedDict() # type: OrderedDict[Manifest, str] - for manifest in create_manifests(configuration, name, pex_info, layout): + for manifest in create_manifests(configuration, name, pex_info, layout, filenames): args = [science, "--cache-dir", _science_dir(env, "cache")] if env.PEX_VERBOSE: args.append("-{verbosity}".format(verbosity="v" * env.PEX_VERBOSE)) @@ -301,12 +331,13 @@ def build( [ "lift", "--file", - "pex={pex_file}".format(pex_file=pex_file), + "{name}={pex_file}".format(name=filenames.pex.name, pex_file=pex_file), "--file", - "configure-binding.py={configure_binding}".format( + "{name}={configure_binding}".format( + name=filenames.configure_binding.name, configure_binding=os.path.join( os.path.dirname(__file__), "configure-binding.py" - ) + ), ), "build", "--dest-dir", diff --git a/pex/version.py b/pex/version.py index e149d3235..597ed68a3 100644 --- a/pex/version.py +++ b/pex/version.py @@ -1,4 +1,4 @@ # Copyright 2015 Pex project contributors. # Licensed under the Apache License, Version 2.0 (see LICENSE). -__version__ = "2.13.0" +__version__ = "2.13.1" diff --git a/tests/integration/scie/test_pex_scie.py b/tests/integration/scie/test_pex_scie.py index 34b95ec23..0c9641fec 100644 --- a/tests/integration/scie/test_pex_scie.py +++ b/tests/integration/scie/test_pex_scie.py @@ -19,6 +19,7 @@ from pex.scie import SciePlatform, ScieStyle from pex.targets import LocalInterpreter from pex.typing import TYPE_CHECKING +from pex.version import __version__ from testing import IS_PYPY, PY_VER, make_env, run_pex_command if TYPE_CHECKING: @@ -369,3 +370,32 @@ def make_20240415_3_10_14_url(platform): stderr.decode("utf-8"), flags=re.DOTALL | re.MULTILINE, ), stderr.decode("utf-8") + + +@skip_if_pypy +def test_pex_pex_scie( + tmpdir, # type: Any + pex_project_dir, # type: Any +): + # type: (...) -> None + + pex = os.path.join(str(tmpdir), "pex") + run_pex_command( + args=[ + pex_project_dir, + "-c", + "pex", + "--scie", + "lazy", + "--scie-python-version", + "3.12", + "-o", + pex, + ] + ).assert_success() + assert ( + __version__ + == subprocess.check_output(args=[pex, "-V"], env=make_env(PATH=None)) + .decode("utf-8") + .strip() + )