mercurial/utils/procutil.py
changeset 43076 2372284d9457
parent 43019 2cc453284d5c
child 43077 687b865b95ad
--- a/mercurial/utils/procutil.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/utils/procutil.py	Sun Oct 06 09:45:02 2019 -0400
@@ -34,12 +34,14 @@
 stdin = pycompat.stdin
 stdout = pycompat.stdout
 
+
 def isatty(fp):
     try:
         return fp.isatty()
     except AttributeError:
         return False
 
+
 # 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 (or unbuffered, on Windows)
@@ -52,6 +54,7 @@
 
 if pycompat.iswindows:
     from .. import windows as platform
+
     stdout = platform.winstdout(stdout)
 else:
     from .. import posix as platform
@@ -83,6 +86,7 @@
 
 closefds = pycompat.isposix
 
+
 def explainexit(code):
     """return a message describing a subprocess status
     (codes from kill are negative - not os.system/wait encoding)"""
@@ -90,6 +94,7 @@
         return _("exited with status %d") % code
     return _("killed by signal %d") % -code
 
+
 class _pfile(object):
     """File-like wrapper for a stream opened by subprocess.Popen()"""
 
@@ -114,6 +119,7 @@
     def __exit__(self, exc_type, exc_value, exc_tb):
         self.close()
 
+
 def popen(cmd, mode='rb', bufsize=-1):
     if mode == 'rb':
         return _popenreader(cmd, bufsize)
@@ -121,52 +127,77 @@
         return _popenwriter(cmd, bufsize)
     raise error.ProgrammingError('unsupported mode: %r' % mode)
 
+
 def _popenreader(cmd, bufsize):
-    p = subprocess.Popen(tonativestr(quotecommand(cmd)),
-                         shell=True, bufsize=bufsize,
-                         close_fds=closefds,
-                         stdout=subprocess.PIPE)
+    p = subprocess.Popen(
+        tonativestr(quotecommand(cmd)),
+        shell=True,
+        bufsize=bufsize,
+        close_fds=closefds,
+        stdout=subprocess.PIPE,
+    )
     return _pfile(p, p.stdout)
 
+
 def _popenwriter(cmd, bufsize):
-    p = subprocess.Popen(tonativestr(quotecommand(cmd)),
-                         shell=True, bufsize=bufsize,
-                         close_fds=closefds,
-                         stdin=subprocess.PIPE)
+    p = subprocess.Popen(
+        tonativestr(quotecommand(cmd)),
+        shell=True,
+        bufsize=bufsize,
+        close_fds=closefds,
+        stdin=subprocess.PIPE,
+    )
     return _pfile(p, p.stdin)
 
+
 def popen2(cmd, env=None):
     # Setting bufsize to -1 lets the system decide the buffer size.
     # The default for bufsize is 0, meaning unbuffered. This leads to
     # poor performance on Mac OS X: http://bugs.python.org/issue4194
-    p = subprocess.Popen(tonativestr(cmd),
-                         shell=True, bufsize=-1,
-                         close_fds=closefds,
-                         stdin=subprocess.PIPE, stdout=subprocess.PIPE,
-                         env=tonativeenv(env))
+    p = subprocess.Popen(
+        tonativestr(cmd),
+        shell=True,
+        bufsize=-1,
+        close_fds=closefds,
+        stdin=subprocess.PIPE,
+        stdout=subprocess.PIPE,
+        env=tonativeenv(env),
+    )
     return p.stdin, p.stdout
 
+
 def popen3(cmd, env=None):
     stdin, stdout, stderr, p = popen4(cmd, env)
     return stdin, stdout, stderr
 
+
 def popen4(cmd, env=None, bufsize=-1):
-    p = subprocess.Popen(tonativestr(cmd),
-                         shell=True, bufsize=bufsize,
-                         close_fds=closefds,
-                         stdin=subprocess.PIPE, stdout=subprocess.PIPE,
-                         stderr=subprocess.PIPE,
-                         env=tonativeenv(env))
+    p = subprocess.Popen(
+        tonativestr(cmd),
+        shell=True,
+        bufsize=bufsize,
+        close_fds=closefds,
+        stdin=subprocess.PIPE,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        env=tonativeenv(env),
+    )
     return p.stdin, p.stdout, p.stderr, p
 
+
 def pipefilter(s, cmd):
     '''filter string S through command CMD, returning its output'''
