| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 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 """A wrapper for subprocess to make calling shell commands easier.""" | 5 """A wrapper for subprocess to make calling shell commands easier.""" |
| 6 | 6 |
| 7 import logging | 7 import logging |
| 8 import os | 8 import os |
| 9 import pipes | 9 import pipes |
| 10 import select | 10 import select |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 138 args: A string or a sequence of program arguments. The program to execute is | 138 args: A string or a sequence of program arguments. The program to execute is |
| 139 the string or the first item in the args sequence. | 139 the string or the first item in the args sequence. |
| 140 cwd: If not None, the subprocess's current directory will be changed to | 140 cwd: If not None, the subprocess's current directory will be changed to |
| 141 |cwd| before it's executed. | 141 |cwd| before it's executed. |
| 142 shell: Whether to execute args as a shell command. Must be True if args | 142 shell: Whether to execute args as a shell command. Must be True if args |
| 143 is a string and False if args is a sequence. | 143 is a string and False if args is a sequence. |
| 144 | 144 |
| 145 Returns: | 145 Returns: |
| 146 The 2-tuple (exit code, output). | 146 The 2-tuple (exit code, output). |
| 147 """ | 147 """ |
| 148 status, stdout, stderr = GetCmdStatusOutputAndError( |
| 149 args, cwd=cwd, shell=shell) |
| 150 |
| 151 if stderr: |
| 152 logging.critical(stderr) |
| 153 if len(stdout) > 4096: |
| 154 logging.debug('Truncated output:') |
| 155 logging.debug(stdout[:4096]) |
| 156 return (status, stdout) |
| 157 |
| 158 def GetCmdStatusOutputAndError(args, cwd=None, shell=False): |
| 159 """Executes a subprocess and returns its exit code, output, and errors. |
| 160 |
| 161 Args: |
| 162 args: A string or a sequence of program arguments. The program to execute is |
| 163 the string or the first item in the args sequence. |
| 164 cwd: If not None, the subprocess's current directory will be changed to |
| 165 |cwd| before it's executed. |
| 166 shell: Whether to execute args as a shell command. Must be True if args |
| 167 is a string and False if args is a sequence. |
| 168 |
| 169 Returns: |
| 170 The 2-tuple (exit code, output). |
| 171 """ |
| 148 _ValidateAndLogCommand(args, cwd, shell) | 172 _ValidateAndLogCommand(args, cwd, shell) |
| 149 pipe = Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, | 173 pipe = Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
| 150 shell=shell, cwd=cwd) | 174 shell=shell, cwd=cwd) |
| 151 stdout, stderr = pipe.communicate() | 175 stdout, stderr = pipe.communicate() |
| 152 | 176 return (pipe.returncode, stdout, stderr) |
| 153 if stderr: | |
| 154 logging.critical(stderr) | |
| 155 if len(stdout) > 4096: | |
| 156 logging.debug('Truncated output:') | |
| 157 logging.debug(stdout[:4096]) | |
| 158 return (pipe.returncode, stdout) | |
| 159 | 177 |
| 160 | 178 |
| 161 class TimeoutError(Exception): | 179 class TimeoutError(Exception): |
| 162 """Module-specific timeout exception.""" | 180 """Module-specific timeout exception.""" |
| 163 | 181 |
| 164 def __init__(self, output=None): | 182 def __init__(self, output=None): |
| 165 super(TimeoutError, self).__init__() | 183 super(TimeoutError, self).__init__() |
| 166 self._output = output | 184 self._output = output |
| 167 | 185 |
| 168 @property | 186 @property |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 buffer_output += data | 281 buffer_output += data |
| 264 has_incomplete_line = buffer_output[-1] not in '\r\n' | 282 has_incomplete_line = buffer_output[-1] not in '\r\n' |
| 265 lines = buffer_output.splitlines() | 283 lines = buffer_output.splitlines() |
| 266 buffer_output = lines.pop() if has_incomplete_line else '' | 284 buffer_output = lines.pop() if has_incomplete_line else '' |
| 267 for line in lines: | 285 for line in lines: |
| 268 yield line | 286 yield line |
| 269 if buffer_output: | 287 if buffer_output: |
| 270 yield buffer_output | 288 yield buffer_output |
| 271 if check_status and process.returncode: | 289 if check_status and process.returncode: |
| 272 raise subprocess.CalledProcessError(process.returncode, cmd) | 290 raise subprocess.CalledProcessError(process.returncode, cmd) |
| OLD | NEW |