utils.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #!/usr/bin/env python
  2. #
  3. # Copyright (C) 2011, 2012 Strahinja Val Markovic <val@markovic.io>
  4. #
  5. # This file is part of YouCompleteMe.
  6. #
  7. # YouCompleteMe is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # YouCompleteMe is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
  19. import tempfile
  20. import os
  21. import sys
  22. import signal
  23. import functools
  24. import socket
  25. import stat
  26. from distutils.spawn import find_executable
  27. import subprocess
  28. WIN_PYTHON27_PATH = 'C:\python27\pythonw.exe'
  29. WIN_PYTHON26_PATH = 'C:\python26\pythonw.exe'
  30. def IsIdentifierChar( char ):
  31. return char.isalnum() or char == '_'
  32. def SanitizeQuery( query ):
  33. return query.strip()
  34. def ToUtf8IfNeeded( value ):
  35. if isinstance( value, unicode ):
  36. return value.encode( 'utf8' )
  37. if isinstance( value, str ):
  38. return value
  39. return str( value )
  40. def PathToTempDir():
  41. tempdir = os.path.join( tempfile.gettempdir(), 'ycm_temp' )
  42. if not os.path.exists( tempdir ):
  43. os.makedirs( tempdir )
  44. # Needed to support multiple users working on the same machine;
  45. # see issue 606.
  46. MakeFolderAccessibleToAll( tempdir )
  47. return tempdir
  48. def MakeFolderAccessibleToAll( path_to_folder ):
  49. current_stat = os.stat( path_to_folder )
  50. # readable, writable and executable by everyone
  51. flags = ( current_stat.st_mode | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH
  52. | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP )
  53. os.chmod( path_to_folder, flags )
  54. def RunningInsideVim():
  55. try:
  56. import vim # NOQA
  57. return True
  58. except ImportError:
  59. return False
  60. def GetUnusedLocalhostPort():
  61. sock = socket.socket()
  62. # This tells the OS to give us any free port in the range [1024 - 65535]
  63. sock.bind( ( '', 0 ) )
  64. port = sock.getsockname()[ 1 ]
  65. sock.close()
  66. return port
  67. def RemoveIfExists( filename ):
  68. try:
  69. os.remove( filename )
  70. except OSError:
  71. pass
  72. def Memoize( obj ):
  73. cache = obj.cache = {}
  74. @functools.wraps( obj )
  75. def memoizer( *args, **kwargs ):
  76. key = str( args ) + str( kwargs )
  77. if key not in cache:
  78. cache[ key ] = obj( *args, **kwargs )
  79. return cache[ key ]
  80. return memoizer
  81. @Memoize
  82. def PathToPythonInterpreter():
  83. if not RunningInsideVim():
  84. return sys.executable
  85. import vim # NOQA
  86. user_path_to_python = vim.eval( 'g:ycm_path_to_python_interpreter' )
  87. if user_path_to_python:
  88. return user_path_to_python
  89. # We check for 'python2' before 'python' because some OS's (I'm looking at you
  90. # Arch Linux) have made the... interesting decision to point /usr/bin/python
  91. # to python3.
  92. python_names = [ 'python2', 'python' ]
  93. if OnWindows():
  94. # On Windows, 'pythonw' doesn't pop-up a console window like running
  95. # 'python' does.
  96. python_names.insert( 0, 'pythonw' )
  97. path_to_python = PathToFirstExistingExecutable( python_names )
  98. if path_to_python:
  99. return path_to_python
  100. # On Windows, Python may not be on the PATH at all, so we check some common
  101. # install locations.
  102. if OnWindows():
  103. if os.path.exists( WIN_PYTHON27_PATH ):
  104. return WIN_PYTHON27_PATH
  105. elif os.path.exists( WIN_PYTHON26_PATH ):
  106. return WIN_PYTHON26_PATH
  107. raise RuntimeError( 'Python 2.7/2.6 not installed!' )
  108. def PathToFirstExistingExecutable( executable_name_list ):
  109. for executable_name in executable_name_list:
  110. path = find_executable( executable_name )
  111. if path:
  112. return path
  113. return None
  114. def OnWindows():
  115. return sys.platform == 'win32'
  116. # From here: http://stackoverflow.com/a/8536476/1672783
  117. def TerminateProcess( pid ):
  118. if OnWindows():
  119. import ctypes
  120. PROCESS_TERMINATE = 1
  121. handle = ctypes.windll.kernel32.OpenProcess( PROCESS_TERMINATE,
  122. False,
  123. pid )
  124. ctypes.windll.kernel32.TerminateProcess( handle, -1 )
  125. ctypes.windll.kernel32.CloseHandle( handle )
  126. else:
  127. os.kill( pid, signal.SIGTERM )
  128. def AddThirdPartyFoldersToSysPath():
  129. path_to_third_party = os.path.join(
  130. os.path.dirname( os.path.abspath( __file__ ) ),
  131. '../../third_party' )
  132. for folder in os.listdir( path_to_third_party ):
  133. sys.path.insert( 0, os.path.realpath( os.path.join( path_to_third_party,
  134. folder ) ) )
  135. def ForceSemanticCompletion( request_data ):
  136. return ( 'force_semantic' in request_data and
  137. bool( request_data[ 'force_semantic' ] ) )
  138. # A wrapper for subprocess.Popen that works around a Popen bug on Windows.
  139. def SafePopen( *args, **kwargs ):
  140. if kwargs.get( 'stdin', '' ) is None:
  141. # We need this on Windows otherwise bad things happen. See issue #637.
  142. kwargs[ 'stdin' ] = subprocess.PIPE if OnWindows() else None
  143. return subprocess.Popen( *args, **kwargs )