Mercurial > public > mercurial-scm > hg
diff mercurial/utils/procutil.py @ 43862:5606e1cb4685
merge with stable
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Fri, 13 Dec 2019 09:43:43 -0800 |
parents | be8552f25cab 15a6c6783060 |
children | a89381e04c58 |
line wrap: on
line diff
--- a/mercurial/utils/procutil.py Mon Dec 09 22:24:58 2019 -0800 +++ b/mercurial/utils/procutil.py Fri Dec 13 09:43:43 2019 -0800 @@ -540,12 +540,18 @@ ) def runbgcommand( - script, env, shell=False, stdout=None, stderr=None, ensurestart=True + script, + env, + shell=False, + stdout=None, + stderr=None, + ensurestart=True, + record_wait=None, ): '''Spawn a command without waiting for it to finish.''' # we can't use close_fds *and* redirect stdin. I'm not sure that we # need to because the detached process has no console connection. - subprocess.Popen( + p = subprocess.Popen( tonativestr(script), shell=shell, env=tonativeenv(env), @@ -554,46 +560,64 @@ stdout=stdout, stderr=stderr, ) + if record_wait is not None: + record_wait(p.wait) else: def runbgcommand( - cmd, env, shell=False, stdout=None, stderr=None, ensurestart=True + cmd, + env, + shell=False, + stdout=None, + stderr=None, + ensurestart=True, + record_wait=None, ): - '''Spawn a command without waiting for it to finish.''' + '''Spawn a command without waiting for it to finish. + + + When `record_wait` is not None, the spawned process will not be fully + detached and the `record_wait` argument will be called with a the + `Subprocess.wait` function for the spawned process. This is mostly + useful for developers that need to make sure the spawned process + finished before a certain point. (eg: writing test)''' # double-fork to completely detach from the parent process # based on http://code.activestate.com/recipes/278731 - pid = os.fork() - if pid: - if not ensurestart: + if record_wait is None: + pid = os.fork() + if pid: + if not ensurestart: + return + # Parent process + (_pid, status) = os.waitpid(pid, 0) + if os.WIFEXITED(status): + returncode = os.WEXITSTATUS(status) + else: + returncode = -(os.WTERMSIG(status)) + if returncode != 0: + # The child process's return code is 0 on success, an errno + # value on failure, or 255 if we don't have a valid errno + # value. + # + # (It would be slightly nicer to return the full exception info + # over a pipe as the subprocess module does. For now it + # doesn't seem worth adding that complexity here, though.) + if returncode == 255: + returncode = errno.EINVAL + raise OSError( + returncode, + b'error running %r: %s' + % (cmd, os.strerror(returncode)), + ) return - # Parent process - (_pid, status) = os.waitpid(pid, 0) - if os.WIFEXITED(status): - returncode = os.WEXITSTATUS(status) - else: - returncode = -(os.WTERMSIG(status)) - if returncode != 0: - # The child process's return code is 0 on success, an errno - # value on failure, or 255 if we don't have a valid errno - # value. - # - # (It would be slightly nicer to return the full exception info - # over a pipe as the subprocess module does. For now it - # doesn't seem worth adding that complexity here, though.) - if returncode == 255: - returncode = errno.EINVAL - raise OSError( - returncode, - b'error running %r: %s' % (cmd, os.strerror(returncode)), - ) - return returncode = 255 try: - # Start a new session - os.setsid() + if record_wait is None: + # Start a new session + os.setsid() stdin = open(os.devnull, b'r') if stdout is None: @@ -603,7 +627,7 @@ # connect stdin to devnull to make sure the subprocess can't # muck up that stream for mercurial. - subprocess.Popen( + p = subprocess.Popen( cmd, shell=shell, env=env, @@ -612,6 +636,8 @@ stdout=stdout, stderr=stderr, ) + if record_wait is not None: + record_wait(p.wait) returncode = 0 except EnvironmentError as ex: returncode = ex.errno & 0xFF @@ -624,4 +650,5 @@ finally: # mission accomplished, this child needs to exit and not # continue the hg process here. - os._exit(returncode) + if record_wait is None: + os._exit(returncode)