Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Commit

Permalink
Fixes issues dealing with path separators on path mappings. Fixes #762,
Browse files Browse the repository at this point in the history
  • Loading branch information
fabioz authored and karthiknadig committed Sep 12, 2018
1 parent c36bf32 commit 66d75d8
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 55 deletions.
71 changes: 46 additions & 25 deletions ptvsd/_vendored/pydevd/pydevd_file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,31 +144,32 @@ 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)
ret = f.getCanonicalPath()
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):
# `normcase` doesn't lower case on Python 2 for non-English locale, but Java
# 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()

Expand All @@ -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 = {}
Expand Down Expand Up @@ -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 = {}
Expand All @@ -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))

Expand All @@ -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:
Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
return None
93 changes: 63 additions & 30 deletions ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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')
Expand Down

0 comments on commit 66d75d8

Please sign in to comment.