From 60a2dc53e7b4407c3c0c14093fd8542879997ca8 Mon Sep 17 00:00:00 2001 From: jsurany <49820772+jsurany@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:50:29 -0400 Subject: [PATCH] fix issues in discovering ruff in pip build environments (#13881) ## Summary Changes in this PR https://github.com/astral-sh/ruff/pull/13591 did not allow correct discovery in pip build environments. ```python # both of these variables are tuple[str, str] (length is 2) first, second = os.path.split(paths[0]), os.path.split(paths[1]) # so these length checks are guaranteed to fail even for build environment folders if ( len(first) >= 3 and len(second) >= 3 ... ) ``` ~~Here we instead use `pathlib`, and we check all `pip-build-env-` paths for the folder that is expected to contain the `ruff` executable.~~ Here we update the logic to more properly split out the path components that we use for `pip-build-env-` inspection. ## Test Plan I've checked this manually against a workflow that was failing, I'm not sure what to do for real tests. The same issues apply as with the previous PR. --------- Co-authored-by: Jonathan Surany Co-authored-by: Charlie Marsh --- python/ruff/__main__.py | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/python/ruff/__main__.py b/python/ruff/__main__.py index d536867ad2..e73bba334e 100644 --- a/python/ruff/__main__.py +++ b/python/ruff/__main__.py @@ -35,22 +35,40 @@ def find_ruff_bin() -> str: # Search for pip-specific build environments. # + # Expect to find ruff in /pip-build-env-/overlay/bin/ruff + # Expect to find a "normal" folder at /pip-build-env-/normal + # # See: https://github.com/pypa/pip/blob/102d8187a1f5a4cd5de7a549fd8a9af34e89a54f/src/pip/_internal/build_env.py#L87 paths = os.environ.get("PATH", "").split(os.pathsep) if len(paths) >= 2: - first, second = os.path.split(paths[0]), os.path.split(paths[1]) - # Search for both an `overlay` and `normal` folder within a `pip-build-env-{random}` folder. (The final segment - # of the path is the `bin` directory.) + + def get_last_three_path_parts(path: str) -> list[str]: + """Return a list of up to the last three parts of a path.""" + parts = [] + + while len(parts) < 3: + head, tail = os.path.split(path) + if tail or head != path: + parts.append(tail) + path = head + else: + parts.append(path) + break + + return parts + + maybe_overlay = get_last_three_path_parts(paths[0]) + maybe_normal = get_last_three_path_parts(paths[1]) if ( - len(first) >= 3 - and len(second) >= 3 - and first[-3].startswith("pip-build-env-") - and first[-2] == "overlay" - and second[-3].startswith("pip-build-env-") - and second[-2] == "normal" + len(maybe_normal) >= 3 + and maybe_normal[-1].startswith("pip-build-env-") + and maybe_normal[-2] == "normal" + and len(maybe_overlay) >= 3 + and maybe_overlay[-1].startswith("pip-build-env-") + and maybe_overlay[-2] == "overlay" ): # The overlay must contain the ruff binary. - candidate = os.path.join(first, ruff_exe) + candidate = os.path.join(paths[0], ruff_exe) if os.path.isfile(candidate): return candidate