doa.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import cPickle as pickle
  2. import marshal
  3. import os
  4. import socket
  5. import subprocess
  6. import sys
  7. import tempfile
  8. import threading
  9. class PythonFileRunner(object):
  10. """A class for running python project files"""
  11. def __init__(self, pycore, file_, args=None, stdin=None,
  12. stdout=None, analyze_data=None):
  13. self.pycore = pycore
  14. self.file = file_
  15. self.analyze_data = analyze_data
  16. self.observers = []
  17. self.args = args
  18. self.stdin = stdin
  19. self.stdout = stdout
  20. def run(self):
  21. """Execute the process"""
  22. env = dict(os.environ)
  23. file_path = self.file.real_path
  24. path_folders = self.pycore.get_source_folders() + \
  25. self.pycore.get_python_path_folders()
  26. env['PYTHONPATH'] = os.pathsep.join(folder.real_path
  27. for folder in path_folders)
  28. runmod_path = self.pycore.find_module('rope.base.oi.runmod').real_path
  29. self.receiver = None
  30. self._init_data_receiving()
  31. send_info = '-'
  32. if self.receiver:
  33. send_info = self.receiver.get_send_info()
  34. args = [sys.executable, runmod_path, send_info,
  35. self.pycore.project.address, self.file.real_path]
  36. if self.analyze_data is None:
  37. del args[1:4]
  38. if self.args is not None:
  39. args.extend(self.args)
  40. self.process = subprocess.Popen(
  41. executable=sys.executable, args=args, env=env,
  42. cwd=os.path.split(file_path)[0], stdin=self.stdin,
  43. stdout=self.stdout, stderr=self.stdout, close_fds=os.name != 'nt')
  44. def _init_data_receiving(self):
  45. if self.analyze_data is None:
  46. return
  47. # Disabling FIFO data transfer due to blocking when running
  48. # unittests in the GUI.
  49. # XXX: Handle FIFO data transfer for `rope.ui.testview`
  50. if True or os.name == 'nt':
  51. self.receiver = _SocketReceiver()
  52. else:
  53. self.receiver = _FIFOReceiver()
  54. self.receiving_thread = threading.Thread(target=self._receive_information)
  55. self.receiving_thread.setDaemon(True)
  56. self.receiving_thread.start()
  57. def _receive_information(self):
  58. #temp = open('/dev/shm/info', 'w')
  59. for data in self.receiver.receive_data():
  60. self.analyze_data(data)
  61. #temp.write(str(data) + '\n')
  62. #temp.close()
  63. for observer in self.observers:
  64. observer()
  65. def wait_process(self):
  66. """Wait for the process to finish"""
  67. self.process.wait()
  68. if self.analyze_data:
  69. self.receiving_thread.join()
  70. def kill_process(self):
  71. """Stop the process"""
  72. if self.process.poll() is not None:
  73. return
  74. try:
  75. if hasattr(self.process, 'terminate'):
  76. self.process.terminate()
  77. elif os.name != 'nt':
  78. os.kill(self.process.pid, 9)
  79. else:
  80. import ctypes
  81. handle = int(self.process._handle)
  82. ctypes.windll.kernel32.TerminateProcess(handle, -1)
  83. except OSError:
  84. pass
  85. def add_finishing_observer(self, observer):
  86. """Notify this observer when execution finishes"""
  87. self.observers.append(observer)
  88. class _MessageReceiver(object):
  89. def receive_data(self):
  90. pass
  91. def get_send_info(self):
  92. pass
  93. class _SocketReceiver(_MessageReceiver):
  94. def __init__(self):
  95. self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  96. self.data_port = 3037
  97. while self.data_port < 4000:
  98. try:
  99. self.server_socket.bind(('', self.data_port))
  100. break
  101. except socket.error, e:
  102. self.data_port += 1
  103. self.server_socket.listen(1)
  104. def get_send_info(self):
  105. return str(self.data_port)
  106. def receive_data(self):
  107. conn, addr = self.server_socket.accept()
  108. self.server_socket.close()
  109. my_file = conn.makefile('r')
  110. while True:
  111. try:
  112. yield pickle.load(my_file)
  113. except EOFError:
  114. break
  115. my_file.close()
  116. conn.close()
  117. class _FIFOReceiver(_MessageReceiver):
  118. def __init__(self):
  119. # XXX: this is insecure and might cause race conditions
  120. self.file_name = self._get_file_name()
  121. os.mkfifo(self.file_name)
  122. def _get_file_name(self):
  123. prefix = tempfile.gettempdir() + '/__rope_'
  124. i = 0
  125. while os.path.exists(prefix + str(i).rjust(4, '0')):
  126. i += 1
  127. return prefix + str(i).rjust(4, '0')
  128. def get_send_info(self):
  129. return self.file_name
  130. def receive_data(self):
  131. my_file = open(self.file_name, 'rb')
  132. while True:
  133. try:
  134. yield marshal.load(my_file)
  135. except EOFError:
  136. break
  137. my_file.close()
  138. os.remove(self.file_name)