D12313: procutil: delete Python 2 support code

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Wed Mar 2 23:32:01 UTC 2022


indygreg created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  This entailed deleting a function for Python 2 support and renaming the
  Python 3 function to match the exported symbol name.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D12313

AFFECTED FILES
  mercurial/utils/procutil.py

CHANGE DETAILS

diff --git a/mercurial/utils/procutil.py b/mercurial/utils/procutil.py
--- a/mercurial/utils/procutil.py
+++ b/mercurial/utils/procutil.py
@@ -80,7 +80,7 @@
 
 
 def make_line_buffered(stream):
-    if pycompat.ispy3 and not isinstance(stream, io.BufferedIOBase):
+    if not isinstance(stream, io.BufferedIOBase):
         # On Python 3, buffered streams can be expected to subclass
         # BufferedIOBase. This is definitively the case for the streams
         # initialized by the interpreter. For unbuffered streams, we don't need
@@ -121,7 +121,6 @@
 
 
 def _make_write_all(stream):
-    assert pycompat.ispy3
     if isinstance(stream, WriteAllWrapper):
         return stream
     if isinstance(stream, io.BufferedIOBase):
@@ -133,52 +132,32 @@
     return WriteAllWrapper(stream)
 
 
-if pycompat.ispy3:
-    # Python 3 implements its own I/O streams. Unlike stdio of C library,
-    # sys.stdin/stdout/stderr may be None if underlying fd is closed.
-
-    # TODO: .buffer might not exist if std streams were replaced; we'll need
-    # a silly wrapper to make a bytes stream backed by a unicode one.
+# Python 3 implements its own I/O streams. Unlike stdio of C library,
+# sys.stdin/stdout/stderr may be None if underlying fd is closed.
 
-    if sys.stdin is None:
-        stdin = BadFile()
-    else:
-        stdin = sys.stdin.buffer
-    if sys.stdout is None:
-        stdout = BadFile()
-    else:
-        stdout = _make_write_all(sys.stdout.buffer)
-    if sys.stderr is None:
-        stderr = BadFile()
-    else:
-        stderr = _make_write_all(sys.stderr.buffer)
+# TODO: .buffer might not exist if std streams were replaced; we'll need
+# a silly wrapper to make a bytes stream backed by a unicode one.
 
-    if pycompat.iswindows:
-        # Work around Windows bugs.
-        stdout = platform.winstdout(stdout)  # pytype: disable=module-attr
-        stderr = platform.winstdout(stderr)  # pytype: disable=module-attr
-    if isatty(stdout):
-        # The standard library doesn't offer line-buffered binary streams.
-        stdout = make_line_buffered(stdout)
+if sys.stdin is None:
+    stdin = BadFile()
+else:
+    stdin = sys.stdin.buffer
+if sys.stdout is None:
+    stdout = BadFile()
 else:
-    # Python 2 uses the I/O streams provided by the C library.
-    stdin = sys.stdin
-    stdout = sys.stdout
-    stderr = sys.stderr
-    if pycompat.iswindows:
-        # Work around Windows bugs.
-        stdout = platform.winstdout(stdout)  # pytype: disable=module-attr
-        stderr = platform.winstdout(stderr)  # pytype: disable=module-attr
-    if isatty(stdout):
-        if pycompat.iswindows:
-            # The Windows C runtime library doesn't support line buffering.
-            stdout = make_line_buffered(stdout)
-        else:
-            # glibc determines buffering on first write to stdout - if we
-            # replace a TTY destined stdout with a pipe destined stdout (e.g.
-            # pager), we want line buffering.
-            stdout = os.fdopen(stdout.fileno(), 'wb', 1)
+    stdout = _make_write_all(sys.stdout.buffer)
+if sys.stderr is None:
+    stderr = BadFile()
+else:
+    stderr = _make_write_all(sys.stderr.buffer)
 
+if pycompat.iswindows:
+    # Work around Windows bugs.
+    stdout = platform.winstdout(stdout)  # pytype: disable=module-attr
+    stderr = platform.winstdout(stderr)  # pytype: disable=module-attr
+if isatty(stdout):
+    # The standard library doesn't offer line-buffered binary streams.
+    stdout = make_line_buffered(stdout)
 
 findexe = platform.findexe
 _gethgcmd = platform.gethgcmd
@@ -703,7 +682,7 @@
 
 else:
 
-    def runbgcommandpy3(
+    def runbgcommand(
         cmd,
         env,
         shell=False,
@@ -786,128 +765,3 @@
             returncode = p.wait
             if record_wait is not None:
                 record_wait(returncode)
-
-    def runbgcommandpy2(
-        cmd,
-        env,
-        shell=False,
-        stdout=None,
-        stderr=None,
-        ensurestart=True,
-        record_wait=None,
-        stdin_bytes=None,
-    ):
-        """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)"""
-        if pycompat.isdarwin:
-            # avoid crash in CoreFoundation in case another thread
-            # calls gui() while we're calling fork().
-            gui()
-
-        # double-fork to completely detach from the parent process
-        # based on http://code.activestate.com/recipes/278731
-        if record_wait is None:
-            pid = os.fork()
-            if pid:
-                if not ensurestart:
-                    # Even though we're not waiting on the child process,
-                    # we still must call waitpid() on it at some point so
-                    # it's not a zombie/defunct. This is especially relevant for
-                    # chg since the parent process won't die anytime soon.
-                    # We use a thread to make the overhead tiny.
-                    def _do_wait():
-                        os.waitpid(pid, 0)
-
-                    t = threading.Thread(target=_do_wait)
-                    t.daemon = True
-                    t.start()
-                    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
-        stdin = None
-
-        try:
-            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)
-
-            if stdout is None:
-                stdout = open(os.devnull, b'w')
-            if stderr is None:
-                stderr = open(os.devnull, b'w')
-
-            p = subprocess.Popen(
-                cmd,
-                shell=shell,
-                env=env,
-                close_fds=True,
-                stdin=stdin,
-                stdout=stdout,
-                stderr=stderr,
-            )
-            if record_wait is not None:
-                record_wait(p.wait)
-            returncode = 0
-        except EnvironmentError as ex:
-            returncode = ex.errno & 0xFF
-            if returncode == 0:
-                # This shouldn't happen, but just in case make sure the
-                # return code is never 0 here.
-                returncode = 255
-        except Exception:
-            returncode = 255
-        finally:
-            # mission accomplished, this child needs to exit and not
-            # continue the hg process here.
-            if stdin is not None:
-                stdin.close()
-            if record_wait is None:
-                os._exit(returncode)
-
-    if pycompat.ispy3:
-        # This branch is more robust, because it avoids running python
-        # code (hence gc finalizers, like sshpeer.__del__, which
-        # blocks).  But we can't easily do the equivalent in py2,
-        # because of the lack of start_new_session=True flag. Given
-        # that the py2 branch should die soon, the short-lived
-        # duplication seems acceptable.
-        runbgcommand = runbgcommandpy3
-    else:
-        runbgcommand = runbgcommandpy2



To: indygreg, #hg-reviewers
Cc: mercurial-patches, mercurial-devel


More information about the Mercurial-devel mailing list