##// END OF EJS Templates
procutil: add a option to not fully detach background process...
marmoute -
r44297:15a6c678 stable
parent child Browse files
Show More
@@ -548,12 +548,18 b' if pycompat.iswindows:'
548 _creationflags = DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP
548 _creationflags = DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP
549
549
550 def runbgcommand(
550 def runbgcommand(
551 script, env, shell=False, stdout=None, stderr=None, ensurestart=True
551 script,
552 env,
553 shell=False,
554 stdout=None,
555 stderr=None,
556 ensurestart=True,
557 record_wait=None,
552 ):
558 ):
553 '''Spawn a command without waiting for it to finish.'''
559 '''Spawn a command without waiting for it to finish.'''
554 # we can't use close_fds *and* redirect stdin. I'm not sure that we
560 # we can't use close_fds *and* redirect stdin. I'm not sure that we
555 # need to because the detached process has no console connection.
561 # need to because the detached process has no console connection.
556 subprocess.Popen(
562 p = subprocess.Popen(
557 tonativestr(script),
563 tonativestr(script),
558 shell=shell,
564 shell=shell,
559 env=tonativeenv(env),
565 env=tonativeenv(env),
@@ -562,46 +568,64 b' if pycompat.iswindows:'
562 stdout=stdout,
568 stdout=stdout,
563 stderr=stderr,
569 stderr=stderr,
564 )
570 )
571 if record_wait is not None:
572 record_wait(p.wait)
565
573
566
574
567 else:
575 else:
568
576
569 def runbgcommand(
577 def runbgcommand(
570 cmd, env, shell=False, stdout=None, stderr=None, ensurestart=True
578 cmd,
579 env,
580 shell=False,
581 stdout=None,
582 stderr=None,
583 ensurestart=True,
584 record_wait=None,
571 ):
585 ):
572 '''Spawn a command without waiting for it to finish.'''
586 '''Spawn a command without waiting for it to finish.
587
588
589 When `record_wait` is not None, the spawned process will not be fully
590 detached and the `record_wait` argument will be called with a the
591 `Subprocess.wait` function for the spawned process. This is mostly
592 useful for developers that need to make sure the spawned process
593 finished before a certain point. (eg: writing test)'''
573 # double-fork to completely detach from the parent process
594 # double-fork to completely detach from the parent process
574 # based on http://code.activestate.com/recipes/278731
595 # based on http://code.activestate.com/recipes/278731
575 pid = os.fork()
596 if record_wait is None:
576 if pid:
597 pid = os.fork()
577 if not ensurestart:
598 if pid:
599 if not ensurestart:
600 return
601 # Parent process
602 (_pid, status) = os.waitpid(pid, 0)
603 if os.WIFEXITED(status):
604 returncode = os.WEXITSTATUS(status)
605 else:
606 returncode = -(os.WTERMSIG(status))
607 if returncode != 0:
608 # The child process's return code is 0 on success, an errno
609 # value on failure, or 255 if we don't have a valid errno
610 # value.
611 #
612 # (It would be slightly nicer to return the full exception info
613 # over a pipe as the subprocess module does. For now it
614 # doesn't seem worth adding that complexity here, though.)
615 if returncode == 255:
616 returncode = errno.EINVAL
617 raise OSError(
618 returncode,
619 b'error running %r: %s'
620 % (cmd, os.strerror(returncode)),
621 )
578 return
622 return
579 # Parent process
580 (_pid, status) = os.waitpid(pid, 0)
581 if os.WIFEXITED(status):
582 returncode = os.WEXITSTATUS(status)
583 else:
584 returncode = -(os.WTERMSIG(status))
585 if returncode != 0:
586 # The child process's return code is 0 on success, an errno
587 # value on failure, or 255 if we don't have a valid errno
588 # value.
589 #
590 # (It would be slightly nicer to return the full exception info
591 # over a pipe as the subprocess module does. For now it
592 # doesn't seem worth adding that complexity here, though.)
593 if returncode == 255:
594 returncode = errno.EINVAL
595 raise OSError(
596 returncode,
597 b'error running %r: %s' % (cmd, os.strerror(returncode)),
598 )
599 return
600
623
601 returncode = 255
624 returncode = 255
602 try:
625 try:
603 # Start a new session
626 if record_wait is None:
604 os.setsid()
627 # Start a new session
628 os.setsid()
605
629
606 stdin = open(os.devnull, b'r')
630 stdin = open(os.devnull, b'r')
607 if stdout is None:
631 if stdout is None:
@@ -611,7 +635,7 b' else:'
611
635
612 # connect stdin to devnull to make sure the subprocess can't
636 # connect stdin to devnull to make sure the subprocess can't
613 # muck up that stream for mercurial.
637 # muck up that stream for mercurial.
614 subprocess.Popen(
638 p = subprocess.Popen(
615 cmd,
639 cmd,
616 shell=shell,
640 shell=shell,
617 env=env,
641 env=env,
@@ -620,6 +644,8 b' else:'
620 stdout=stdout,
644 stdout=stdout,
621 stderr=stderr,
645 stderr=stderr,
622 )
646 )
647 if record_wait is not None:
648 record_wait(p.wait)
623 returncode = 0
649 returncode = 0
624 except EnvironmentError as ex:
650 except EnvironmentError as ex:
625 returncode = ex.errno & 0xFF
651 returncode = ex.errno & 0xFF
@@ -632,4 +658,5 b' else:'
632 finally:
658 finally:
633 # mission accomplished, this child needs to exit and not
659 # mission accomplished, this child needs to exit and not
634 # continue the hg process here.
660 # continue the hg process here.
635 os._exit(returncode)
661 if record_wait is None:
662 os._exit(returncode)
General Comments 0
You need to be logged in to leave comments. Login now