diff --git a/README.md b/README.md index 936a081f..e7880b84 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio "Jinja", // Enables Jinja (Flask) Template debugging "FixFilePathCase", // See FIX_FILE_PATH_CASE in wrapper.py "DebugStdLib" // Whether to enable debugging of standard library functions + "FilePathIsCaseSensitive" // Whether file paths are case sensitive on the client OS ], "pathMappings": [ { diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py index 2e07eec9..597837df 100644 --- a/ptvsd/wrapper.py +++ b/ptvsd/wrapper.py @@ -828,10 +828,6 @@ class VSCodeMessageProcessor(ipcjson.SocketIO, ipcjson.IpcChannel): @async_handler def on_initialize(self, request, args): # TODO: docstring - cmd = pydevd_comm.CMD_VERSION - os_id = 'WINDOWS' if platform.system() == 'Windows' else 'UNIX' - msg = '1.1\t{}\tID'.format(os_id) - yield self.pydevd_request(cmd, msg) self.send_response( request, supportsExceptionInfoRequest=True, @@ -900,6 +896,7 @@ class VSCodeMessageProcessor(ipcjson.SocketIO, ipcjson.IpcChannel): 'Jinja': 'FLASK_DEBUG=True', 'FixFilePathCase': 'FIX_FILE_PATH_CASE=True', 'DebugStdLib': 'DEBUG_STD_LIB=True', + 'FilePathIsCaseSensitive': 'FILE_PATH_IS_CASE_SENSITIVE=True', } return ';'.join(debug_option_mapping[option] for option in debug_options @@ -914,17 +911,20 @@ class VSCodeMessageProcessor(ipcjson.SocketIO, ipcjson.IpcChannel): INTERPRETER_OPTIONS=string WEB_BROWSER_URL=string url DJANGO_DEBUG=True|False + FILE_PATH_IS_CASE_SENSITIVE=True|False """ + bool_parser = lambda str: str in ("True", "true", "1") DEBUG_OPTIONS_PARSER = { - 'WAIT_ON_ABNORMAL_EXIT': bool, - 'WAIT_ON_NORMAL_EXIT': bool, - 'REDIRECT_OUTPUT': bool, + 'WAIT_ON_ABNORMAL_EXIT': bool_parser, + 'WAIT_ON_NORMAL_EXIT': bool_parser, + 'REDIRECT_OUTPUT': bool_parser, 'VERSION': unquote, 'INTERPRETER_OPTIONS': unquote, 'WEB_BROWSER_URL': unquote, - 'DJANGO_DEBUG': bool, - 'FLASK_DEBUG': bool, - 'FIX_FILE_PATH_CASE': bool, + 'DJANGO_DEBUG': bool_parser, + 'FLASK_DEBUG': bool_parser, + 'FIX_FILE_PATH_CASE': bool_parser, + 'FILE_PATH_IS_CASE_SENSITIVE': bool_parser, } options = {} @@ -934,6 +934,11 @@ class VSCodeMessageProcessor(ipcjson.SocketIO, ipcjson.IpcChannel): except ValueError: continue options[key] = DEBUG_OPTIONS_PARSER[key](value) + + if 'FILE_PATH_IS_CASE_SENSITIVE' not in options: + file_path_is_case_sensitive = platform.system() != 'Windows' + options['FILE_PATH_IS_CASE_SENSITIVE'] = file_path_is_case_sensitive # noqa + return options def _initialize_path_maps(self, args): @@ -947,6 +952,12 @@ class VSCodeMessageProcessor(ipcjson.SocketIO, ipcjson.IpcChannel): if len(pathMaps) > 0: pydevd_file_utils.setup_client_server_paths(pathMaps) + def _send_cmd_version_command(self, file_path_is_case_sensitive): + cmd = pydevd_comm.CMD_VERSION + os_id = 'UNIX' if file_path_is_case_sensitive else 'WINDOWS' + msg = '1.1\t{}\tID'.format(os_id) + return self.pydevd_request(cmd, msg) + @async_handler def on_attach(self, request, args): # TODO: docstring @@ -955,6 +966,8 @@ class VSCodeMessageProcessor(ipcjson.SocketIO, ipcjson.IpcChannel): options = self.build_debug_options(args.get('debugOptions', [])) self.debug_options = self._parse_debug_options( args.get('options', options)) + file_path_is_case_sensitive = self.debug_options.get('FILE_PATH_IS_CASE_SENSITIVE', False) + yield self._send_cmd_version_command(file_path_is_case_sensitive) self.send_response(request) @async_handler @@ -964,6 +977,8 @@ class VSCodeMessageProcessor(ipcjson.SocketIO, ipcjson.IpcChannel): options = self.build_debug_options(args.get('debugOptions', [])) self.debug_options = self._parse_debug_options( args.get('options', options)) + file_path_is_case_sensitive = platform.system() != 'Windows' + yield self._send_cmd_version_command(file_path_is_case_sensitive) self.send_response(request) def on_disconnect(self, request, args): diff --git a/tests/highlevel/test_lifecycle.py b/tests/highlevel/test_lifecycle.py index a170fdf0..1b694c87 100644 --- a/tests/highlevel/test_lifecycle.py +++ b/tests/highlevel/test_lifecycle.py @@ -29,7 +29,7 @@ class LifecycleTests(HighlevelTest, unittest.TestCase): class FIXTURE(HighlevelFixture): lifecycle = None # Make sure we don't cheat. - def test_attach(self): + def attach(self, expected_os_id, attach_args): version = self.debugger.VERSION addr = (None, 8888) daemon = self.vsc.start(addr) @@ -44,7 +44,7 @@ class LifecycleTests(HighlevelTest, unittest.TestCase): }) # attach - req_attach = self.send_request('attach') + req_attach = self.send_request('attach', attach_args) # configuration req_config = self.send_request('configurationDone') @@ -102,11 +102,22 @@ class LifecycleTests(HighlevelTest, unittest.TestCase): ]) self.assert_received(self.debugger, [ self.debugger_msgs.new_request(CMD_VERSION, - *['1.1', OS_ID, 'ID']), + *['1.1', expected_os_id, 'ID']), self.debugger_msgs.new_request(CMD_REDIRECT_OUTPUT), self.debugger_msgs.new_request(CMD_RUN), ]) + def test_attach(self): + self.attach(expected_os_id=OS_ID, attach_args={}) + + def test_attach_from_unix_os(self): + attach_args = {'options':'FILE_PATH_IS_CASE_SENSITIVE=True'} + self.attach(expected_os_id='UNIX', attach_args=attach_args) + + def test_attach_from_windows_os(self): + attach_args = {'options': 'FILE_PATH_IS_CASE_SENSITIVE=False'} + self.attach(expected_os_id='WINDOWS', attach_args=attach_args) + def test_launch(self): version = self.debugger.VERSION addr = (None, 8888) diff --git a/tests/highlevel/test_messages.py b/tests/highlevel/test_messages.py index 9c432479..e1a96b4d 100644 --- a/tests/highlevel/test_messages.py +++ b/tests/highlevel/test_messages.py @@ -93,9 +93,7 @@ class InitializeTests(LifecycleTest, unittest.TestCase): @unittest.skip('tested via test_lifecycle.py') def test_basic(self): - version = self.debugger.VERSION with self.lifecycle.demon_running(port=8888): - self.set_debugger_response(CMD_VERSION, version) req = self.send_request('initialize', { 'adapterID': 'spam', }) @@ -126,10 +124,7 @@ class InitializeTests(LifecycleTest, unittest.TestCase): )), self.new_event(1, 'initialized'), ]) - self.assert_received(self.debugger, [ - self.new_debugger_request(CMD_VERSION, - *['1.1', OS_ID, 'ID']), - ]) + self.assert_received(self.debugger, []) ################################## @@ -1882,11 +1877,13 @@ class SourceTests(NormalRequestTest, unittest.TestCase): def test_unsupported(self): with self.launched(): self.send_request( - sourceReference=1, + sourceReference=0, ) received = self.vsc.received - self.assert_vsc_received(received, []) + self.assert_vsc_received(received, [ + self.expected_failure('Source unavailable'), + ]) self.assert_received(self.debugger, [])