diff --git a/tests/tools/test_local_env_cwd_recovery.py b/tests/tools/test_local_env_cwd_recovery.py index 59aa8f106730..07ec8e8615ce 100644 --- a/tests/tools/test_local_env_cwd_recovery.py +++ b/tests/tools/test_local_env_cwd_recovery.py @@ -160,13 +160,14 @@ class TestUpdateCwdRejectsMissingPaths: with patch.object(LocalEnvironment, "init_session", autospec=True, return_value=None): env = LocalEnvironment(cwd=str(original), timeout=10) - # Simulate the stale-marker case: the prior command's ``pwd -P`` left - # a path in the cwd file, but that path has since been deleted. + # Simulate the stale-marker case: the prior command emitted a cwd + # marker for a directory that has since been deleted. deleted = tmp_path / "wedge-repro" - with open(env._cwd_file, "w") as f: - f.write(str(deleted)) + marker = env._cwd_marker - env._update_cwd({"output": "", "returncode": 0}) + env._update_cwd( + {"output": f"x\n{marker}{deleted}{marker}\n", "returncode": 0} + ) assert env.cwd == str(original) @@ -178,10 +179,10 @@ class TestUpdateCwdRejectsMissingPaths: with patch.object(LocalEnvironment, "init_session", autospec=True, return_value=None): env = LocalEnvironment(cwd=str(original), timeout=10) + marker = env._cwd_marker - with open(env._cwd_file, "w") as f: - f.write(str(new_dir)) - - env._update_cwd({"output": "", "returncode": 0}) + env._update_cwd( + {"output": f"x\n{marker}{new_dir}{marker}\n", "returncode": 0} + ) assert env.cwd == str(new_dir) diff --git a/tests/tools/test_local_env_windows_msys.py b/tests/tools/test_local_env_windows_msys.py index f5eba3f252a8..6f77af1fac89 100644 --- a/tests/tools/test_local_env_windows_msys.py +++ b/tests/tools/test_local_env_windows_msys.py @@ -180,15 +180,15 @@ class TestResolveSafeCwdWindows: # --------------------------------------------------------------------------- -# End-to-end: _update_cwd via marker file (Windows simulation) +# End-to-end: _update_cwd via stdout marker (Windows simulation) # --------------------------------------------------------------------------- class TestUpdateCwdWindowsMsys: - def test_marker_file_msys_path_stored_in_native_form( + def test_marker_output_msys_path_stored_in_native_form( self, monkeypatch, tmp_path, ): - """When Git Bash writes ``/c/Users/x`` to the cwd marker file on - Windows, ``_update_cwd`` must translate to native form before + """When Git Bash emits ``/c/Users/x`` in the cwd marker on Windows, + ``_update_cwd`` must translate to native form before validating and storing — otherwise ``os.path.isdir`` rejects a perfectly real directory.""" original = tmp_path / "starting" @@ -205,18 +205,21 @@ class TestUpdateCwdWindowsMsys: # Pretend Git Bash wrote an MSYS path that maps to tmp_path/"next" new_dir = tmp_path / "next" new_dir.mkdir() + marker = env._cwd_marker - with open(env._cwd_file, "w") as f: - f.write("/c/whatever/from/bash") - - # Translate the synthetic MSYS string to the real native dir. + # Translate the synthetic MSYS marker path to the real native dir. def fake_translate(p): if p == "/c/whatever/from/bash": return str(new_dir) return p with patch.object(local_mod, "_msys_to_windows_path", side_effect=fake_translate): - env._update_cwd({"output": "", "returncode": 0}) + env._update_cwd( + { + "output": f"x\n{marker}/c/whatever/from/bash{marker}\n", + "returncode": 0, + } + ) assert env.cwd == str(new_dir) diff --git a/tools/environments/local.py b/tools/environments/local.py index e18d1a7bd1f5..4f182477fedc 100644 --- a/tools/environments/local.py +++ b/tools/environments/local.py @@ -1353,31 +1353,14 @@ class LocalEnvironment(BaseEnvironment): pass def _update_cwd(self, result: dict): - """Read CWD from temp file (local-only, no round-trip needed). + """Update cwd from the stdout marker emitted by the wrapped command. - Skip the assignment when the path no longer exists as a directory — - ``pwd -P`` on a deleted cwd can leave a stale value in the marker - file, and propagating it would re-wedge the next ``Popen``. The - ``_run_bash`` recovery path will resolve a safe fallback if needed. - - On Windows, the value written by Git Bash's ``pwd -P`` is in - MSYS form (``/c/Users/x``). Translate it to native Windows form - before validating with ``os.path.isdir`` and before storing on - ``self.cwd``; otherwise the isdir check rejects every valid - result and ``_run_bash`` later prints a misleading "cwd is - missing" warning on every command. + The base command wrapper already appends ``pwd -P`` to stdout inside a + session-specific marker, so the local backend can share the same parser + as remote backends instead of re-reading the temp file it just wrote. + ``_extract_cwd_from_output`` keeps the local Windows normalization and + stale-path rollback semantics intact. """ - try: - with open(self._cwd_file, encoding="utf-8") as f: - cwd_path = f.read().strip() - if _IS_WINDOWS: - cwd_path = _msys_to_windows_path(cwd_path) - if cwd_path and os.path.isdir(cwd_path): - self.cwd = cwd_path - except (OSError, FileNotFoundError): - pass - - # Still strip the marker from output so it's not visible self._extract_cwd_from_output(result) def _extract_cwd_from_output(self, result: dict):