ycm_core now imported after extra conf preload

This commit is contained in:
Strahinja Val Markovic 2013-10-14 15:29:00 -07:00
parent bc607724f0
commit b903867cdd
5 changed files with 289 additions and 223 deletions

View File

@ -0,0 +1,210 @@
#!/usr/bin/env python
#
# Copyright (C) 2013 Strahinja Val Markovic <val@markovic.io>
#
# This file is part of YouCompleteMe.
#
# YouCompleteMe is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# YouCompleteMe is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
import atexit
import logging
import json
import bottle
import httplib
from bottle import request, response
import server_state
from ycm import user_options_store
from ycm.server.responses import BuildExceptionResponse
from ycm import extra_conf_store
# num bytes for the request body buffer; request.json only works if the request
# size is less than this
bottle.Request.MEMFILE_MAX = 300 * 1024
# TODO: rename these to _lower_case
SERVER_STATE = None
LOGGER = logging.getLogger( __name__ )
app = bottle.Bottle()
@app.post( '/event_notification' )
def EventNotification():
LOGGER.info( 'Received event notification' )
request_data = request.json
event_name = request_data[ 'event_name' ]
LOGGER.debug( 'Event name: %s', event_name )
event_handler = 'On' + event_name
getattr( SERVER_STATE.GetGeneralCompleter(), event_handler )( request_data )
filetypes = request_data[ 'filetypes' ]
response_data = None
if SERVER_STATE.FiletypeCompletionUsable( filetypes ):
response_data = getattr( SERVER_STATE.GetFiletypeCompleter( filetypes ),
event_handler )( request_data )
if response_data:
return _JsonResponse( response_data )
@app.post( '/run_completer_command' )
def RunCompleterCommand():
LOGGER.info( 'Received command request' )
request_data = request.json
completer = _GetCompleterForRequestData( request_data )
return _JsonResponse( completer.OnUserCommand(
request_data[ 'command_arguments' ],
request_data ) )
@app.post( '/completions' )
def GetCompletions():
LOGGER.info( 'Received completion request' )
request_data = request.json
do_filetype_completion = SERVER_STATE.ShouldUseFiletypeCompleter(
request_data )
LOGGER.debug( 'Using filetype completion: %s', do_filetype_completion )
filetypes = request_data[ 'filetypes' ]
completer = ( SERVER_STATE.GetFiletypeCompleter( filetypes ) if
do_filetype_completion else
SERVER_STATE.GetGeneralCompleter() )
return _JsonResponse( completer.ComputeCandidates( request_data ) )
@app.get( '/user_options' )
def GetUserOptions():
LOGGER.info( 'Received user options GET request' )
return _JsonResponse( dict( SERVER_STATE.user_options ) )
@app.get( '/healthy' )
def GetHealthy():
LOGGER.info( 'Received health request' )
return _JsonResponse( True )
@app.post( '/user_options' )
def SetUserOptions():
LOGGER.info( 'Received user options POST request' )
UpdateUserOptions( request.json )
@app.post( '/semantic_completion_available' )
def FiletypeCompletionAvailable():
LOGGER.info( 'Received filetype completion available request' )
return _JsonResponse( SERVER_STATE.FiletypeCompletionAvailable(
request.json[ 'filetypes' ] ) )
@app.post( '/defined_subcommands' )
def DefinedSubcommands():
LOGGER.info( 'Received defined subcommands request' )
completer = _GetCompleterForRequestData( request.json )
return _JsonResponse( completer.DefinedSubcommands() )
@app.post( '/detailed_diagnostic' )
def GetDetailedDiagnostic():
LOGGER.info( 'Received detailed diagnostic request' )
request_data = request.json
completer = _GetCompleterForRequestData( request_data )
return _JsonResponse( completer.GetDetailedDiagnostic( request_data ) )
@app.post( '/load_extra_conf_file' )
def LoadExtraConfFile():
LOGGER.info( 'Received extra conf load request' )
request_data = request.json
extra_conf_store.Load( request_data[ 'filepath' ], force = True )
@app.post( '/debug_info' )
def DebugInfo():
# This can't be at the top level because of possible extra conf preload
import ycm_core
LOGGER.info( 'Received debug info request' )
output = []
has_clang_support = ycm_core.HasClangSupport()
output.append( 'Server has Clang support compiled in: {0}'.format(
has_clang_support ) )
if has_clang_support:
output.append( 'Clang version: ' + ycm_core.ClangVersion() )
request_data = request.json
try:
output.append(
_GetCompleterForRequestData( request_data ).DebugInfo( request_data) )
except:
pass
return _JsonResponse( '\n'.join( output ) )
# The type of the param is Bottle.HTTPError
@app.error( httplib.INTERNAL_SERVER_ERROR )
def ErrorHandler( httperror ):
return _JsonResponse( BuildExceptionResponse( httperror.exception,
httperror.traceback ) )
def _JsonResponse( data ):
response.set_header( 'Content-Type', 'application/json' )
return json.dumps( data, default = _UniversalSerialize )
def _UniversalSerialize( obj ):
serialized = obj.__dict__.copy()
serialized[ 'TYPE' ] = type( obj ).__name__
return serialized
def _GetCompleterForRequestData( request_data ):
completer_target = request_data.get( 'completer_target', None )
if completer_target == 'identifier':
return SERVER_STATE.GetGeneralCompleter().GetIdentifierCompleter()
elif completer_target == 'filetype_default' or not completer_target:
return SERVER_STATE.GetFiletypeCompleter( request_data[ 'filetypes' ] )
else:
return SERVER_STATE.GetFiletypeCompleter( [ completer_target ] )
@atexit.register
def _ServerShutdown():
if SERVER_STATE:
SERVER_STATE.Shutdown()
extra_conf_store.Shutdown()
def UpdateUserOptions( options ):
global SERVER_STATE
if not options:
return
user_options_store.SetAll( options )
SERVER_STATE = server_state.ServerState( options )
def SetServerStateToDefaults():
global SERVER_STATE, LOGGER
LOGGER = logging.getLogger( __name__ )
user_options_store.LoadDefaults()
SERVER_STATE = server_state.ServerState( user_options_store.GetAll() )
extra_conf_store.Reset()

