def _StartServerNoLock(self): if self._ServerIsRunning(): return self._logfile = utils.CreateLogfile(LOGFILE_FORMAT) tsserver_log = f'-file { self._logfile } -level {_LogLevel()}' # TSServer gets the configuration for the log file through the # environment variable 'TSS_LOG'. This seems to be undocumented but # looking at the source code it seems like this is the way: # https://github.com/Microsoft/TypeScript/blob/8a93b489454fdcbdf544edef05f73a913449be1d/src/server/server.ts#L136 environ = os.environ.copy() environ['TSS_LOG'] = tsserver_log # TSServer runs out of memory on larger projects. This is the value that # VSCode uses. environ['NODE_OPTIONS'] = '--max_old_space_size=3072' LOGGER.info('TSServer log file: %s', self._logfile) # We need to redirect the error stream to the output one on Windows. self._tsserver_handle = utils.SafePopen(self._tsserver_executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=environ) LOGGER.info("TSServer started with PID %s", self._tsserver_handle.pid) self._tsserver_is_running.set() utils.StartThread(self._SetServerVersion)
def _StartServer(self): with self._tsserver_lock: if self._ServerIsRunning(): return self._logfile = utils.CreateLogfile(LOGFILE_FORMAT) tsserver_log = '-file {path} -level {level}'.format( path=self._logfile, level=_LogLevel()) # TSServer gets the configuration for the log file through the # environment variable 'TSS_LOG'. This seems to be undocumented but # looking at the source code it seems like this is the way: # https://github.com/Microsoft/TypeScript/blob/8a93b489454fdcbdf544edef05f73a913449be1d/src/server/server.ts#L136 environ = os.environ.copy() environ['TSS_LOG'] = tsserver_log LOGGER.info('TSServer log file: %s', self._logfile) # We need to redirect the error stream to the output one on Windows. self._tsserver_handle = utils.SafePopen(self._tsserver_executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=environ) self._tsserver_is_running.set() utils.StartThread(self._SetServerVersion)
def ServerManagement_ServerDiesWhileShuttingDown_test( app ): StartClangd( app ) process = psutil.Process( GetPid( app ) ) completer = handlers._server_state.GetFiletypeCompleter( [ 'cpp' ] ) # We issue a shutdown but make sure it never reaches server by mocking # WriteData in Connection. Then we kill the server and check shutdown still # succeeds. with patch.object( completer.GetConnection(), 'WriteData' ): stop_server_task = utils.StartThread( StopCompleterServer, app, 'cpp', '' ) process.terminate() stop_server_task.join() CheckStopped( app )
def __init__(self, user_options): super().__init__(user_options) self._logfile = None self._tsserver_lock = threading.RLock() self._tsserver_handle = None self._tsserver_version = None self._tsserver_executable = FindTSServer( user_options['tsserver_binary_path']) # Used to read response only if TSServer is running. self._tsserver_is_running = threading.Event() # Used to prevent threads from concurrently writing to # the tsserver process' stdin self._write_lock = threading.Lock() # Each request sent to tsserver must have a sequence id. # Responses contain the id sent in the corresponding request. self._sequenceid = itertools.count() # Used to prevent threads from concurrently accessing the sequence counter self._sequenceid_lock = threading.Lock() # Start a thread to read response from TSServer. utils.StartThread(self._ReaderLoop) # Used to map sequence id's to their corresponding DeferredResponse # objects. The reader loop uses this to hand out responses. self._pending = {} # Used to prevent threads from concurrently reading and writing to # the pending response dictionary self._pending_lock = threading.Lock() self._StartServer() self._latest_diagnostics_for_file_lock = threading.Lock() self._latest_diagnostics_for_file = defaultdict(list) # There's someting in the API that lists the trigger characters, but # there is no way to request that from the server, so we just hard-code # the signature triggers. self.SetSignatureHelpTriggers(['(', ',', '<']) LOGGER.info('Enabling TypeScript completion')
def Shutdown_ServerDiesDuringShutdown_test(app): StartClangd(app) debug_info = GetDebugInfo(app) pid = debug_info['completer']['servers'][0]['pid'] process = psutil.Process(pid) completer = handlers._server_state.GetFiletypeCompleter(['cpp']) # We issue a shutdown but make sure it never reaches server by mocking # WriteData in Connection. Then we kill the server and check shutdown still # succeeds. with patch.object(completer.GetConnection(), 'WriteData'): stop_server_task = utils.StartThread(StopCompleterServer, app, 'cpp', '') process.terminate() stop_server_task.join() CheckStopped(app)
def ServerManagement_ServerDiesWhileShuttingDown_test( app ): StartJavaCompleterServerInDirectory( app, PathToTestFile( 'simple_eclipse_project' ) ) request_data = BuildRequest( filetype = 'java' ) debug_info = app.post_json( '/debug_info', request_data ).json print( 'Debug info: {0}'.format( debug_info ) ) pid = debug_info[ 'completer' ][ 'servers' ][ 0 ][ 'pid' ] print( 'pid: {0}'.format( pid ) ) process = psutil.Process( pid ) def StopServerInAnotherThread(): app.post_json( '/run_completer_command', BuildRequest( filetype = 'java', command_arguments = [ 'StopServer' ], ), ) completer = handlers._server_state.GetFiletypeCompleter( [ 'java' ] ) # In this test we mock out the sending method so that we don't actually send # the shutdown request. We then assisted-suicide the downstream server, which # causes the shutdown request to be aborted. This is interpreted by the # shutdown code as a successful shutdown. We need to do the shutdown and # terminate in parallel as the post_json is a blocking call. with patch.object( completer.GetConnection(), 'WriteData' ): stop_server_task = utils.StartThread( StopServerInAnotherThread ) process.terminate() stop_server_task.join() request_data = BuildRequest( filetype = 'java' ) debug_info = app.post_json( '/debug_info', request_data ).json assert_that( debug_info, has_entry( 'completer', has_entry( 'servers', contains( has_entry( 'is_running', False ) ) ) ) )
def __init__(self, user_options): super(TypeScriptCompleter, self).__init__(user_options) self._logfile = None self._tsserver_lock = threading.RLock() self._tsserver_binary_path = FindTsserverBinary() self._tsserver_handle = None self._tsserver_version = None # Used to read response only if TSServer is running. self._tsserver_is_running = threading.Event() # Used to prevent threads from concurrently writing to # the tsserver process' stdin self._write_lock = threading.Lock() # Each request sent to tsserver must have a sequence id. # Responses contain the id sent in the corresponding request. self._sequenceid = itertools.count() # Used to prevent threads from concurrently accessing the sequence counter self._sequenceid_lock = threading.Lock() # Start a thread to read response from TSServer. utils.StartThread(self._ReaderLoop) # Used to map sequence id's to their corresponding DeferredResponse # objects. The reader loop uses this to hand out responses. self._pending = {} # Used to prevent threads from concurrently reading and writing to # the pending response dictionary self._pending_lock = threading.Lock() self._StartServer() self._max_diagnostics_to_display = user_options[ 'max_diagnostics_to_display'] self._latest_diagnostics_for_file_lock = threading.Lock() self._latest_diagnostics_for_file = defaultdict(list) _logger.info('Enabling typescript completion')