Robot Framework Integrated Development Environment (RIDE)
Process.py
Go to the documentation of this file.
1 # Copyright 2010 Orbitz WorldWide
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 # Modified by NSN
16 # Copyright 2010-2012 Nokia Solutions and Networks
17 # Copyright 2013-2015 Nokia Networks
18 # Copyright 2016- Robot Framework Foundation
19 #
20 # Licensed under the Apache License, Version 2.0 (the "License");
21 # you may not use this file except in compliance with the License.
22 # You may obtain a copy of the License at
23 #
24 # http://www.apache.org/licenses/LICENSE-2.0
25 #
26 # Unless required by applicable law or agreed to in writing, software
27 # distributed under the License is distributed on an "AS IS" BASIS,
28 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 # See the License for the specific language governing permissions and
30 # limitations under the License.
31 
32 import os
33 import signal
34 import socket
35 import subprocess
36 import sys
37 import threading
38 
39 from queue import Empty, Queue
40 from robotide.context import IS_WINDOWS
41 
42 OUTPUT_ENCODING = sys.getfilesystemencoding()
43 
44 
45 class Process():
46 
47  def __init__(self, cwd):
48  self._process_process = None
49  self._error_stream_error_stream = None
50  self._output_stream_output_stream = None
51  self._cwd_cwd = cwd
52  self._port_port = None
53  self._sock_sock = None
54  self._kill_called_kill_called = False
55 
56  def run_command(self, command):
57  # We need to supply stdin for subprocess, because other ways in python
58  # subprocess will try using sys.stdin which causes an error in windows
59  # print("DEBUG: enter run_command %s dir %s" % (command, self._cwd))
60  subprocess_args = dict(bufsize=0,
61  stdout=subprocess.PIPE,
62  stderr=subprocess.PIPE,
63  stdin=subprocess.PIPE,
64  cwd=self._cwd_cwd)
65  if IS_WINDOWS:
66  startupinfo = subprocess.STARTUPINFO()
67  try:
68  import _subprocess
69  startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
70  except ImportError:
71  startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
72  subprocess_args['startupinfo'] = startupinfo
73  subprocess_args['env'] = dict(os.environ, PYTHONIOENCODING='UTF-8')
74  else:
75  subprocess_args['preexec_fn'] = os.setsid
76  subprocess_args['shell'] = True
77  self._process_process = subprocess.Popen(command, **subprocess_args)
78  self._process_process.stdin.close()
79  self._output_stream_output_stream = StreamReaderThread(self._process_process.stdout)
80  self._error_stream_error_stream = StreamReaderThread(self._process_process.stderr)
81  self._output_stream_output_stream.run()
82  self._error_stream_error_stream.run()
83  self._kill_called_kill_called = False
84 
85  def set_port(self, port):
86  self._port_port = port
87 
88  def get_output(self):
89  return self._output_stream_output_stream.pop()
90 
91  def get_errors(self):
92  return self._error_stream_error_stream.pop()
93 
94  def get_returncode(self):
95  return self._process_process.returncode
96 
97  def is_alive(self):
98  return self._process_process.poll() is None
99 
100  def wait(self):
101  self._process_process.wait()
102 
103  def kill(self, force=False, killer_pid=None):
104  if not self._process_process:
105  return
106  if force:
107  self._process_process.kill()
108  self.resumeresume() # Send so that RF is not blocked
109  if IS_WINDOWS and not self._kill_called_kill_called and self._port_port is not None:
110  self._signal_kill_with_listener_server_signal_kill_with_listener_server()
111  self._kill_called_kill_called = True
112  else:
113  self._kill_kill(killer_pid or self._process_process.pid)
114 
116  self._send_socket_send_socket('kill')
117 
118  def _send_socket(self, data):
119  if self._port_port is None:
120  return # Silent failure..
121  sock = None
122  if IS_WINDOWS:
123  host = '127.0.0.1'
124  else:
125  host = 'localhost'
126  try:
127  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
128  sock.connect((host, self._port_port))
129  sock.send(bytes(data, OUTPUT_ENCODING))
130  # except Exception:
131  # print(r"DEBUG: Exception at send socket %s" % data)
132  finally:
133  sock.close()
134 
135  def pause(self):
136  self._send_socket_send_socket('pause')
137 
138  def pause_on_failure(self, pause):
139  if pause:
140  self._send_socket_send_socket('pause_on_failure')
141  else:
142  self._send_socket_send_socket('do_not_pause_on_failure')
143 
144  def resume(self):
145  self._send_socket_send_socket('resume')
146 
147  def step_next(self):
148  self._send_socket_send_socket('step_next')
149 
150  def step_over(self):
151  self._send_socket_send_socket('step_over')
152 
153  @staticmethod
154  def _kill(pid):
155  if pid:
156  try:
157  os.kill(pid, signal.SIGINT)
158  except OSError:
159  pass
160 
161 
163 
164  def __init__(self, stream):
165  self._queue_queue = Queue()
166  self._thread_thread = None
167  self._stream_stream = stream
168 
169  def run(self):
170  self._thread_thread = threading.Thread(target=self._enqueue_output_enqueue_output,
171  args=(self._stream_stream,))
172  self._thread_thread.daemon = True
173  self._thread_thread.start()
174 
175  def _enqueue_output(self, out):
176  for line in iter(out.readline, b''):
177  self._queue_queue.put(line)
178 
179  def pop(self):
180  result = b''
181  my_queue_rng = range(self._queue_queue.qsize())
182  for _ in my_queue_rng:
183  try:
184  result += self._queue_queue.get_nowait()
185  except Empty:
186  pass
187  return result
def kill(self, force=False, killer_pid=None)
Definition: Process.py:103
def run(*tests, **options)
Programmatic entry point for running tests.
Definition: run.py:546