Execute a command on the local system in a subprocess. .. note:: When Invoke itself is executed without a controlling terminal (e.g. when ``sys.stdin`` lacks a useful ``fileno``), it's not possible to present a handle on our PTY to local subprocesses. In such situat
| 1232 | |
| 1233 | |
| 1234 | class Local(Runner): |
| 1235 | """ |
| 1236 | Execute a command on the local system in a subprocess. |
| 1237 | |
| 1238 | .. note:: |
| 1239 | When Invoke itself is executed without a controlling terminal (e.g. |
| 1240 | when ``sys.stdin`` lacks a useful ``fileno``), it's not possible to |
| 1241 | present a handle on our PTY to local subprocesses. In such situations, |
| 1242 | `Local` will fallback to behaving as if ``pty=False`` (on the theory |
| 1243 | that degraded execution is better than none at all) as well as printing |
| 1244 | a warning to stderr. |
| 1245 | |
| 1246 | To disable this behavior, say ``fallback=False``. |
| 1247 | |
| 1248 | .. versionadded:: 1.0 |
| 1249 | """ |
| 1250 | |
| 1251 | def __init__(self, context: "Context") -> None: |
| 1252 | super().__init__(context) |
| 1253 | # Bookkeeping var for pty use case |
| 1254 | self.status = 0 |
| 1255 | |
| 1256 | def should_use_pty(self, pty: bool = False, fallback: bool = True) -> bool: |
| 1257 | use_pty = False |
| 1258 | if pty: |
| 1259 | use_pty = True |
| 1260 | # TODO: pass in & test in_stream, not sys.stdin |
| 1261 | if not has_fileno(sys.stdin) and fallback: |
| 1262 | if not self.warned_about_pty_fallback: |
| 1263 | err = "WARNING: stdin has no fileno; falling back to non-pty execution!\n" # noqa |
| 1264 | sys.stderr.write(err) |
| 1265 | self.warned_about_pty_fallback = True |
| 1266 | use_pty = False |
| 1267 | return use_pty |
| 1268 | |
| 1269 | def read_proc_stdout(self, num_bytes: int) -> Optional[bytes]: |
| 1270 | # Obtain useful read-some-bytes function |
| 1271 | if self.using_pty: |
| 1272 | # Need to handle spurious OSErrors on some Linux platforms. |
| 1273 | try: |
| 1274 | data = os.read(self.parent_fd, num_bytes) |
| 1275 | except OSError as e: |
| 1276 | # Only eat I/O specific OSErrors so we don't hide others |
| 1277 | stringified = str(e) |
| 1278 | io_errors = ( |
| 1279 | # The typical default |
| 1280 | "Input/output error", |
| 1281 | # Some less common platforms phrase it this way |
| 1282 | "I/O error", |
| 1283 | ) |
| 1284 | if not any(error in stringified for error in io_errors): |
| 1285 | raise |
| 1286 | # The bad OSErrors happen after all expected output has |
| 1287 | # appeared, so we return a falsey value, which triggers the |
| 1288 | # "end of output" logic in code using reader functions. |
| 1289 | data = None |
| 1290 | elif self.process and self.process.stdout: |
| 1291 | data = os.read(self.process.stdout.fileno(), num_bytes) |
no outgoing calls
no test coverage detected
searching dependent graphs…