Run a GPG command using os.posix_spawn. os.posix_spawn skips pthread_atfork handlers, avoiding the indefinite hang that fork()-based approaches suffer under gevent+uWSGI. select.select() and time.sleep() are gevent-patched so reads and the waitpid poll yield to the hub coopera
(cmd, input_data=None, timeout=30)
| 618 | |
| 619 | |
| 620 | def _gpg_run(cmd, input_data=None, timeout=30): |
| 621 | """ |
| 622 | Run a GPG command using os.posix_spawn. |
| 623 | |
| 624 | os.posix_spawn skips pthread_atfork handlers, avoiding the indefinite hang |
| 625 | that fork()-based approaches suffer under gevent+uWSGI. select.select() |
| 626 | and time.sleep() are gevent-patched so reads and the waitpid poll yield to |
| 627 | the hub cooperatively. |
| 628 | |
| 629 | Returns (returncode, stdout_bytes, stderr_bytes). |
| 630 | """ |
| 631 | import select as _select |
| 632 | import signal as _signal |
| 633 | import time as _time |
| 634 | |
| 635 | stdin_r, stdin_w = os.pipe() |
| 636 | stdout_r, stdout_w = os.pipe() |
| 637 | stderr_r, stderr_w = os.pipe() |
| 638 | |
| 639 | try: |
| 640 | executable = shutil.which(cmd[0]) or cmd[0] |
| 641 | pid = os.posix_spawn( |
| 642 | executable, cmd, os.environ, |
| 643 | file_actions=[ |
| 644 | (os.POSIX_SPAWN_DUP2, stdin_r, 0), |
| 645 | (os.POSIX_SPAWN_DUP2, stdout_w, 1), |
| 646 | (os.POSIX_SPAWN_DUP2, stderr_w, 2), |
| 647 | (os.POSIX_SPAWN_CLOSE, stdin_r), |
| 648 | (os.POSIX_SPAWN_CLOSE, stdin_w), |
| 649 | (os.POSIX_SPAWN_CLOSE, stdout_w), |
| 650 | (os.POSIX_SPAWN_CLOSE, stderr_w), |
| 651 | (os.POSIX_SPAWN_CLOSE, stdout_r), |
| 652 | (os.POSIX_SPAWN_CLOSE, stderr_r), |
| 653 | ], |
| 654 | ) |
| 655 | except Exception: |
| 656 | for fd in (stdin_r, stdin_w, stdout_r, stdout_w, stderr_r, stderr_w): |
| 657 | try: |
| 658 | os.close(fd) |
| 659 | except OSError: |
| 660 | pass |
| 661 | raise |
| 662 | |
| 663 | for fd in (stdin_r, stdout_w, stderr_w): |
| 664 | os.close(fd) |
| 665 | |
| 666 | try: |
| 667 | if input_data: |
| 668 | os.write(stdin_w, input_data) |
| 669 | finally: |
| 670 | os.close(stdin_w) |
| 671 | |
| 672 | out, err = [], [] |
| 673 | done = set() |
| 674 | deadline = _time.monotonic() + timeout |
| 675 | try: |
| 676 | while len(done) < 2: |
| 677 | remaining = deadline - _time.monotonic() |
no test coverage detected