View File

@ -19,7 +19,6 @@
import imp import imp
import os import os
from ycm import extra_conf_store
from ycm.utils import ForceSemanticCompletion from ycm.utils import ForceSemanticCompletion
from ycm.completers.general.general_completer_store import GeneralCompleterStore from ycm.completers.general.general_completer_store import GeneralCompleterStore
from ycm.completers.completer_utils import PathToFiletypeCompleterPluginLoader from ycm.completers.completer_utils import PathToFiletypeCompleterPluginLoader
@ -30,7 +29,6 @@ class ServerState( object ):
self._user_options = user_options self._user_options = user_options
self._filetype_completers = {} self._filetype_completers = {}
self._gencomp = GeneralCompleterStore( self._user_options ) self._gencomp = GeneralCompleterStore( self._user_options )
extra_conf_store.CallGlobalExtraConfYcmCorePreloadIfExists()
@property @property
@ -44,7 +42,6 @@ class ServerState( object ):
completer.Shutdown() completer.Shutdown()
self._gencomp.Shutdown() self._gencomp.Shutdown()
extra_conf_store.Shutdown()
def _GetFiletypeCompleterForFiletype( self, filetype ): def _GetFiletypeCompleterForFiletype( self, filetype ):

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python
#
# Copyright (C) 2013 Strahinja Val Markovic <val@markovic.io>
#
# This file is part of YouCompleteMe.
#
# YouCompleteMe is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# YouCompleteMe is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
def SetUpPythonPath():
# We want to have the YouCompleteMe/python directory on the Python PATH
# because all the code already assumes that it's there. This is a relic from
# before the client/server architecture.
# TODO: Fix things so that this is not needed anymore when we split ycmd into
# a separate repository.
sys.path.insert( 0, os.path.join(
os.path.dirname( os.path.abspath( __file__ ) ),
'../..' ) )
from ycm import utils
utils.AddThirdPartyFoldersToSysPath()

View File

