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() + )