# HG changeset patch # User Pierre-Yves David # Date 2020-10-14 15:52:18 # Node ID 37c65704869d33223d1e2f750a95308914993ccc # Parent 80f32ec8653aa06337c21bd144bf57f10b0221d9 procutil: allow to specify arbitrary stdin bytes to runbgcommand For automatic clonebundles generation I need to pass arbitrary large amount of data to the process (eg: common nodes, target nodes). I am updating the `runbgcommand` to allow for this. Previously not stdin input was possible, now, one can provide raw bytes and they will be feed to the command through an unnamed temporary files. Differential Revision: https://phab.mercurial-scm.org/D9212 diff --git a/mercurial/utils/procutil.py b/mercurial/utils/procutil.py --- a/mercurial/utils/procutil.py +++ b/mercurial/utils/procutil.py @@ -635,21 +635,35 @@ if pycompat.iswindows: stderr=None, ensurestart=True, record_wait=None, + stdin_bytes=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. - p = subprocess.Popen( - tonativestr(script), - shell=shell, - env=tonativeenv(env), - close_fds=True, - creationflags=_creationflags, - stdout=stdout, - stderr=stderr, - ) - if record_wait is not None: - record_wait(p.wait) + + try: + stdin = None + if stdin_bytes is not None: + stdin = pycompat.unnamedtempfile() + stdin.write(stdin_bytes) + stdin.flush() + stdin.seek(0) + + p = subprocess.Popen( + tonativestr(script), + shell=shell, + env=tonativeenv(env), + close_fds=True, + creationflags=_creationflags, + stdin=stdin, + stdout=stdout, + stderr=stderr, + ) + if record_wait is not None: + record_wait(p.wait) + finally: + if stdin is not None: + stdin.close() else: @@ -662,6 +676,7 @@ else: stderr=None, ensurestart=True, record_wait=None, + stdin_bytes=None, ): '''Spawn a command without waiting for it to finish. @@ -722,15 +737,21 @@ else: if record_wait is None: # Start a new session os.setsid() + # connect stdin to devnull to make sure the subprocess can't + # muck up that stream for mercurial. + if stdin_bytes is None: + stdin = open(os.devnull, b'r') + else: + stdin = pycompat.unnamedtempfile() + stdin.write(stdin_bytes) + stdin.flush() + stdin.seek(0) - stdin = open(os.devnull, b'r') if stdout is None: stdout = open(os.devnull, b'w') if stderr is None: stderr = open(os.devnull, b'w') - # connect stdin to devnull to make sure the subprocess can't - # muck up that stream for mercurial. p = subprocess.Popen( cmd, shell=shell, @@ -754,5 +775,6 @@ else: finally: # mission accomplished, this child needs to exit and not # continue the hg process here. + stdin.close() if record_wait is None: os._exit(returncode)