Passing user options as file to server

This is a much better idea than starting the server in a default state, and then
resetting the state with a POST request.
This commit is contained in:
Strahinja Val Markovic 2013-09-24 14:00:27 -07:00
parent 10469d318d
commit dd2445db06
3 changed files with 44 additions and 129 deletions

View File

@ -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

View File

@ -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 )

View File

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