1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# Copyright (C) 2015 YouCompleteMe contributors.
#
# 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/>.
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import * # noqa
import os
import sys
import vim
import functools
import re
# Can't import these from setup.py because it makes nosetests go crazy.
DIR_OF_CURRENT_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) )
DIR_OF_YCMD = os.path.join( DIR_OF_CURRENT_SCRIPT, '..', '..', 'third_party',
'ycmd' )
WIN_PYTHON_PATH = os.path.join( sys.exec_prefix, 'python.exe' )
PYTHON_BINARY_REGEX = re.compile(
r'python((2(\.[67])?)|(3(\.[3-9])?))?(.exe)?$' )
def Memoize( obj ):
cache = obj.cache = {}
@functools.wraps( obj )
def memoizer( *args, **kwargs ):
key = str( args ) + str( kwargs )
if key not in cache:
cache[ key ] = obj( *args, **kwargs )
return cache[ key ]
return memoizer
@Memoize
def PathToPythonInterpreter():
from ycmd import utils
python_interpreter = vim.eval( 'g:ycm_server_python_interpreter' )
if python_interpreter:
if IsPythonVersionCorrect( python_interpreter ):
return python_interpreter
raise RuntimeError( "Path in 'g:ycm_server_python_interpreter' option "
"does not point to a valid Python 2.6+ or 3.3+." )
python_interpreter = _PathToPythonUsedDuringBuild()
if IsPythonVersionCorrect( python_interpreter ):
return python_interpreter
# On UNIX platforms, we use sys.executable as the Python interpreter path.
# We cannot use sys.executable on Windows because for unknown reasons, it
# returns the Vim executable. Instead, we use sys.exec_prefix to deduce the
# interpreter path.
python_interpreter = ( WIN_PYTHON_PATH if utils.OnWindows() else
sys.executable )
if IsPythonVersionCorrect( python_interpreter ):
return python_interpreter
# As a last resort, we search python in the PATH. We prefer Python 2 over 3
# for the sake of backwards compatibility with ycm_extra_conf.py files out
# there; few people wrote theirs to work on py3.
# So we check 'python2' before 'python' because on some distributions (Arch
# Linux for example), python refers to python3.
python_interpreter = utils.PathToFirstExistingExecutable( [ 'python2',
'python',
'python3' ] )
if IsPythonVersionCorrect( python_interpreter ):
return python_interpreter
raise RuntimeError( "Cannot find Python 2.6+ or 3.3+. You can set its path "
"using the 'g:ycm_server_python_interpreter' "
"option." )
def _PathToPythonUsedDuringBuild():
from ycmd import utils
try:
filepath = os.path.join( DIR_OF_YCMD, 'PYTHON_USED_DURING_BUILDING' )
return utils.ReadFile( filepath ).strip()
# We need to check for IOError for Python2 and OSError for Python3
except ( IOError, OSError ):
return None
def EndsWithPython( path ):
"""Check if given path ends with a python 2.6+ or 3.3+ name."""
return path and PYTHON_BINARY_REGEX.search( path ) is not None
def IsPythonVersionCorrect( path ):
"""Check if given path is the Python interpreter version 2.6+ or 3.3+."""
from ycmd import utils
if not EndsWithPython( path ):
return False
command = [ path,
'-c',
"import sys;"
"major, minor = sys.version_info[ :2 ];"
"good_python = ( major == 2 and minor >= 6 ) "
"or ( major == 3 and minor >= 3 ) or major > 3;"
# If this looks weird, remember that:
# int( True ) == 1
# int( False ) == 0
"sys.exit( not good_python )" ]
return utils.SafePopen( command ).wait() == 0
def PathToServerScript():
return os.path.join( DIR_OF_YCMD, 'ycmd' )
|