Mercurial > public > mercurial-scm > hg
comparison mercurial/utils/procutil.py @ 40497:3fbfbc8c9f82
remotefilelog: transplant runbgcommand to procutil
While cleaning up the deprecated runshellcommand I noticed a
near-clone of this in logtoprocess, so I'm standardizing on what
appears to be the newer one by moving it to procutil.
Differential Revision: https://phab.mercurial-scm.org/D4938
author | Augie Fackler <augie@google.com> |
---|---|
date | Wed, 03 Oct 2018 14:01:04 -0400 |
parents | a9f56e4501c1 |
children | 8fab95aa5280 |
comparison
equal
deleted
inserted
replaced
40496:60eb35b0c11c | 40497:3fbfbc8c9f82 |
---|---|
8 # GNU General Public License version 2 or any later version. | 8 # GNU General Public License version 2 or any later version. |
9 | 9 |
10 from __future__ import absolute_import | 10 from __future__ import absolute_import |
11 | 11 |
12 import contextlib | 12 import contextlib |
13 import errno | |
13 import imp | 14 import imp |
14 import io | 15 import io |
15 import os | 16 import os |
16 import signal | 17 import signal |
17 import subprocess | 18 import subprocess |
465 finally: | 466 finally: |
466 if oldsiginthandler: | 467 if oldsiginthandler: |
467 signal.signal(signal.SIGINT, oldsiginthandler[0]) | 468 signal.signal(signal.SIGINT, oldsiginthandler[0]) |
468 if shouldbail: | 469 if shouldbail: |
469 raise KeyboardInterrupt | 470 raise KeyboardInterrupt |
471 | |
472 if pycompat.iswindows: | |
473 # no fork on Windows, but we can create a detached process | |
474 # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx | |
475 # No stdlib constant exists for this value | |
476 DETACHED_PROCESS = 0x00000008 | |
477 _creationflags = DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP | |
478 | |
479 def runbgcommand(script, env, shell=False, stdout=None, stderr=None): | |
480 '''Spawn a command without waiting for it to finish.''' | |
481 # we can't use close_fds *and* redirect stdin. I'm not sure that we | |
482 # need to because the detached process has no console connection. | |
483 subprocess.Popen( | |
484 script, shell=shell, env=env, close_fds=True, | |
485 creationflags=_creationflags, stdout=stdout, stderr=stderr) | |
486 else: | |
487 def runbgcommand(cmd, env, shell=False, stdout=None, stderr=None): | |
488 '''Spawn a command without waiting for it to finish.''' | |
489 # double-fork to completely detach from the parent process | |
490 # based on http://code.activestate.com/recipes/278731 | |
491 pid = os.fork() | |
492 if pid: | |
493 # Parent process | |
494 (_pid, status) = os.waitpid(pid, 0) | |
495 if os.WIFEXITED(status): | |
496 returncode = os.WEXITSTATUS(status) | |
497 else: | |
498 returncode = -os.WTERMSIG(status) | |
499 if returncode != 0: | |
500 # The child process's return code is 0 on success, an errno | |
501 # value on failure, or 255 if we don't have a valid errno | |
502 # value. | |
503 # | |
504 # (It would be slightly nicer to return the full exception info | |
505 # over a pipe as the subprocess module does. For now it | |
506 # doesn't seem worth adding that complexity here, though.) | |
507 if returncode == 255: | |
508 returncode = errno.EINVAL | |
509 raise OSError(returncode, 'error running %r: %s' % | |
510 (cmd, os.strerror(returncode))) | |
511 return | |
512 | |
513 returncode = 255 | |
514 try: | |
515 # Start a new session | |
516 os.setsid() | |
517 | |
518 stdin = open(os.devnull, 'r') | |
519 if stdout is None: | |
520 stdout = open(os.devnull, 'w') | |
521 if stderr is None: | |
522 stderr = open(os.devnull, 'w') | |
523 | |
524 # connect stdin to devnull to make sure the subprocess can't | |
525 # muck up that stream for mercurial. | |
526 subprocess.Popen( | |
527 cmd, shell=shell, env=env, close_fds=True, | |
528 stdin=stdin, stdout=stdout, stderr=stderr) | |
529 returncode = 0 | |
530 except EnvironmentError as ex: | |
531 returncode = (ex.errno & 0xff) | |
532 if returncode == 0: | |
533 # This shouldn't happen, but just in case make sure the | |
534 # return code is never 0 here. | |
535 returncode = 255 | |
536 except Exception: | |
537 returncode = 255 | |
538 finally: | |
539 # mission accomplished, this child needs to exit and not | |
540 # continue the hg process here. | |
541 os._exit(returncode) |