diff --git a/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_process_net_command_json.py b/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_process_net_command_json.py index 7922f45c1..c1ae27cf4 100644 --- a/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_process_net_command_json.py +++ b/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_process_net_command_json.py @@ -388,6 +388,10 @@ def get_variable_presentation(setting, default): if bool(path_mappings): pydevd_file_utils.setup_client_server_paths(path_mappings) + resolve_symlinks = args.get('resolveSymlinks', None) + if resolve_symlinks is not None: + pydevd_file_utils.set_resolve_symlinks(resolve_symlinks) + redirecting = args.get("isOutputRedirected") if self._options.redirect_output: py_db.enable_output_redirection(True, True) diff --git a/src/debugpy/_vendored/pydevd/pydevd_file_utils.py b/src/debugpy/_vendored/pydevd/pydevd_file_utils.py index 940d32ee7..ffe0d7f6d 100644 --- a/src/debugpy/_vendored/pydevd/pydevd_file_utils.py +++ b/src/debugpy/_vendored/pydevd/pydevd_file_utils.py @@ -43,7 +43,7 @@ from _pydev_bundle import pydev_log from _pydevd_bundle.pydevd_constants import DebugInfoHolder, IS_WINDOWS, IS_JYTHON, \ - DISABLE_FILE_VALIDATION + DISABLE_FILE_VALIDATION, is_true_in_env from _pydev_bundle._pydev_filesystem_encoding import getfilesystemencoding from _pydevd_bundle.pydevd_comm_constants import file_system_encoding, filesystem_encoding_is_utf8 from _pydev_bundle.pydev_log import error_once @@ -401,6 +401,9 @@ def _abs_and_canonical_path(filename, NORM_PATHS_CONTAINER=NORM_PATHS_CONTAINER) isabs = os_path_isabs(filename) + if _global_resolve_symlinks: + os_path_abspath = os_path_real_path + normalize = False abs_path = _apply_func_and_normalize_case(filename, os_path_abspath, isabs, normalize) @@ -643,6 +646,14 @@ def get_frame_id_from_source_reference(source_reference): return _source_reference_to_frame_id.get(source_reference) +_global_resolve_symlinks = is_true_in_env('PYDEVD_RESOLVE_SYMLINKS') + + +def set_resolve_symlinks(resolve_symlinks): + global _global_resolve_symlinks + _global_resolve_symlinks = resolve_symlinks + + def setup_client_server_paths(paths): '''paths is the same format as PATHS_FROM_ECLIPSE_TO_PYTHON''' diff --git a/src/debugpy/_vendored/pydevd/tests_python/test_debugger_json.py b/src/debugpy/_vendored/pydevd/tests_python/test_debugger_json.py index 69f74c53d..d29c8ea17 100644 --- a/src/debugpy/_vendored/pydevd/tests_python/test_debugger_json.py +++ b/src/debugpy/_vendored/pydevd/tests_python/test_debugger_json.py @@ -6088,6 +6088,43 @@ def run(self): writer.finished_ok = True +@pytest.mark.parametrize('resolve_symlinks', [True, False]) +def test_use_real_path_and_not_links(case_setup, tmpdir, resolve_symlinks): + dira = tmpdir.join('dira') + dira.mkdir() + + dirb = tmpdir.join('dirb') + dirb.mkdir() + + original_file = dira.join('test.py') + original_file.write(''' +print('p1') # Break here +print('p2') +print('TEST SUCEEDED') +''') + + symlinked_file = dirb.join('testit.py') + os.symlink(str(original_file), str(symlinked_file)) + + # I.e.: we're launching the symlinked file but we're actually + # working with the original file afterwards. + with case_setup.test_file(str(symlinked_file)) as writer: + json_facade = JsonFacade(writer) + + writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'), filename=str(original_file)) + json_facade.write_launch(justMyCode=False, resolveSymlinks=resolve_symlinks) + json_facade.write_make_initial_run() + + json_hit = json_facade.wait_for_thread_stopped() + filename = json_hit.stack_trace_response.body.stackFrames[0]['source']['path'] + if resolve_symlinks: + assert filename == str(original_file) + else: + assert filename == str(symlinked_file) + json_facade.write_continue() + writer.finished_ok = True + + if __name__ == '__main__': pytest.main(['-k', 'test_replace_process', '-s'])