From f986bf19db973852b87f24ddcfd81b835a5a3cc3 Mon Sep 17 00:00:00 2001 From: Val Markovic Date: Fri, 19 Feb 2016 11:02:58 -0800 Subject: [PATCH] Updating to latest ycmd --- autoload/youcompleteme.vim | 7 ++++--- install.py | 5 +++++ python/test_requirements.txt | 2 ++ python/ycm/client/base_request.py | 21 +++++++++++++------- python/ycm/client/command_request.py | 6 +++--- python/ycm/client/completion_request.py | 18 ++++++++--------- python/ycm/client/omni_completion_request.py | 12 +++++------ python/ycm/vimsupport.py | 21 +++++++++++--------- python/ycm/youcompleteme.py | 5 +++-- run_tests.py | 11 ++++++++++ third_party/ycmd | 2 +- 11 files changed, 70 insertions(+), 40 deletions(-) diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim index 9d0fe102..1b15530a 100644 --- a/autoload/youcompleteme.vim +++ b/autoload/youcompleteme.vim @@ -139,12 +139,13 @@ import subprocess script_folder = vim.eval( 's:script_folder_path' ) sys.path.insert( 0, os.path.join( script_folder, '../python' ) ) sys.path.insert( 0, os.path.join( script_folder, '../third_party/ycmd' ) ) -from ycmd import utils -utils.AddNearestThirdPartyFoldersToSysPath( script_folder ) +from ycmd import server_utils +server_utils.AddNearestThirdPartyFoldersToSysPath( script_folder ) # We need to import ycmd's third_party folders as well since we import and # use ycmd code in the client. -utils.AddNearestThirdPartyFoldersToSysPath( utils.__file__ ) +server_utils.AddNearestThirdPartyFoldersToSysPath( server_utils.__file__ ) +from ycmd import utils from ycm import base base.LoadJsonDefaultsIntoVim() from ycmd import user_options_store diff --git a/install.py b/install.py index e5063e2f..a4cf292d 100755 --- a/install.py +++ b/install.py @@ -6,6 +6,11 @@ import sys import os.path as p import glob +major, minor = sys.version_info[ 0 : 2 ] +if major != 2 or minor < 6: + sys.exit( 'The build script requires Python version >= 2.6 and < 3.0; ' + 'your version of Python is ' + sys.version ) + DIR_OF_THIS_SCRIPT = p.dirname( p.abspath( __file__ ) ) DIR_OF_OLD_LIBS = p.join( DIR_OF_THIS_SCRIPT, 'python' ) diff --git a/python/test_requirements.txt b/python/test_requirements.txt index 7e53ca53..b67c0139 100644 --- a/python/test_requirements.txt +++ b/python/test_requirements.txt @@ -2,3 +2,5 @@ flake8>=2.0 mock>=1.0.1 nose>=1.3.0 PyHamcrest>=1.8.0 +# This needs to be kept in sync with submodule checkout in third_party/ycmd/third_party +future==0.15.2 diff --git a/python/ycm/client/base_request.py b/python/ycm/client/base_request.py index 7cd27793..83b4159b 100644 --- a/python/ycm/client/base_request.py +++ b/python/ycm/client/base_request.py @@ -17,13 +17,14 @@ import requests import urlparse +import json from base64 import b64decode, b64encode from retries import retries from requests_futures.sessions import FuturesSession from ycm.unsafe_thread_pool_executor import UnsafeThreadPoolExecutor from ycm import vimsupport -from ycmd.utils import ToUtf8Json -from ycmd.hmac_utils import CreateRequestHmac, CreateHmac, SecureStringsEqual +from ycmd.utils import ToBytes +from ycmd.hmac_utils import CreateRequestHmac, CreateHmac, SecureBytesEqual from ycmd.responses import ServerError, UnknownExtraConf _HEADERS = {'content-type': 'application/json'} @@ -89,7 +90,7 @@ class BaseRequest( object ): def SendRequest( data, handler, method, timeout ): request_uri = _BuildUri( handler ) if method == 'POST': - sent_data = ToUtf8Json( data ) + sent_data = _ToUtf8Json( data ) return BaseRequest.session.post( request_uri, data = sent_data, @@ -107,7 +108,7 @@ class BaseRequest( object ): def DelayedSendRequest( data, handler, method ): request_uri = _BuildUri( handler ) if method == 'POST': - sent_data = ToUtf8Json( data ) + sent_data = _ToUtf8Json( data ) return requests.post( request_uri, data = sent_data, @@ -182,13 +183,18 @@ def HandleServerException( exception ): vimsupport.PostVimMessage( serialized_exception ) +def _ToUtf8Json( data ): + return ToBytes( json.dumps( data ) if data else None ) + + def _ValidateResponseObject( response ): - hmac = CreateHmac( response.content, BaseRequest.hmac_secret ) - if not SecureStringsEqual( hmac, - b64decode( response.headers[ _HMAC_HEADER ] ) ): + our_hmac = CreateHmac( response.content, BaseRequest.hmac_secret ) + their_hmac = ToBytes( b64decode( response.headers[ _HMAC_HEADER ] ) ) + if not SecureBytesEqual( our_hmac, their_hmac ): raise RuntimeError( 'Received invalid HMAC for response!' ) return True + def _BuildUri( handler ): return urlparse.urljoin( BaseRequest.server_location, handler ) @@ -216,6 +222,7 @@ def _CheckServerIsHealthyWithCache(): except: return False + def MakeServerException( data ): if data[ 'exception' ][ 'TYPE' ] == UnknownExtraConf.__name__: return UnknownExtraConf( data[ 'exception' ][ 'extra_conf_file' ] ) diff --git a/python/ycm/client/command_request.py b/python/ycm/client/command_request.py index 405e4f47..8b7c12cb 100644 --- a/python/ycm/client/command_request.py +++ b/python/ycm/client/command_request.py @@ -18,7 +18,7 @@ import vim from ycm.client.base_request import BaseRequest, BuildRequestData, ServerError from ycm import vimsupport -from ycmd.utils import ToUtf8IfNeeded +from ycmd.utils import ToUnicode def _EnsureBackwardsCompatibility( arguments ): @@ -123,9 +123,9 @@ def SendCommandRequest( arguments, completer ): def _BuildQfListItem( goto_data_item ): qf_item = {} if 'filepath' in goto_data_item: - qf_item[ 'filename' ] = ToUtf8IfNeeded( goto_data_item[ 'filepath' ] ) + qf_item[ 'filename' ] = ToUnicode( goto_data_item[ 'filepath' ] ) if 'description' in goto_data_item: - qf_item[ 'text' ] = ToUtf8IfNeeded( goto_data_item[ 'description' ] ) + qf_item[ 'text' ] = ToUnicode( goto_data_item[ 'description' ] ) if 'line_num' in goto_data_item: qf_item[ 'lnum' ] = goto_data_item[ 'line_num' ] if 'column_num' in goto_data_item: diff --git a/python/ycm/client/completion_request.py b/python/ycm/client/completion_request.py index 0ecec63d..e162b8e5 100644 --- a/python/ycm/client/completion_request.py +++ b/python/ycm/client/completion_request.py @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License # along with YouCompleteMe. If not, see . -from ycmd.utils import ToUtf8IfNeeded +from ycmd.utils import ToBytes, ToUnicode from ycm.client.base_request import ( BaseRequest, JsonFromFuture, HandleServerException, MakeServerException ) @@ -69,22 +69,22 @@ def ConvertCompletionDataToVimData( completion_data ): if ( 'extra_data' in completion_data and 'doc_string' in completion_data[ 'extra_data' ] ): - doc_string = ToUtf8IfNeeded( - completion_data[ 'extra_data' ][ 'doc_string' ] ) + doc_string = ToBytes( completion_data[ 'extra_data' ][ 'doc_string' ] ) else: doc_string = "" if 'insertion_text' in completion_data: - vim_data[ 'word' ] = ToUtf8IfNeeded( completion_data[ 'insertion_text' ] ) + vim_data[ 'word' ] = ToBytes( completion_data[ 'insertion_text' ] ) if 'menu_text' in completion_data: - vim_data[ 'abbr' ] = ToUtf8IfNeeded( completion_data[ 'menu_text' ] ) + vim_data[ 'abbr' ] = ToBytes( completion_data[ 'menu_text' ] ) if 'extra_menu_info' in completion_data: - vim_data[ 'menu' ] = ToUtf8IfNeeded( completion_data[ 'extra_menu_info' ] ) + vim_data[ 'menu' ] = ToBytes( completion_data[ 'extra_menu_info' ] ) if 'kind' in completion_data: - vim_data[ 'kind' ] = ToUtf8IfNeeded( - completion_data[ 'kind' ] )[ 0 ].lower() + kind = ToUnicode( completion_data[ 'kind' ] ) + if kind: + vim_data[ 'kind' ] = ToBytes( kind[ 0 ].lower() ) if 'detailed_info' in completion_data: - vim_data[ 'info' ] = ToUtf8IfNeeded( completion_data[ 'detailed_info' ] ) + vim_data[ 'info' ] = ToBytes( completion_data[ 'detailed_info' ] ) if doc_string: vim_data[ 'info' ] += '\n' + doc_string elif doc_string: diff --git a/python/ycm/client/omni_completion_request.py b/python/ycm/client/omni_completion_request.py index 25e3008e..48cb112f 100644 --- a/python/ycm/client/omni_completion_request.py +++ b/python/ycm/client/omni_completion_request.py @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License # along with YouCompleteMe. If not, see . -from ycmd.utils import ToUtf8IfNeeded +from ycmd.utils import ToBytes from ycm.client.completion_request import CompletionRequest @@ -46,15 +46,15 @@ def ConvertVimDataToCompletionData( vim_data ): completion_data = {} if 'word' in vim_data: - completion_data[ 'insertion_text' ] = ToUtf8IfNeeded( vim_data[ 'word' ] ) + completion_data[ 'insertion_text' ] = ToBytes( vim_data[ 'word' ] ) if 'abbr' in vim_data: - completion_data[ 'menu_text' ] = ToUtf8IfNeeded( vim_data[ 'abbr' ] ) + completion_data[ 'menu_text' ] = ToBytes( vim_data[ 'abbr' ] ) if 'menu' in vim_data: - completion_data[ 'extra_menu_info' ] = ToUtf8IfNeeded( vim_data[ 'menu' ] ) + completion_data[ 'extra_menu_info' ] = ToBytes( vim_data[ 'menu' ] ) if 'kind' in vim_data: - completion_data[ 'kind' ] = [ ToUtf8IfNeeded( vim_data[ 'kind' ] ) ] + completion_data[ 'kind' ] = [ ToBytes( vim_data[ 'kind' ] ) ] if 'info' in vim_data: - completion_data[ 'detailed_info' ] = ToUtf8IfNeeded( vim_data[ 'info' ] ) + completion_data[ 'detailed_info' ] = ToBytes( vim_data[ 'info' ] ) return completion_data diff --git a/python/ycm/vimsupport.py b/python/ycm/vimsupport.py index 015312b2..0ed090f9 100644 --- a/python/ycm/vimsupport.py +++ b/python/ycm/vimsupport.py @@ -21,7 +21,7 @@ import tempfile import json import re from collections import defaultdict -from ycmd.utils import ToUtf8IfNeeded +from ycmd.utils import ToBytes, ToUnicode from ycmd import user_options_store BUFFER_COMMAND_MAP = { 'same-buffer' : 'edit', @@ -277,7 +277,7 @@ def ConvertDiagnosticsToQfList( diagnostics ): 'bufnr' : GetBufferNumberForFilename( location[ 'filepath' ] ), 'lnum' : line_num, 'col' : location[ 'column_num' ], - 'text' : ToUtf8IfNeeded( text ), + 'text' : ToBytes( text ), 'type' : diagnostic[ 'kind' ][ 0 ], 'valid' : 1 } @@ -409,7 +409,7 @@ def NumLinesInBuffer( buffer_object ): # or type command to continue" prompt when editing a new C-family file. def PostVimMessage( message ): vim.command( "redraw | echohl WarningMsg | echom '{0}' | echohl None" - .format( EscapeForVim( str( message ) ) ) ) + .format( EscapeForVim( ToUnicode( message ) ) ) ) # Unlike PostVimMesasge, this supports messages with newlines in them because it @@ -417,7 +417,7 @@ def PostVimMessage( message ): # appear in Vim's message log. def PostMultiLineNotice( message ): vim.command( "echohl WarningMsg | echo '{0}' | echohl None" - .format( EscapeForVim( str( message ) ) ) ) + .format( EscapeForVim( ToUnicode( message ) ) ) ) def PresentDialog( message, choices, default_choice_index = 0 ): @@ -439,8 +439,10 @@ def PresentDialog( message, choices, default_choice_index = 0 ): PresentDialog("Is this a nice example?", ["Yes", "No", "May&be"]) Is this a nice example? [Y]es, (N)o, May(b)e:""" - to_eval = "confirm('{0}', '{1}', {2})".format( EscapeForVim( message ), - EscapeForVim( "\n" .join( choices ) ), default_choice_index + 1 ) + to_eval = "confirm('{0}', '{1}', {2})".format( + EscapeForVim( ToUnicode( message ) ), + EscapeForVim( ToUnicode( "\n" .join( choices ) ) ), + default_choice_index + 1 ) return int( vim.eval( to_eval ) ) - 1 @@ -453,16 +455,17 @@ def Confirm( message ): def EchoText( text, log_as_message = True ): def EchoLine( text ): command = 'echom' if log_as_message else 'echo' - vim.command( "{0} '{1}'".format( command, EscapeForVim( text ) ) ) + vim.command( "{0} '{1}'".format( command, + EscapeForVim( text ) ) ) - for line in str( text ).split( '\n' ): + for line in ToUnicode( text ).split( '\n' ): EchoLine( line ) # Echos text but truncates it so that it all fits on one line def EchoTextVimWidth( text ): vim_width = GetIntValue( '&columns' ) - truncated_text = ToUtf8IfNeeded( text )[ : int( vim_width * 0.9 ) ] + truncated_text = ToUnicode( text )[ : int( vim_width * 0.9 ) ] truncated_text.replace( '\n', ' ' ) old_ruler = GetIntValue( '&ruler' ) diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py index b3e74138..cf3f4f17 100644 --- a/python/ycm/youcompleteme.py +++ b/python/ycm/youcompleteme.py @@ -117,7 +117,7 @@ class YouCompleteMe( object ): '--idle_suicide_seconds={0}'.format( SERVER_IDLE_SUICIDE_SECONDS )] - filename_format = os.path.join( utils.PathToTempDir(), + filename_format = os.path.join( utils.PathToCreatedTempDir(), 'server_{port}_{std}.log' ) self._server_stdout = filename_format.format( port = server_port, @@ -131,12 +131,13 @@ class YouCompleteMe( object ): args.append( '--keep_logfiles' ) self._server_popen = utils.SafePopen( args, stdin_windows = PIPE, - stdout = PIPE, stderr = PIPE) + stdout = PIPE, stderr = PIPE ) BaseRequest.server_location = 'http://127.0.0.1:' + str( server_port ) BaseRequest.hmac_secret = hmac_secret self._NotifyUserIfServerCrashed() + def IsServerAlive( self ): returncode = self._server_popen.poll() # When the process hasn't finished yet, poll() returns None. diff --git a/run_tests.py b/run_tests.py index f2427921..705b803e 100755 --- a/run_tests.py +++ b/run_tests.py @@ -13,6 +13,17 @@ python_path = [] for folder in os.listdir( DIR_OF_THIRD_PARTY ): python_path.append( p.abspath( p.join( DIR_OF_THIRD_PARTY, folder ) ) ) for folder in os.listdir( DIR_OF_YCMD_THIRD_PARTY ): + # We skip python-future because it needs to be inserted in sys.path AFTER + # the standard library imports but we can't do that with PYTHONPATH because + # the std lib paths are always appended to PYTHONPATH. We do it correctly in + # prod in ycmd/utils.py because we have access to the right sys.path. + # So for dev, we rely on python-future being installed correctly with + # pip install -r test_requirements.txt + # + # Pip knows how to install this correctly so that it doesn't matter where in + # sys.path the path is. + if folder == 'python-future': + continue python_path.append( p.abspath( p.join( DIR_OF_YCMD_THIRD_PARTY, folder ) ) ) if os.environ.get( 'PYTHONPATH' ): python_path.append( os.environ[ 'PYTHONPATH' ] ) diff --git a/third_party/ycmd b/third_party/ycmd index d0932eb1..3ed1634a 160000 --- a/third_party/ycmd +++ b/third_party/ycmd @@ -1 +1 @@ -Subproject commit d0932eb1895644e982d3a1daf210c09ca479a620 +Subproject commit 3ed1634afd7bfef872abde4e91bd012fbb08a9d8