| OLD | NEW |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import subprocess | 5 import subprocess |
| 6 import threading | 6 import threading |
| 7 | 7 |
| 8 from devtoolslib import http_server |
| 8 from devtoolslib.shell import Shell | 9 from devtoolslib.shell import Shell |
| 9 from devtoolslib import http_server | 10 from devtoolslib.utils import overrides |
| 10 | 11 |
| 11 | 12 |
| 12 class LinuxShell(Shell): | 13 class LinuxShell(Shell): |
| 13 """Wrapper around Mojo shell running on Linux. | 14 """Wrapper around Mojo shell running on Linux. |
| 14 | 15 |
| 15 Args: | 16 Args: |
| 16 executable_path: path to the shell binary | 17 executable_path: path to the shell binary |
| 17 command_prefix: optional list of arguments to prepend to the shell command, | 18 command_prefix: optional list of arguments to prepend to the shell command, |
| 18 allowing e.g. to run the shell under debugger. | 19 allowing e.g. to run the shell under debugger. |
| 19 """ | 20 """ |
| 20 | 21 |
| 21 def __init__(self, executable_path, command_prefix=None): | 22 def __init__(self, executable_path, command_prefix=None): |
| 22 self.executable_path = executable_path | 23 self.executable_path = executable_path |
| 23 self.command_prefix = command_prefix if command_prefix else [] | 24 self.command_prefix = command_prefix if command_prefix else [] |
| 24 | 25 |
| 26 @overrides(Shell) |
| 25 def ServeLocalDirectory(self, local_dir_path, port=0): | 27 def ServeLocalDirectory(self, local_dir_path, port=0): |
| 26 """Serves the content of the local (host) directory, making it available to | |
| 27 the shell under the url returned by the function. | |
| 28 | |
| 29 The server will run on a separate thread until the program terminates. The | |
| 30 call returns immediately. | |
| 31 | |
| 32 Args: | |
| 33 local_dir_path: path to the directory to be served | |
| 34 port: port at which the server will be available to the shell | |
| 35 | |
| 36 Returns: | |
| 37 The url that the shell can use to access the content of |local_dir_path|. | |
| 38 """ | |
| 39 mappings = [('', local_dir_path)] | 28 mappings = [('', local_dir_path)] |
| 40 return 'http://%s:%d/' % http_server.start_http_server(mappings, port) | 29 return 'http://%s:%d/' % http_server.start_http_server(mappings, port) |
| 41 | 30 |
| 31 @overrides(Shell) |
| 42 def ServeLocalDirectories(self, mappings, port=0): | 32 def ServeLocalDirectories(self, mappings, port=0): |
| 43 """Serves the content of the local (host) directories, making it available | |
| 44 to the shell under the url returned by the function. | |
| 45 | |
| 46 The server will run on a separate thread until the program terminates. The | |
| 47 call returns immediately. | |
| 48 | |
| 49 Args: | |
| 50 mappings: List of tuples (prefix, local_base_path) mapping URLs that start | |
| 51 with |prefix| to local directory at |local_base_path|. The prefixes | |
| 52 should skip the leading slash. The first matching prefix will be used | |
| 53 each time. | |
| 54 port: port at which the server will be available to the shell | |
| 55 | |
| 56 Returns: | |
| 57 The url that the shell can use to access the content of |local_dir_path|. | |
| 58 """ | |
| 59 return 'http://%s:%d/' % http_server.start_http_server(mappings, port) | 33 return 'http://%s:%d/' % http_server.start_http_server(mappings, port) |
| 60 | 34 |
| 35 @overrides(Shell) |
| 61 def ForwardHostPortToShell(self, host_port): | 36 def ForwardHostPortToShell(self, host_port): |
| 62 """Forwards a port on the host machine to the same port wherever the shell | |
| 63 is running. | |
| 64 | |
| 65 This is a no-op if the shell is running locally. | |
| 66 """ | |
| 67 pass | 37 pass |
| 68 | 38 |
| 39 @overrides(Shell) |
| 69 def Run(self, arguments): | 40 def Run(self, arguments): |
| 70 """Runs the shell with given arguments until shell exits, passing the stdout | |
| 71 mingled with stderr produced by the shell onto the stdout. | |
| 72 | |
| 73 Returns: | |
| 74 Exit code retured by the shell or None if the exit code cannot be | |
| 75 retrieved. | |
| 76 """ | |
| 77 command = self.command_prefix + [self.executable_path] + arguments | 41 command = self.command_prefix + [self.executable_path] + arguments |
| 78 return subprocess.call(command, stderr=subprocess.STDOUT) | 42 return subprocess.call(command, stderr=subprocess.STDOUT) |
| 79 | 43 |
| 44 @overrides(Shell) |
| 80 def RunAndGetOutput(self, arguments, timeout=None): | 45 def RunAndGetOutput(self, arguments, timeout=None): |
| 81 """Runs the shell with given arguments until shell exits and returns the | |
| 82 output. | |
| 83 | |
| 84 Args: | |
| 85 arguments: list of arguments for the shell | |
| 86 timeout: maximum running time in seconds, after which the shell will be | |
| 87 terminated | |
| 88 | |
| 89 Returns: | |
| 90 A tuple of (return_code, output, did_time_out). |return_code| is the exit | |
| 91 code returned by the shell or None if the exit code cannot be retrieved. | |
| 92 |output| is the stdout mingled with the stderr produced by the shell. | |
| 93 |did_time_out| is True iff the shell was terminated because it exceeded | |
| 94 the |timeout| and False otherwise. | |
| 95 """ | |
| 96 command = self.command_prefix + [self.executable_path] + arguments | 46 command = self.command_prefix + [self.executable_path] + arguments |
| 97 p = subprocess.Popen(command, stdout=subprocess.PIPE, | 47 p = subprocess.Popen(command, stdout=subprocess.PIPE, |
| 98 stderr=subprocess.STDOUT) | 48 stderr=subprocess.STDOUT) |
| 99 | 49 |
| 100 class Results: | 50 class Results: |
| 101 """Workaround for Python scoping rules that prevent assigning to variables | 51 """Workaround for Python scoping rules that prevent assigning to variables |
| 102 from the outer scope. | 52 from the outer scope. |
| 103 """ | 53 """ |
| 104 output = None | 54 output = None |
| 105 | 55 |
| 106 def do_run(): | 56 def do_run(): |
| 107 (Results.output, _) = p.communicate() | 57 (Results.output, _) = p.communicate() |
| 108 | 58 |
| 109 run_thread = threading.Thread(target=do_run) | 59 run_thread = threading.Thread(target=do_run) |
| 110 run_thread.start() | 60 run_thread.start() |
| 111 run_thread.join(timeout) | 61 run_thread.join(timeout) |
| 112 | 62 |
| 113 if run_thread.is_alive(): | 63 if run_thread.is_alive(): |
| 114 p.terminate() | 64 p.terminate() |
| 115 return p.returncode, Results.output, True | 65 return p.returncode, Results.output, True |
| 116 return p.returncode, Results.output, False | 66 return p.returncode, Results.output, False |
| OLD | NEW |