diff --git a/ptvsd/_vendored/pydevd/pydevd_file_utils.py b/ptvsd/_vendored/pydevd/pydevd_file_utils.py index 97f3e972e..9a94cd1d8 100644 --- a/ptvsd/_vendored/pydevd/pydevd_file_utils.py +++ b/ptvsd/_vendored/pydevd/pydevd_file_utils.py @@ -144,8 +144,9 @@ def _get_path_with_real_case(filename): convert_to_long_pathname = _convert_to_long_pathname convert_to_short_pathname = _convert_to_short_pathname get_path_with_real_case = _get_path_with_real_case - + elif IS_JYTHON and IS_WINDOWS: + def get_path_with_real_case(filename): from java.io import File f = File(filename) @@ -153,14 +154,14 @@ def get_path_with_real_case(filename): if IS_PY2 and not isinstance(ret, str): return ret.encode(getfilesystemencoding()) return ret - if IS_WINDOWS: if IS_JYTHON: + def normcase(filename): return filename.lower() - + else: def normcase(filename): @@ -168,7 +169,7 @@ def normcase(filename): # side does it, so we should do it manually. if '~' in filename: filename = convert_to_long_pathname(filename) - + filename = _os_normcase(filename) return filename.lower() @@ -189,16 +190,20 @@ def set_ide_os(os): :param os: 'UNIX' or 'WINDOWS' ''' + global _ide_os + prev = _ide_os if os == 'WIN': # Apparently PyCharm uses 'WIN' (https://github.com/fabioz/PyDev.Debugger/issues/116) os = 'WINDOWS' - + assert os in ('WINDOWS', 'UNIX') - global _ide_os - _ide_os = os + if prev != os: + _ide_os = os + # We need to (re)setup how the client <-> server translation works to provide proper separators. + setup_client_server_paths(_last_client_server_paths_set) -DEBUG_CLIENT_SERVER_TRANSLATION = False +DEBUG_CLIENT_SERVER_TRANSLATION = os.environ.get('DEBUG_PYDEVD_PATHS_TRANSLATION', 'False').lower() in ('1', 'true') # Caches filled as requested during the debug session. NORM_PATHS_CONTAINER = {} @@ -372,11 +377,29 @@ def _original_file_to_client(filename, cache={}): norm_file_to_server = _original_file_to_server +def _fix_path(path, sep): + if path.endswith('/') or path.endswith('\\'): + path = path[:-1] + + if sep != '/': + path = path.replace('/', sep) + return path + + +_last_client_server_paths_set = [] + + def setup_client_server_paths(paths): '''paths is the same format as PATHS_FROM_ECLIPSE_TO_PYTHON''' global norm_file_to_client global norm_file_to_server + global _last_client_server_paths_set + _last_client_server_paths_set = paths[:] + + # Work on the client and server slashes. + python_sep = '\\' if IS_WINDOWS else '/' + eclipse_sep = '\\' if _ide_os == 'WINDOWS' else '/' norm_filename_to_server_container = {} norm_filename_to_client_container = {} @@ -391,6 +414,10 @@ def setup_client_server_paths(paths): path0 = path0.encode(sys.getfilesystemencoding()) if isinstance(path1, unicode): path1 = path1.encode(sys.getfilesystemencoding()) + + path0 = _fix_path(path0, eclipse_sep) + path1 = _fix_path(path1, python_sep) + initial_paths[i] = (path0, path1) paths_from_eclipse_to_python[i] = (normcase(path0), normcase(path1)) @@ -400,19 +427,17 @@ def setup_client_server_paths(paths): norm_file_to_server = _original_file_to_server return - # Work on the client and server slashes. - python_sep = '\\' if IS_WINDOWS else '/' - # only setup translation functions if absolutely needed! - def _norm_file_to_server(filename): + def _norm_file_to_server(filename, cache=norm_filename_to_server_container): # Eclipse will send the passed filename to be translated to the python process # So, this would be 'NormFileFromEclipseToPython' try: - return norm_filename_to_server_container[filename] + return cache[filename] except KeyError: - # Note: compute eclipse_sep lazily so that _ide_os is taken into account. - # (https://www.brainwy.com/tracker/PyDev/930) - eclipse_sep = '\\' if _ide_os == 'WINDOWS' else '/' + if eclipse_sep != python_sep: + # Make sure that the separators are what we expect from the IDE. + filename = filename.replace(python_sep, eclipse_sep) + # used to translate a path from the client to the debug server translated = normcase(filename) for eclipse_prefix, server_prefix in paths_from_eclipse_to_python: @@ -433,19 +458,15 @@ def _norm_file_to_server(filename): translated = translated.replace(eclipse_sep, python_sep) translated = _NormFile(translated) - norm_filename_to_server_container[filename] = translated + cache[filename] = translated return translated - def _norm_file_to_client(filename): + def _norm_file_to_client(filename, cache=norm_filename_to_client_container): # The result of this method will be passed to eclipse # So, this would be 'NormFileFromPythonToEclipse' try: - return norm_filename_to_client_container[filename] + return cache[filename] except KeyError: - # Note: compute eclipse_sep lazily so that _ide_os is taken into account. - # (https://www.brainwy.com/tracker/PyDev/930) - eclipse_sep = '\\' if _ide_os == 'WINDOWS' else '/' - # used to translate a path from the debug server to the client translated = _NormFile(filename) @@ -485,7 +506,7 @@ def _norm_file_to_client(filename): # The resulting path is not in the python process, so, we cannot do a _NormFile here, # only at the beginning of this method. - norm_filename_to_client_container[filename] = translated + cache[filename] = translated return translated norm_file_to_server = _norm_file_to_server @@ -550,4 +571,4 @@ def get_package_dir(mod_name): mod_path = join(path, mod_name) if os.path.isdir(mod_path): return mod_path - return None \ No newline at end of file + return None diff --git a/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py b/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py index 1ca0ea1fa..40f0c05fe 100644 --- a/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py +++ b/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py @@ -54,26 +54,48 @@ def check(obtained, expected): # Client and server are on windows. pydevd_file_utils.set_ide_os('WINDOWS') - in_eclipse = 'c:\\foo' - in_python = 'c:\\bar' - PATHS_FROM_ECLIPSE_TO_PYTHON = [ - (in_eclipse, in_python) - ] - pydevd_file_utils.setup_client_server_paths(PATHS_FROM_ECLIPSE_TO_PYTHON) - check(pydevd_file_utils.norm_file_to_server('c:\\foo\\my'), 'c:\\bar\\my') - check(pydevd_file_utils.norm_file_to_server('c:\\foo\\áéíóú'.upper()), 'c:\\bar\\áéíóú') - check(pydevd_file_utils.norm_file_to_client('c:\\bar\\my'), 'c:\\foo\\my') + for in_eclipse, in_python in ([ + ('c:\\foo', 'c:\\bar'), + ('c:/foo', 'c:\\bar'), + ('c:\\foo', 'c:/bar'), + ('c:\\foo', 'c:\\bar\\'), + ('c:/foo', 'c:\\bar\\'), + ('c:\\foo', 'c:/bar/'), + ('c:\\foo\\', 'c:\\bar'), + ('c:/foo/', 'c:\\bar'), + ('c:\\foo\\', 'c:/bar'), + + ]): + PATHS_FROM_ECLIPSE_TO_PYTHON = [ + (in_eclipse, in_python) + ] + pydevd_file_utils.setup_client_server_paths(PATHS_FROM_ECLIPSE_TO_PYTHON) + check(pydevd_file_utils.norm_file_to_server('c:\\foo\\my'), 'c:\\bar\\my') + check(pydevd_file_utils.norm_file_to_server('c:/foo/my'), 'c:\\bar\\my') + check(pydevd_file_utils.norm_file_to_server('c:/foo/my/'), 'c:\\bar\\my') + check(pydevd_file_utils.norm_file_to_server('c:\\foo\\áéíóú'.upper()), 'c:\\bar\\áéíóú') + check(pydevd_file_utils.norm_file_to_client('c:\\bar\\my'), 'c:\\foo\\my') # Client on unix and server on windows pydevd_file_utils.set_ide_os('UNIX') - in_eclipse = '/foo' - in_python = 'c:\\bar' - PATHS_FROM_ECLIPSE_TO_PYTHON = [ - (in_eclipse, in_python) - ] - pydevd_file_utils.setup_client_server_paths(PATHS_FROM_ECLIPSE_TO_PYTHON) - check(pydevd_file_utils.norm_file_to_server('/foo/my'), 'c:\\bar\\my') - check(pydevd_file_utils.norm_file_to_client('c:\\bar\\my'), '/foo/my') + for in_eclipse, in_python in ([ + ('/foo', 'c:\\bar'), + ('/foo', 'c:/bar'), + ('/foo', 'c:\\bar\\'), + ('/foo', 'c:/bar/'), + ('/foo/', 'c:\\bar'), + ('/foo/', 'c:\\bar\\'), + ]): + + PATHS_FROM_ECLIPSE_TO_PYTHON = [ + (in_eclipse, in_python) + ] + pydevd_file_utils.setup_client_server_paths(PATHS_FROM_ECLIPSE_TO_PYTHON) + check(pydevd_file_utils.norm_file_to_server('/foo/my'), 'c:\\bar\\my') + check(pydevd_file_utils.norm_file_to_client('c:\\bar\\my'), '/foo/my') + check(pydevd_file_utils.norm_file_to_client('c:\\bar\\my\\'), '/foo/my') + check(pydevd_file_utils.norm_file_to_client('c:/bar/my'), '/foo/my') + check(pydevd_file_utils.norm_file_to_client('c:/bar/my/'), '/foo/my') # Test with 'real' files # Client and server are on windows. @@ -116,22 +138,33 @@ def check(obtained, expected): pydevd_file_utils.setup_client_server_paths(PATHS_FROM_ECLIPSE_TO_PYTHON) assert pydevd_file_utils.norm_file_to_server(test_dir) == test_dir.lower() assert pydevd_file_utils.norm_file_to_client(test_dir).endswith('\\Foo') - else: # Client on windows and server on unix pydevd_file_utils.set_ide_os('WINDOWS') - in_eclipse = 'c:\\foo' - in_python = '/bar' - PATHS_FROM_ECLIPSE_TO_PYTHON = [ - (in_eclipse, in_python) - ] - pydevd_file_utils.setup_client_server_paths(PATHS_FROM_ECLIPSE_TO_PYTHON) - assert pydevd_file_utils.norm_file_to_server('c:\\foo\\my') == '/bar/my' - assert pydevd_file_utils.norm_file_to_client('/bar/my') == 'c:\\foo\\my' - - # Files for which there's no translation have only their separators updated. - assert pydevd_file_utils.norm_file_to_client('/usr/bin') == '\\usr\\bin' - assert pydevd_file_utils.norm_file_to_server('\\usr\\bin') == '/usr/bin' + for in_eclipse, in_python in ([ + ('c:\\foo', '/bar'), + ('c:/foo', '/bar'), + ('c:/foo/', '/bar'), + ]): + + PATHS_FROM_ECLIPSE_TO_PYTHON = [ + (in_eclipse, in_python) + ] + + pydevd_file_utils.setup_client_server_paths(PATHS_FROM_ECLIPSE_TO_PYTHON) + assert pydevd_file_utils.norm_file_to_server('c:\\foo\\my') == '/bar/my' + assert pydevd_file_utils.norm_file_to_server('c:/foo/my') == '/bar/my' + assert pydevd_file_utils.norm_file_to_server('c:\\foo\\my\\') == '/bar/my' + assert pydevd_file_utils.norm_file_to_server('c:/foo/my/') == '/bar/my' + + assert pydevd_file_utils.norm_file_to_client('/bar/my') == 'c:\\foo\\my' + assert pydevd_file_utils.norm_file_to_client('/bar/my/') == 'c:\\foo\\my' + + # Files for which there's no translation have only their separators updated. + assert pydevd_file_utils.norm_file_to_client('/usr/bin') == '\\usr\\bin' + assert pydevd_file_utils.norm_file_to_client('/usr/bin/') == '\\usr\\bin' + assert pydevd_file_utils.norm_file_to_server('\\usr\\bin') == '/usr/bin' + assert pydevd_file_utils.norm_file_to_server('\\usr\\bin\\') == '/usr/bin' # Client and server on unix pydevd_file_utils.set_ide_os('UNIX')