@ -20,8 +20,10 @@
import os import os
import httplib import httplib
import time import time
from ..server_utils import SetUpPythonPath
SetUpPythonPath()
from webtest import TestApp from webtest import TestApp
from .. import ycmd from .. import handlers
from ..responses import BuildCompletionData, UnknownExtraConf from ..responses import BuildCompletionData, UnknownExtraConf
from nose.tools import ok_, eq_, with_setup from nose.tools import ok_, eq_, with_setup
from hamcrest import ( assert_that, has_items, has_entry, contains, from hamcrest import ( assert_that, has_items, has_entry, contains,
@ -73,7 +75,7 @@ def CompletionEntryMatcher( insertion_text ):
def Setup(): def Setup():
ycmd.SetServerStateToDefaults() handlers.SetServerStateToDefaults()
def PathToTestDataDir(): def PathToTestDataDir():
@ -87,7 +89,7 @@ def PathToTestFile( test_basename ):
@with_setup( Setup ) @with_setup( Setup )
def GetCompletions_IdentifierCompleter_Works_test(): def GetCompletions_IdentifierCompleter_Works_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
event_data = BuildRequest( contents = 'foo foogoo ba', event_data = BuildRequest( contents = 'foo foogoo ba',
event_name = 'FileReadyToParse' ) event_name = 'FileReadyToParse' )
@ -104,7 +106,7 @@ def GetCompletions_IdentifierCompleter_Works_test():
@with_setup( Setup ) @with_setup( Setup )
def GetCompletions_CsCompleter_Works_test(): def GetCompletions_CsCompleter_Works_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
filepath = PathToTestFile( 'testy/Program.cs' ) filepath = PathToTestFile( 'testy/Program.cs' )
contents = open( filepath ).read() contents = open( filepath ).read()
event_data = BuildRequest( filepath = filepath, event_data = BuildRequest( filepath = filepath,
@ -138,7 +140,7 @@ def GetCompletions_CsCompleter_Works_test():
@with_setup( Setup ) @with_setup( Setup )
def GetCompletions_ClangCompleter_WorksWithExplicitFlags_test(): def GetCompletions_ClangCompleter_WorksWithExplicitFlags_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
contents = """ contents = """
struct Foo { struct Foo {
int x; int x;
@ -170,7 +172,7 @@ int main()
@with_setup( Setup ) @with_setup( Setup )
def GetCompletions_ClangCompleter_UnknownExtraConfException_test(): def GetCompletions_ClangCompleter_UnknownExtraConfException_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
filepath = PathToTestFile( 'basic.cpp' ) filepath = PathToTestFile( 'basic.cpp' )
completion_data = BuildRequest( filepath = filepath, completion_data = BuildRequest( filepath = filepath,
filetype = 'cpp', filetype = 'cpp',
@ -189,7 +191,7 @@ def GetCompletions_ClangCompleter_UnknownExtraConfException_test():
@with_setup( Setup ) @with_setup( Setup )
def GetCompletions_ClangCompleter_WorksWhenExtraConfExplicitlyAllowed_test(): def GetCompletions_ClangCompleter_WorksWhenExtraConfExplicitlyAllowed_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
app.post_json( '/load_extra_conf_file', app.post_json( '/load_extra_conf_file',
{ 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } ) { 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } )
@ -209,7 +211,7 @@ def GetCompletions_ClangCompleter_WorksWhenExtraConfExplicitlyAllowed_test():
@with_setup( Setup ) @with_setup( Setup )
def GetCompletions_ClangCompleter_ForceSemantic_OnlyFileteredCompletions_test(): def GetCompletions_ClangCompleter_ForceSemantic_OnlyFileteredCompletions_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
contents = """ contents = """
int main() int main()
{ {
@ -241,7 +243,7 @@ int main()
@with_setup( Setup ) @with_setup( Setup )
def GetCompletions_ForceSemantic_Works_test(): def GetCompletions_ForceSemantic_Works_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
completion_data = BuildRequest( filetype = 'python', completion_data = BuildRequest( filetype = 'python',
force_semantic = True ) force_semantic = True )
@ -254,7 +256,7 @@ def GetCompletions_ForceSemantic_Works_test():
@with_setup( Setup ) @with_setup( Setup )
def GetCompletions_IdentifierCompleter_SyntaxKeywordsAdded_test(): def GetCompletions_IdentifierCompleter_SyntaxKeywordsAdded_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
event_data = BuildRequest( event_name = 'FileReadyToParse', event_data = BuildRequest( event_name = 'FileReadyToParse',
syntax_keywords = ['foo', 'bar', 'zoo'] ) syntax_keywords = ['foo', 'bar', 'zoo'] )
@ -271,7 +273,7 @@ def GetCompletions_IdentifierCompleter_SyntaxKeywordsAdded_test():
@with_setup( Setup ) @with_setup( Setup )
def GetCompletions_UltiSnipsCompleter_Works_test(): def GetCompletions_UltiSnipsCompleter_Works_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
event_data = BuildRequest( event_data = BuildRequest(
event_name = 'BufferVisit', event_name = 'BufferVisit',
ultisnips_snippets = [ ultisnips_snippets = [
@ -292,7 +294,7 @@ def GetCompletions_UltiSnipsCompleter_Works_test():
@with_setup( Setup ) @with_setup( Setup )
def RunCompleterCommand_GoTo_Jedi_ZeroBasedLineAndColumn_test(): def RunCompleterCommand_GoTo_Jedi_ZeroBasedLineAndColumn_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
contents = """ contents = """
def foo(): def foo():
pass pass
@ -318,7 +320,7 @@ foo()
@with_setup( Setup ) @with_setup( Setup )
def RunCompleterCommand_GoTo_Clang_ZeroBasedLineAndColumn_test(): def RunCompleterCommand_GoTo_Clang_ZeroBasedLineAndColumn_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
contents = """ contents = """
struct Foo { struct Foo {
int x; int x;
@ -352,7 +354,7 @@ int main()
@with_setup( Setup ) @with_setup( Setup )
def DefinedSubcommands_Works_test(): def DefinedSubcommands_Works_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
subcommands_data = BuildRequest( completer_target = 'python' ) subcommands_data = BuildRequest( completer_target = 'python' )
eq_( [ 'GoToDefinition', eq_( [ 'GoToDefinition',
@ -363,7 +365,7 @@ def DefinedSubcommands_Works_test():
@with_setup( Setup ) @with_setup( Setup )
def DefinedSubcommands_WorksWhenNoExplicitCompleterTargetSpecified_test(): def DefinedSubcommands_WorksWhenNoExplicitCompleterTargetSpecified_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
subcommands_data = BuildRequest( filetype = 'python' ) subcommands_data = BuildRequest( filetype = 'python' )
eq_( [ 'GoToDefinition', eq_( [ 'GoToDefinition',
@ -374,7 +376,7 @@ def DefinedSubcommands_WorksWhenNoExplicitCompleterTargetSpecified_test():
@with_setup( Setup ) @with_setup( Setup )
def Diagnostics_ClangCompleter_ZeroBasedLineAndColumn_test(): def Diagnostics_ClangCompleter_ZeroBasedLineAndColumn_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
contents = """ contents = """
struct Foo { struct Foo {
int x // semicolon missing here! int x // semicolon missing here!
@ -399,7 +401,7 @@ struct Foo {
@with_setup( Setup ) @with_setup( Setup )
def GetDetailedDiagnostic_ClangCompleter_Works_test(): def GetDetailedDiagnostic_ClangCompleter_Works_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
contents = """ contents = """
struct Foo { struct Foo {
int x // semicolon missing here! int x // semicolon missing here!
@ -427,7 +429,7 @@ struct Foo {
@with_setup( Setup ) @with_setup( Setup )
def FiletypeCompletionAvailable_Works_test(): def FiletypeCompletionAvailable_Works_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
request_data = { request_data = {
'filetypes': ['python'] 'filetypes': ['python']
} }
@ -438,7 +440,7 @@ def FiletypeCompletionAvailable_Works_test():
@with_setup( Setup ) @with_setup( Setup )
def UserOptions_Works_test(): def UserOptions_Works_test():
app = TestApp( ycmd.app ) app = TestApp( handlers.app )
options = app.get( '/user_options' ).json options = app.get( '/user_options' ).json
ok_( len( options ) ) ok_( len( options ) )

View File

@ -17,214 +17,24 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
from server_utils import SetUpPythonPath
SetUpPythonPath()
import sys import sys
import os
import atexit
# We want to have the YouCompleteMe/python directory on the Python PATH because
# all the code already assumes that it's there. This is a relic from before the
# client/server architecture.
# TODO: Fix things so that this is not needed anymore when we split ycmd into a
# separate repository.
sys.path.insert( 0, os.path.join(
os.path.dirname( os.path.abspath( __file__ ) ),
'../..' ) )
from ycm import utils
utils.AddThirdPartyFoldersToSysPath()
import logging import logging
import json import json
import bottle
import argparse import argparse
import httplib
import waitress import waitress
from bottle import request, response
import server_state
from ycm import user_options_store from ycm import user_options_store
from ycm.server.responses import BuildExceptionResponse
from ycm import extra_conf_store from ycm import extra_conf_store
# num bytes for the request body buffer; request.json only works if the request
# size is less than this
bottle.Request.MEMFILE_MAX = 300 * 1024
# TODO: rename these to _lower_case def YcmCoreSanityCheck():
SERVER_STATE = None if 'ycm_core' in sys.modules:
LOGGER = None raise RuntimeError( 'ycm_core already imported, ycmd has a bug!' )
app = bottle.Bottle()
@app.post( '/event_notification' )
def EventNotification():
LOGGER.info( 'Received event notification' )
request_data = request.json
event_name = request_data[ 'event_name' ]
LOGGER.debug( 'Event name: %s', event_name )
event_handler = 'On' + event_name
getattr( SERVER_STATE.GetGeneralCompleter(), event_handler )( request_data )
filetypes = request_data[ 'filetypes' ]
response_data = None
if SERVER_STATE.FiletypeCompletionUsable( filetypes ):
response_data = getattr( SERVER_STATE.GetFiletypeCompleter( filetypes ),
event_handler )( request_data )
if response_data:
return _JsonResponse( response_data )
@app.post( '/run_completer_command' )
def RunCompleterCommand():
LOGGER.info( 'Received command request' )
request_data = request.json
completer = _GetCompleterForRequestData( request_data )
return _JsonResponse( completer.OnUserCommand(
request_data[ 'command_arguments' ],
request_data ) )
@app.post( '/completions' )
def GetCompletions():
LOGGER.info( 'Received completion request' )
request_data = request.json
do_filetype_completion = SERVER_STATE.ShouldUseFiletypeCompleter(
request_data )
LOGGER.debug( 'Using filetype completion: %s', do_filetype_completion )
filetypes = request_data[ 'filetypes' ]
completer = ( SERVER_STATE.GetFiletypeCompleter( filetypes ) if
do_filetype_completion else
SERVER_STATE.GetGeneralCompleter() )
return _JsonResponse( completer.ComputeCandidates( request_data ) )
@app.get( '/user_options' )
def GetUserOptions():
LOGGER.info( 'Received user options GET request' )
return _JsonResponse( dict( SERVER_STATE.user_options ) )
@app.get( '/healthy' )
def GetHealthy():
LOGGER.info( 'Received health request' )
return _JsonResponse( True )
@app.post( '/user_options' )
def SetUserOptions():
LOGGER.info( 'Received user options POST request' )
_SetUserOptions( request.json )
@app.post( '/semantic_completion_available' )
def FiletypeCompletionAvailable():
LOGGER.info( 'Received filetype completion available request' )
return _JsonResponse( SERVER_STATE.FiletypeCompletionAvailable(
request.json[ 'filetypes' ] ) )
@app.post( '/defined_subcommands' )
def DefinedSubcommands():
LOGGER.info( 'Received defined subcommands request' )
completer = _GetCompleterForRequestData( request.json )
return _JsonResponse( completer.DefinedSubcommands() )
@app.post( '/detailed_diagnostic' )
def GetDetailedDiagnostic():
LOGGER.info( 'Received detailed diagnostic request' )
request_data = request.json
completer = _GetCompleterForRequestData( request_data )
return _JsonResponse( completer.GetDetailedDiagnostic( request_data ) )
@app.post( '/load_extra_conf_file' )
def LoadExtraConfFile():
LOGGER.info( 'Received extra conf load request' )
request_data = request.json
extra_conf_store.Load( request_data[ 'filepath' ], force = True )
@app.post( '/debug_info' )
def DebugInfo():
# This can't be at the top level because of possible extra conf preload
import ycm_core
LOGGER.info( 'Received debug info request' )
output = []
has_clang_support = ycm_core.HasClangSupport()
output.append( 'Server has Clang support compiled in: {0}'.format(
has_clang_support ) )
if has_clang_support:
output.append( 'Clang version: ' + ycm_core.ClangVersion() )
request_data = request.json
try:
output.append(
_GetCompleterForRequestData( request_data ).DebugInfo( request_data) )
except:
pass
return _JsonResponse( '\n'.join( output ) )
# The type of the param is Bottle.HTTPError
@app.error( httplib.INTERNAL_SERVER_ERROR )
def ErrorHandler( httperror ):
return _JsonResponse( BuildExceptionResponse( httperror.exception,
httperror.traceback ) )
def _JsonResponse( data ):
response.set_header( 'Content-Type', 'application/json' )
return json.dumps( data, default = _UniversalSerialize )
def _UniversalSerialize( obj ):
serialized = obj.__dict__.copy()
serialized[ 'TYPE' ] = type( obj ).__name__
return serialized
def _GetCompleterForRequestData( request_data ):
completer_target = request_data.get( 'completer_target', None )
if completer_target == 'identifier':
return SERVER_STATE.GetGeneralCompleter().GetIdentifierCompleter()
elif completer_target == 'filetype_default' or not completer_target:
return SERVER_STATE.GetFiletypeCompleter( request_data[ 'filetypes' ] )
else:
return SERVER_STATE.GetFiletypeCompleter( [ completer_target ] )
@atexit.register
def _ServerShutdown():
if SERVER_STATE:
SERVER_STATE.Shutdown()
def _SetUserOptions( options ):
global SERVER_STATE
user_options_store.SetAll( options )
SERVER_STATE = server_state.ServerState( options )
def SetServerStateToDefaults():
global SERVER_STATE, LOGGER
LOGGER = logging.getLogger( __name__ )
user_options_store.LoadDefaults()
SERVER_STATE = server_state.ServerState( user_options_store.GetAll() )
extra_conf_store.Reset()
def Main(): def Main():
global LOGGER
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( '--host', type = str, default = 'localhost', parser.add_argument( '--host', type = str, default = 'localhost',
help = 'server hostname') help = 'server hostname')
@ -237,18 +47,31 @@ def Main():
help = 'file with user options, in JSON format' ) help = 'file with user options, in JSON format' )
args = parser.parse_args() args = parser.parse_args()
if args.options_file:
_SetUserOptions( json.load( open( args.options_file, 'r' ) ) )
numeric_level = getattr( logging, args.log.upper(), None ) numeric_level = getattr( logging, args.log.upper(), None )
if not isinstance( numeric_level, int ): if not isinstance( numeric_level, int ):
raise ValueError( 'Invalid log level: %s' % args.log ) raise ValueError( 'Invalid log level: %s' % args.log )
# Has to be called before any call to logging.getLogger()
logging.basicConfig( format = '%(asctime)s - %(levelname)s - %(message)s', logging.basicConfig( format = '%(asctime)s - %(levelname)s - %(message)s',
level = numeric_level ) level = numeric_level )
LOGGER = logging.getLogger( __name__ ) options = None
waitress.serve( app, host = args.host, port = args.port, threads = 10 ) if args.options_file:
options = json.load( open( args.options_file, 'r' ) )
user_options_store.SetAll( options )
# This ensures that ycm_core is not loaded before extra conf preload
# was run.
YcmCoreSanityCheck()
extra_conf_store.CallGlobalExtraConfYcmCorePreloadIfExists()
# This can't be a top-level import because it transitively imports ycm_core
# which we want to be imported ONLY after extra conf preload has executed.
import handlers
handlers.UpdateUserOptions( options )
waitress.serve( handlers.app,
host = args.host,
port = args.port,
threads = 10 )
if __name__ == "__main__": if __name__ == "__main__":