diff --git a/python/ycm/retries.py b/python/ycm/retries.py deleted file mode 100644 index 1d7131d5..00000000 --- a/python/ycm/retries.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2012 by Jeff Laughlin Consulting LLC -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - - -import sys -from time import sleep - -# Source: https://gist.github.com/n1ywb/2570004 - -def example_exc_handler(tries_remaining, exception, delay): - """Example exception handler; prints a warning to stderr. - - tries_remaining: The number of tries remaining. - exception: The exception instance which was raised. - """ - print >> sys.stderr, "Caught '%s', %d tries remaining, sleeping for %s seconds" % (exception, tries_remaining, delay) - - -def retries(max_tries, delay=1, backoff=2, exceptions=(Exception,), hook=None): - """Function decorator implementing retrying logic. - - delay: Sleep this many seconds * backoff * try number after failure - backoff: Multiply delay by this factor after each failure - exceptions: A tuple of exception classes; default (Exception,) - hook: A function with the signature myhook(tries_remaining, exception); - default None - - The decorator will call the function up to max_tries times if it raises - an exception. - - By default it catches instances of the Exception class and subclasses. - This will recover after all but the most fatal errors. You may specify a - custom tuple of exception classes with the 'exceptions' argument; the - function will only be retried if it raises one of the specified - exceptions. - - Additionally you may specify a hook function which will be called prior - to retrying with the number of remaining tries and the exception instance; - see given example. This is primarily intended to give the opportunity to - log the failure. Hook is not called after failure if no retries remain. - """ - def dec(func): - def f2(*args, **kwargs): - mydelay = delay - tries = range(max_tries) - tries.reverse() - for tries_remaining in tries: - try: - return func(*args, **kwargs) - except exceptions as e: - if tries_remaining > 0: - if hook is not None: - hook(tries_remaining, e, mydelay) - sleep(mydelay) - mydelay = mydelay * backoff - else: - raise - else: - break - return f2 - return dec diff --git a/python/ycm/server/server.py b/python/ycm/server/server.py index 1b8387dd..85520ca6 100755 --- a/python/ycm/server/server.py +++ b/python/ycm/server/server.py @@ -114,12 +114,8 @@ def GetUserOptions(): @app.post( '/user_options' ) def SetUserOptions(): - global SERVER_STATE - LOGGER.info( 'Received user options POST request') - data = request.json - SERVER_STATE = server_state.ServerState( data ) - user_options_store.SetAll( data ) + _SetUserOptions( request.json ) @app.post( '/filetype_completion_available') @@ -139,6 +135,13 @@ def _ServerShutdown(): SERVER_STATE.Shutdown() +def _SetUserOptions( options ): + global SERVER_STATE + + SERVER_STATE = server_state.ServerState( options ) + user_options_store.SetAll( options ) + + def Main(): global LOGGER parser = argparse.ArgumentParser() @@ -149,8 +152,13 @@ def Main(): parser.add_argument( '--log', type = str, default = 'info', help='log level, one of ' '[debug|info|warning|error|critical]') + parser.add_argument( '--options_file', type = str, default = '', + help='file with user options, in JSON format') args = parser.parse_args() + if args.options_file: + _SetUserOptions( json.load( open( args.options_file, 'r' ) ) ) + numeric_level = getattr( logging, args.log.upper(), None ) if not isinstance( numeric_level, int ): raise ValueError( 'Invalid log level: %s' % args.log ) diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py index 3d3ca2be..2a5b48b7 100644 --- a/python/ycm/youcompleteme.py +++ b/python/ycm/youcompleteme.py @@ -21,8 +21,8 @@ import os import vim import ycm_core import subprocess -import threading -from ycm.retries import retries +import tempfile +import json from ycm import vimsupport from ycm import utils from ycm.completers.all.omni_completer import OmniCompleter @@ -43,57 +43,43 @@ class YouCompleteMe( object ): self._server_stderr = None self._server_popen = None self._filetypes_with_keywords_loaded = set() - self._options_thread = None + self._temp_options_filename = None self._SetupServer() def _SetupServer( self ): server_port = SERVER_PORT_RANGE_START + os.getpid() - command = ''.join( [ 'python ', - _PathToServerScript(), - ' --port=', - str( server_port ), - ' --log=', - self._user_options[ 'server_log_level' ] ] ) + with tempfile.NamedTemporaryFile( delete = False ) as options_file: + self._temp_options_filename = options_file.name + json.dump( dict( self._user_options ), options_file ) + command = ''.join( [ 'python ', + _PathToServerScript(), + ' --port=', + str( server_port ), + ' --options_file=', + options_file.name, + ' --log=', + self._user_options[ 'server_log_level' ] ] ) - BaseRequest.server_location = 'http://localhost:' + str( server_port ) + BaseRequest.server_location = 'http://localhost:' + str( server_port ) - if self._user_options[ 'server_use_vim_stdout' ]: - self._server_popen = subprocess.Popen( command, shell = True ) - else: - filename_format = os.path.join( utils.PathToTempDir(), - 'server_{port}_{std}.log' ) + if self._user_options[ 'server_use_vim_stdout' ]: + self._server_popen = subprocess.Popen( command, shell = True ) + else: + filename_format = os.path.join( utils.PathToTempDir(), + 'server_{port}_{std}.log' ) - self._server_stdout = filename_format.format( port = server_port, - std = 'stdout' ) - self._server_stderr = filename_format.format( port = server_port, - std = 'stderr' ) - - with open( self._server_stderr, 'w' ) as fstderr: - with open( self._server_stdout, 'w' ) as fstdout: - self._server_popen = subprocess.Popen( command, - stdout = fstdout, - stderr = fstderr, - shell = True ) - - self._StartOptionsThread() - - - def _StartOptionsThread( self ): - def OptionsThreadMain( options ): - @retries( 5, delay = 0.5 ) - def PostOptionsToServer(): - BaseRequest.PostDataToHandler( options, 'user_options' ) - - PostOptionsToServer() - - self._options_thread = threading.Thread( - target = OptionsThreadMain, - args = ( dict( self._user_options ), ) ) - - self._options_thread.daemon = True - self._options_thread.start() + self._server_stdout = filename_format.format( port = server_port, + std = 'stdout' ) + self._server_stderr = filename_format.format( port = server_port, + std = 'stderr' ) + with open( self._server_stderr, 'w' ) as fstderr: + with open( self._server_stdout, 'w' ) as fstdout: + self._server_popen = subprocess.Popen( command, + stdout = fstdout, + stderr = fstderr, + shell = False ) def CreateCompletionRequest( self ): @@ -165,6 +151,7 @@ class YouCompleteMe( object ): def OnVimLeave( self ): self._server_popen.terminate() + os.remove( self._temp_options_filename ) def OnCurrentIdentifierFinished( self ):