-    p = subprocess.Popen(tonativestr(cmd),
-                         shell=True, close_fds=closefds,
-                         stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+    p = subprocess.Popen(
+        tonativestr(cmd),
+        shell=True,
+        close_fds=closefds,
+        stdin=subprocess.PIPE,
+        stdout=subprocess.PIPE,
+    )
     pout, perr = p.communicate(s)
     return pout
 
+
 def tempfilter(s, cmd):
     '''filter string S through a pair of temporary files with CMD.
     CMD is used as a template to create the real command to be run,
@@ -186,8 +217,9 @@
         if pycompat.sysplatform == 'OpenVMS' and code & 1:
             code = 0
         if code:
-            raise error.Abort(_("command '%s' failed: %s") %
-                              (cmd, explainexit(code)))
+            raise error.Abort(
+                _("command '%s' failed: %s") % (cmd, explainexit(code))
+            )
         with open(outname, 'rb') as fp:
             return fp.read()
     finally:
@@ -202,30 +234,37 @@
         except OSError:
             pass
 
+
 _filtertable = {
     'tempfile:': tempfilter,
     'pipe:': pipefilter,
 }
 
+
 def filter(s, cmd):
     "filter a string through a command that transforms its input to its output"
     for name, fn in _filtertable.iteritems():
         if cmd.startswith(name):
-            return fn(s, cmd[len(name):].lstrip())
+            return fn(s, cmd[len(name) :].lstrip())
     return pipefilter(s, cmd)
 
+
 def mainfrozen():
     """return True if we are a frozen executable.
 
     The code supports py2exe (most common, Windows only) and tools/freeze
     (portable, not much used).
     """
-    return (pycompat.safehasattr(sys, "frozen") or # new py2exe
-            pycompat.safehasattr(sys, "importers") or # old py2exe
-            imp.is_frozen(r"__main__")) # tools/freeze
+    return (
+        pycompat.safehasattr(sys, "frozen")
+        or pycompat.safehasattr(sys, "importers")  # new py2exe
+        or imp.is_frozen(r"__main__")  # old py2exe
+    )  # tools/freeze
+
 
 _hgexecutable = None
 
+
 def hgexecutable():
     """return location of the 'hg' executable.
 
@@ -242,32 +281,43 @@
                 _sethgexecutable(encoding.environ['EXECUTABLEPATH'])
             else:
                 _sethgexecutable(pycompat.sysexecutable)
-        elif (not pycompat.iswindows and os.path.basename(
-            pycompat.fsencode(getattr(mainmod, '__file__', ''))) == 'hg'):
+        elif (
+            not pycompat.iswindows
+            and os.path.basename(
+                pycompat.fsencode(getattr(mainmod, '__file__', ''))
+            )
+            == 'hg'
+        ):
             _sethgexecutable(pycompat.fsencode(mainmod.__file__))
         else:
-            _sethgexecutable(findexe('hg') or
-                             os.path.basename(pycompat.sysargv[0]))
+            _sethgexecutable(
+                findexe('hg') or os.path.basename(pycompat.sysargv[0])
+            )
     return _hgexecutable
 
+
 def _sethgexecutable(path):
     """set location of the 'hg' executable"""
     global _hgexecutable
     _hgexecutable = path
 
+
 def _testfileno(f, stdf):
     fileno = getattr(f, 'fileno', None)
     try:
         return fileno and fileno() == stdf.fileno()
     except io.UnsupportedOperation:
-        return False # fileno() raised UnsupportedOperation
+        return False  # fileno() raised UnsupportedOperation
+
 
 def isstdin(f):
     return _testfileno(f, sys.__stdin__)
 
+
 def isstdout(f):
     return _testfileno(f, sys.__stdout__)
 
+
 def protectstdio(uin, uout):
     """Duplicate streams and redirect original if (uin, uout) are stdio
 
@@ -292,6 +342,7 @@
         fout = os.fdopen(newfd, r'wb')
     return fin, fout
 
+
 def restorestdio(uin, uout, fin, fout):
     """Restore (uin, uout) streams from possibly duplicated (fin, fout)"""
     uout.flush()
@@ -300,8 +351,10 @@
             os.dup2(f.fileno(), uif.fileno())
             f.close()
 
+
 def shellenviron(environ=None):
     """return environ with optional override, useful for shelling out"""
+
     def py2shell(val):
         'convert python object into string that is useful to shell'
         if val is None or val is False:
@@ -309,28 +362,34 @@
         if val is True:
             return '1'
         return pycompat.bytestr(val)
+
     env = dict(encoding.environ)
     if environ:
         env.update((k, py2shell(v)) for k, v in environ.iteritems())
     env['HG'] = hgexecutable()
     return env
 
+
 if pycompat.iswindows:
+
     def shelltonative(cmd, env):
         return platform.shelltocmdexe(cmd, shellenviron(env))
 
     tonativestr = encoding.strfromlocal
 else:
+
     def shelltonative(cmd, env):
         return cmd
 
     tonativestr = pycompat.identity
 
+
 def tonativeenv(env):
     '''convert the environment from bytes to strings suitable for Popen(), etc.
     '''
     return pycompat.rapply(tonativestr, env)
 
+
 def system(cmd, environ=None, cwd=None, out=None):
     '''enhanced shell command execution.
     run with environment maybe modified, maybe in different dir.
@@ -344,17 +403,23 @@
     cmd = quotecommand(cmd)
     env = shellenviron(environ)
     if out is None or isstdout(out):
-        rc = subprocess.call(tonativestr(cmd),
-                             shell=True, close_fds=closefds,
-                             env=tonativeenv(env),
-                             cwd=pycompat.rapply(tonativestr, cwd))
+        rc = subprocess.call(
+            tonativestr(cmd),
+            shell=True,
+            close_fds=closefds,
+            env=tonativeenv(env),
+            cwd=pycompat.rapply(tonativestr, cwd),
+        )
     else:
-        proc = subprocess.Popen(tonativestr(cmd),
-                                shell=True, close_fds=closefds,
-                                env=tonativeenv(env),
-                                cwd=pycompat.rapply(tonativestr, cwd),
-                                stdout=subprocess.PIPE,
-                                stderr=subprocess.STDOUT)
+        proc = subprocess.Popen(
+            tonativestr(cmd),
+            shell=True,
+            close_fds=closefds,
+            env=tonativeenv(env),
+            cwd=pycompat.rapply(tonativestr, cwd),
+            stdout=subprocess.PIPE,
+            stderr=subprocess.STDOUT,
+        )
         for line in iter(proc.stdout.readline, ''):
             out.write(line)
         proc.wait()
@@ -363,6 +428,7 @@
         rc = 0
     return rc
 
+
 def gui():
     '''Are we running in a GUI?'''
     if pycompat.isdarwin:
@@ -378,6 +444,7 @@
     else:
         return pycompat.iswindows or encoding.environ.get("DISPLAY")
 
+
 def hgcmd():
     """Return the command used to execute current hg
 
@@ -393,6 +460,7 @@
             return [pycompat.sysexecutable]
     return _gethgcmd()
 
+
 def rundetached(args, condfn):
     """Execute the argument list in a detached process.
 
@@ -410,8 +478,10 @@
     # running process on success. Instead we listen for SIGCHLD telling
     # us our child process terminated.
     terminated = set()
+
     def handler(signum, frame):
         terminated.add(os.wait())
+
     prevhandler = None
     SIGCHLD = getattr(signal, 'SIGCHLD', None)
     if SIGCHLD is not None:
@@ -419,8 +489,7 @@
     try:
         pid = spawndetached(args)
         while not condfn():
-            if ((pid in terminated or not testpid(pid))
-                and not condfn()):
+            if (pid in terminated or not testpid(pid)) and not condfn():
                 return -1
             time.sleep(0.1)
         return pid
@@ -428,6 +497,7 @@
         if prevhandler is not None:
             signal.signal(signal.SIGCHLD, prevhandler)
 
+
 @contextlib.contextmanager
 def uninterruptible(warn):
     """Inhibit SIGINT handling on a region of code.
@@ -461,6 +531,7 @@
         if shouldbail:
             raise KeyboardInterrupt
 
+
 if pycompat.iswindows:
     # no fork on Windows, but we can create a detached process
     # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx
@@ -472,18 +543,27 @@
     _creationflags = DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP
 
     def runbgcommand(
-      script, env, shell=False, stdout=None, stderr=None, ensurestart=True):
+        script, env, shell=False, stdout=None, stderr=None, ensurestart=True
+    ):
         '''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(
             tonativestr(script),
-            shell=shell, env=tonativeenv(env), close_fds=True,
-            creationflags=_creationflags, stdout=stdout,
-            stderr=stderr)
+            shell=shell,
+            env=tonativeenv(env),
+            close_fds=True,
+            creationflags=_creationflags,
+            stdout=stdout,
+            stderr=stderr,
+        )
+
+
 else:
+
     def runbgcommand(
-      cmd, env, shell=False, stdout=None, stderr=None, ensurestart=True):
+        cmd, env, shell=False, stdout=None, stderr=None, ensurestart=True
+    ):
         '''Spawn a command without waiting for it to finish.'''
         # double-fork to completely detach from the parent process
         # based on http://code.activestate.com/recipes/278731
@@ -496,7 +576,7 @@
             if os.WIFEXITED(status):
                 returncode = os.WEXITSTATUS(status)
             else:
-                returncode = -os.WTERMSIG(status)
+                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
@@ -507,8 +587,10 @@
                 # doesn't seem worth adding that complexity here, though.)
                 if returncode == 255:
                     returncode = errno.EINVAL
-                raise OSError(returncode, 'error running %r: %s' %
-                              (cmd, os.strerror(returncode)))
+                raise OSError(
+                    returncode,
+                    'error running %r: %s' % (cmd, os.strerror(returncode)),
+                )
             return
 
         returncode = 255
@@ -525,11 +607,17 @@
             # connect stdin to devnull to make sure the subprocess can't
             # muck up that stream for mercurial.
             subprocess.Popen(
-                cmd, shell=shell, env=env, close_fds=True,
-                stdin=stdin, stdout=stdout, stderr=stderr)
+                cmd,
+                shell=shell,
+                env=env,
+                close_fds=True,
+                stdin=stdin,
+                stdout=stdout,
+                stderr=stderr,
+            )
             returncode = 0
         except EnvironmentError as ex:
-            returncode = (ex.errno & 0xff)
+            returncode = ex.errno & 0xFF
             if returncode == 0:
                 # This shouldn't happen, but just in case make sure the
                 # return code is never 0 here.