|
6 | 6 | import subprocess |
7 | 7 | import sys |
8 | 8 | from pathlib import Path |
9 | | -from typing import Sequence |
| 9 | +from typing import Callable, Sequence |
10 | 10 |
|
11 | 11 |
|
12 | 12 | class Namespace: |
@@ -88,22 +88,31 @@ def run_cmd_in_foreground(args: Sequence[str | Path], **kwargs): |
88 | 88 | old_pgrp = os.tcgetpgrp(sys.stdin.fileno()) |
89 | 89 | old_attr = termios.tcgetattr(sys.stdin.fileno()) |
90 | 90 |
|
91 | | - # generally, the child process should stop itself |
92 | | - # before exec so the parent can set its new pgid. |
93 | | - # (setting pgid has to be done before the child execs). |
94 | | - # however, Python 'guarantee' that `preexec_fn` |
95 | | - # is run before `Popen` returns. |
96 | | - # this is because `Popen` waits for the closure of |
97 | | - # the error relay pipe '`errpipe_write`', |
98 | | - # which happens at child's exec. |
99 | | - # this is also the reason the child can't stop itself |
100 | | - # in Python's `Popen`, since the `Popen` call would never |
101 | | - # terminate then. |
102 | | - # `os.kill(os.getpid(), signal.SIGSTOP)` |
| 91 | + user_preexec_fn: Callable | None = kwargs.pop("preexec_fn", None) |
| 92 | + |
| 93 | + def new_pgid(): |
| 94 | + if user_preexec_fn: |
| 95 | + user_preexec_fn() |
| 96 | + |
| 97 | + # set a new process group id |
| 98 | + os.setpgid(os.getpid(), os.getpid()) |
| 99 | + |
| 100 | + # generally, the child process should stop itself |
| 101 | + # before exec so the parent can set its new pgid. |
| 102 | + # (setting pgid has to be done before the child execs). |
| 103 | + # however, Python 'guarantee' that `preexec_fn` |
| 104 | + # is run before `Popen` returns. |
| 105 | + # this is because `Popen` waits for the closure of |
| 106 | + # the error relay pipe '`errpipe_write`', |
| 107 | + # which happens at child's exec. |
| 108 | + # this is also the reason the child can't stop itself |
| 109 | + # in Python's `Popen`, since the `Popen` call would never |
| 110 | + # terminate then. |
| 111 | + # `os.kill(os.getpid(), signal.SIGSTOP)` |
103 | 112 |
|
104 | 113 | try: |
105 | 114 | # fork the child |
106 | | - child = subprocess.Popen(args, process_group=os.getpid(), **kwargs) |
| 115 | + child = subprocess.Popen(args, preexec_fn=new_pgid, **kwargs) # noqa: PLW1509 |
107 | 116 |
|
108 | 117 | # we can't set the process group id from the parent since the child |
109 | 118 | # will already have exec'd. and we can't SIGSTOP it before exec, |
|
0 commit comments