diff --git a/python/ycm/server/ycmd.py b/python/ycm/server/ycmd.py index aa10923f..ed9dee15 100755 --- a/python/ycm/server/ycmd.py +++ b/python/ycm/server/ycmd.py @@ -26,6 +26,7 @@ import json import argparse import waitress import signal +import os from ycm import user_options_store from ycm import extra_conf_store from ycm.server.watchdog_plugin import WatchdogPlugin @@ -38,8 +39,25 @@ def YcmCoreSanityCheck(): # We manually call sys.exit() on SIGTERM and SIGINT so that atexit handlers are # properly executed. -def SetUpSignalHandler(): +def SetUpSignalHandler(stdout, stderr, keep_logfiles): def SignalHandler( signum, frame ): + if stderr: + # Reset stderr, just in case something tries to use it + tmp = sys.stderr + sys.stderr = sys.__stderr__ + tmp.close() + if stdout: + # Reset stdout, just in case something tries to use it + tmp = sys.stdout + sys.stdout = sys.__stdout__ + tmp.close() + + if not keep_logfiles: + if stderr: + utils.RemoveIfExists( stderr ) + if stdout: + utils.RemoveIfExists( stdout ) + sys.exit() for sig in [ signal.SIGTERM, @@ -61,8 +79,21 @@ def Main(): help = 'num idle seconds before server shuts down') parser.add_argument( '--options_file', type = str, default = '', help = 'file with user options, in JSON format' ) + parser.add_argument( '--stdout', type = str, default = None, + help = 'optional file to use for stdout' ) + parser.add_argument( '--stderr', type = str, default = None, + help = 'optional file to use for stderr' ) + parser.add_argument( '--keep_logfiles', action = 'store_true', default = None, + help = 'optional file to use for stderr' ) args = parser.parse_args() + if args.stdout is not None: + sys.stdout = open(args.stdout, "wb") + #os.dup2(stdout.fileno(), sys.stdout.fileno()) + if args.stderr is not None: + sys.stderr = open(args.stderr, "wb") + #os.dup2(stderr.fileno(), sys.stderr.fileno()) + numeric_level = getattr( logging, args.log.upper(), None ) if not isinstance( numeric_level, int ): raise ValueError( 'Invalid log level: %s' % args.log ) @@ -86,7 +117,7 @@ def Main(): # preload has executed. from ycm.server import handlers handlers.UpdateUserOptions( options ) - SetUpSignalHandler() + SetUpSignalHandler(args.stdout, args.stderr, args.keep_logfiles) handlers.app.install( WatchdogPlugin( args.idle_suicide_seconds ) ) waitress.serve( handlers.app, host = args.host, diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py index b4a45c15..c6e11be7 100644 --- a/python/ycm/youcompleteme.py +++ b/python/ycm/youcompleteme.py @@ -22,6 +22,7 @@ import vim import tempfile import json import signal +from subprocess import PIPE from ycm import vimsupport from ycm import utils from ycm.diagnostic_interface import DiagnosticInterface @@ -84,26 +85,22 @@ class YouCompleteMe( object ): self._SetupServer() self._ycmd_keepalive.Start() - def _SetupServer( self ): server_port = utils.GetUnusedLocalhostPort() with tempfile.NamedTemporaryFile( delete = False ) as options_file: self._temp_options_filename = options_file.name json.dump( dict( self._user_options ), options_file ) options_file.flush() + args = [ utils.PathToPythonInterpreter(), _PathToServerScript(), '--port={0}'.format( server_port ), '--options_file={0}'.format( options_file.name ), '--log={0}'.format( self._user_options[ 'server_log_level' ] ), '--idle_suicide_seconds={0}'.format( - SERVER_IDLE_SUICIDE_SECONDS ) ] + SERVER_IDLE_SUICIDE_SECONDS )] - BaseRequest.server_location = 'http://localhost:' + str( server_port ) - - if self._user_options[ 'server_use_vim_stdout' ]: - self._server_popen = utils.SafePopen( args ) - else: + if not self._user_options[ 'server_use_vim_stdout' ]: filename_format = os.path.join( utils.PathToTempDir(), 'server_{port}_{std}.log' ) @@ -111,15 +108,18 @@ class YouCompleteMe( object ): std = 'stdout' ) self._server_stderr = filename_format.format( port = server_port, std = 'stderr' ) + args.append('--stdout={0}'.format( self._server_stdout )) + args.append('--stderr={0}'.format( self._server_stderr )) + + if self._user_options[ 'server_keep_logfiles' ]: + args.append('--keep_logfiles') + + self._server_popen = utils.SafePopen( args, stdout = PIPE, stderr = PIPE) + + BaseRequest.server_location = 'http://localhost:' + str( server_port ) - with open( self._server_stderr, 'w' ) as fstderr: - with open( self._server_stdout, 'w' ) as fstdout: - self._server_popen = utils.SafePopen( args, - stdout = fstdout, - stderr = fstderr ) self._NotifyUserIfServerCrashed() - def _IsServerAlive( self ): returncode = self._server_popen.poll() # When the process hasn't finished yet, poll() returns None. @@ -149,16 +149,8 @@ class YouCompleteMe( object ): def _ServerCleanup( self ): if self._IsServerAlive(): self._server_popen.terminate() - self._server_popen.communicate() utils.RemoveIfExists( self._temp_options_filename ) - if not self._user_options[ 'server_keep_logfiles' ]: - if self._server_stderr: - utils.RemoveIfExists( self._server_stderr ) - if self._server_stdout: - utils.RemoveIfExists( self._server_stdout ) - - def RestartServer( self ): vimsupport.PostVimMessage( 'Restarting ycmd server...' ) self._user_notified_about_crash = False