Patchwork [2,of,2] py3: convert arguments, cwd and env to native strings when spawning subprocess

login
register
mail settings
Submitter Matt Harbison
Date Sept. 23, 2018, 5:18 a.m.
Message ID <422a159f22ec9dda9518.1537679933@Envy>
Download mbox | patch
Permalink /patch/34925/
State New
Headers show

Comments

Matt Harbison - Sept. 23, 2018, 5:18 a.m.
# HG changeset patch
# User Matt Harbison <matt_harbison@yahoo.com>
# Date 1537678024 14400
#      Sun Sep 23 00:47:04 2018 -0400
# Node ID 422a159f22ec9dda95181c0933a2848ab8a64ba6
# Parent  10b1e61357ac546e70e590cc79889c0889e7bc22
py3: convert arguments, cwd and env to native strings when spawning subprocess

This keeps Windows happy.

Patch

diff --git a/hgext/convert/common.py b/hgext/convert/common.py
--- a/hgext/convert/common.py
+++ b/hgext/convert/common.py
@@ -402,7 +402,8 @@  class commandline(object):
 
     def _run(self, cmd, *args, **kwargs):
         def popen(cmdline):
-            p = subprocess.Popen(cmdline, shell=True, bufsize=-1,
+            p = subprocess.Popen(pycompat.rapply(procutil.tonativestr, cmdline),
+                                 shell=True, bufsize=-1,
                                  close_fds=procutil.closefds,
                                  stdout=subprocess.PIPE)
             return p
diff --git a/hgext/convert/gnuarch.py b/hgext/convert/gnuarch.py
--- a/hgext/convert/gnuarch.py
+++ b/hgext/convert/gnuarch.py
@@ -17,6 +17,7 @@  from mercurial.i18n import _
 from mercurial import (
     encoding,
     error,
+    pycompat,
 )
 from mercurial.utils import (
     dateutil,
@@ -201,7 +202,7 @@  class gnuarch_source(common.converter_so
         cmdline += ['>', os.devnull, '2>', os.devnull]
         cmdline = procutil.quotecommand(' '.join(cmdline))
         self.ui.debug(cmdline, '\n')
-        return os.system(cmdline)
+        return os.system(pycompat.rapply(procutil.tonativestr, cmdline))
 
     def _update(self, rev):
         self.ui.debug('applying revision %s...\n' % rev)
diff --git a/hgext/factotum.py b/hgext/factotum.py
--- a/hgext/factotum.py
+++ b/hgext/factotum.py
@@ -49,6 +49,9 @@  from __future__ import absolute_import
 
 import os
 from mercurial.i18n import _
+from mercurial.utils import (
+    procutil,
+)
 from mercurial import (
     error,
     httpconnection,
@@ -83,7 +86,7 @@  def auth_getkey(self, params):
     if 'user=' not in params:
         params = '%s user?' % params
     params = '%s !password?' % params
-    os.system("%s -g '%s'" % (_executable, params))
+    os.system(procutil.tonativestr("%s -g '%s'" % (_executable, params)))
 
 def auth_getuserpasswd(self, getkey, params):
     params = 'proto=pass %s' % params
diff --git a/hgext/fix.py b/hgext/fix.py
--- a/hgext/fix.py
+++ b/hgext/fix.py
@@ -58,6 +58,10 @@  from mercurial.i18n import _
 from mercurial.node import nullrev
 from mercurial.node import wdirrev
 
+from mercurial.utils import (
+    procutil,
+)
+
 from mercurial import (
     cmdutil,
     context,
@@ -448,9 +452,9 @@  def fixfile(ui, opts, fixers, fixctx, pa
                 continue
             ui.debug('subprocess: %s\n' % (command,))
             proc = subprocess.Popen(
-                command,
+                pycompat.rapply(procutil.tonativestr, command),
                 shell=True,
-                cwd='/',
+                cwd=procutil.tonativestr(b'/'),
                 stdin=subprocess.PIPE,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE)
diff --git a/hgext/fsmonitor/pywatchman/__init__.py b/hgext/fsmonitor/pywatchman/__init__.py
--- a/hgext/fsmonitor/pywatchman/__init__.py
+++ b/hgext/fsmonitor/pywatchman/__init__.py
@@ -48,6 +48,14 @@  try:
 except ImportError:
     from . import pybser as bser
 
+from mercurial.utils import (
+    procutil,
+)
+
+from mercurial import (
+    pycompat,
+)
+
 from . import (
     capabilities,
     compat,
@@ -580,7 +588,8 @@  class CLIProcessTransport(Transport):
             '--no-pretty',
             '-j',
         ]
-        self.proc = subprocess.Popen(args,
+        self.proc = subprocess.Popen(pycompat.rapply(procutil.tonativestr,
+                                                     args),
                                      stdin=subprocess.PIPE,
                                      stdout=subprocess.PIPE)
         return self.proc
@@ -822,7 +831,8 @@  class client(object):
                 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
                 args['startupinfo'] = startupinfo
 
-            p = subprocess.Popen(cmd, **args)
+            p = subprocess.Popen(pycompat.rapply(procutil.tonativestr, cmd),
+                                 **args)
 
         except OSError as e:
             raise WatchmanError('"watchman" executable not in PATH (%s)' % e)
diff --git a/hgext/infinitepush/__init__.py b/hgext/infinitepush/__init__.py
--- a/hgext/infinitepush/__init__.py
+++ b/hgext/infinitepush/__init__.py
@@ -1182,5 +1182,6 @@  def _asyncsavemetadata(root, nodes):
         cmdline = [util.hgexecutable(), 'debugfillinfinitepushmetadata',
                    '-R', root] + nodesargs
         # Process will run in background. We don't care about the return code
-        subprocess.Popen(cmdline, close_fds=True, shell=False,
+        subprocess.Popen(pycompat.rapply(procutil.tonativestr, cmdline),
+                         close_fds=True, shell=False,
                          stdin=devnull, stdout=devnull, stderr=devnull)
diff --git a/hgext/infinitepush/store.py b/hgext/infinitepush/store.py
--- a/hgext/infinitepush/store.py
+++ b/hgext/infinitepush/store.py
@@ -111,7 +111,8 @@  class externalbundlestore(abstractbundle
 
     def _call_binary(self, args):
         p = subprocess.Popen(
-            args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+            pycompat.rapply(procutil.tonativestr, args),
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
             close_fds=True)
         stdout, stderr = p.communicate()
         returncode = p.returncode
diff --git a/hgext/logtoprocess.py b/hgext/logtoprocess.py
--- a/hgext/logtoprocess.py
+++ b/hgext/logtoprocess.py
@@ -44,6 +44,10 @@  from mercurial import (
     pycompat,
 )
 
+from mercurial.utils import (
+    procutil,
+)
+
 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
 # be specifying the version(s) of Mercurial they are tested with, or
@@ -62,7 +66,8 @@  def uisetup(ui):
             # 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(
-                script, shell=True, env=env, close_fds=True,
+                pycompat.rapply(procutil.tonativestr, script),
+                shell=True, env=procutil.tonativeenv(env), close_fds=True,
                 creationflags=_creationflags)
     else:
         def runshellcommand(script, env):
@@ -82,7 +87,9 @@  def uisetup(ui):
                 # connect stdin to devnull to make sure the subprocess can't
                 # muck up that stream for mercurial.
                 subprocess.Popen(
-                    script, shell=True, stdin=open(os.devnull, 'r'), env=env,
+                    pycompat.rapply(procutil.tonativestr, script),
+                    shell=True, stdin=open(os.devnull, 'r'),
+                    env=procutil.tonativeenv(env),
                     close_fds=True, **newsession)
             finally:
                 # mission accomplished, this child needs to exit and not
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -3074,7 +3074,8 @@  def debugwireproto(ui, repo, path=None, 
             '-R', repo.root,
             'debugserve', '--sshstdio',
         ]
-        proc = subprocess.Popen(args, stdin=subprocess.PIPE,
+        proc = subprocess.Popen(pycompat.rapply(procutil.tonativestr, args),
+                                stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                 bufsize=0)
 
diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -1339,9 +1339,11 @@  def extdatasource(repo, source):
         if spec.startswith("shell:"):
             # external commands should be run relative to the repo root
             cmd = spec[6:]
-            proc = subprocess.Popen(cmd, shell=True, bufsize=-1,
+            proc = subprocess.Popen(pycompat.rapply(procutil.tonativestr, cmd),
+                                    shell=True, bufsize=-1,
                                     close_fds=procutil.closefds,
-                                    stdout=subprocess.PIPE, cwd=repo.root)
+                                    stdout=subprocess.PIPE,
+                                    cwd=procutil.tonativestr(repo.root))
             src = proc.stdout
         else:
             # treat as a URL or file
diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -951,9 +951,11 @@  class svnsubrepo(abstractsubrepo):
             env['LANG'] = lc_all
             del env['LC_ALL']
         env['LC_MESSAGES'] = 'C'
-        p = subprocess.Popen(cmd, bufsize=-1, close_fds=procutil.closefds,
+        p = subprocess.Popen(pycompat.rapply(procutil.tonativestr, cmd),
+                             bufsize=-1, close_fds=procutil.closefds,
                              stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-                              universal_newlines=True, env=env, **extrakw)
+                             universal_newlines=True,
+                             env=procutil.tonativeenv(env), **extrakw)
         stdout, stderr = p.communicate()
         stderr = stderr.strip()
         if not failok:
@@ -1268,8 +1270,12 @@  class gitsubrepo(abstractsubrepo):
             # insert the argument in the front,
             # the end of git diff arguments is used for paths
             commands.insert(1, '--color')
-        p = subprocess.Popen([self._gitexecutable] + commands, bufsize=-1,
-                             cwd=cwd, env=env, close_fds=procutil.closefds,
+        p = subprocess.Popen(pycompat.rapply(procutil.tonativestr,
+                                             [self._gitexecutable] + commands),
+                             bufsize=-1,
+                             cwd=procutil.tonativestr(cwd),
+                             env=procutil.tonativeenv(env),
+                             close_fds=procutil.closefds,
                              stdout=subprocess.PIPE, stderr=errpipe)
         if stream:
             return p.stdout, None
diff --git a/mercurial/utils/procutil.py b/mercurial/utils/procutil.py
--- a/mercurial/utils/procutil.py
+++ b/mercurial/utils/procutil.py
@@ -120,13 +120,15 @@  def popen(cmd, mode='rb', bufsize=-1):
     raise error.ProgrammingError('unsupported mode: %r' % mode)
 
 def _popenreader(cmd, bufsize):
-    p = subprocess.Popen(quotecommand(cmd), shell=True, bufsize=bufsize,
+    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(quotecommand(cmd), shell=True, bufsize=bufsize,
+    p = subprocess.Popen(tonativestr(quotecommand(cmd)),
+                         shell=True, bufsize=bufsize,
                          close_fds=closefds,
                          stdin=subprocess.PIPE)
     return _pfile(p, p.stdin)
@@ -135,10 +137,11 @@  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(cmd, shell=True, bufsize=-1,
+    p = subprocess.Popen(pycompat.rapply(tonativestr, cmd),
+                         shell=True, bufsize=-1,
                          close_fds=closefds,
                          stdin=subprocess.PIPE, stdout=subprocess.PIPE,
-                         env=env)
+                         env=tonativeenv(env))
     return p.stdin, p.stdout
 
 def popen3(cmd, env=None):
@@ -146,16 +149,18 @@  def popen3(cmd, env=None):
     return stdin, stdout, stderr
 
 def popen4(cmd, env=None, bufsize=-1):
-    p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
+    p = subprocess.Popen(pycompat.rapply(tonativestr, cmd),
+                         shell=True, bufsize=bufsize,
                          close_fds=closefds,
                          stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE,
-                         env=env)
+                         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(cmd, shell=True, close_fds=closefds,
+    p = subprocess.Popen(pycompat.rapply(tonativestr, cmd),
+                         shell=True, close_fds=closefds,
                          stdin=subprocess.PIPE, stdout=subprocess.PIPE)
     pout, perr = p.communicate(s)
     return pout
@@ -346,11 +351,14 @@  def system(cmd, environ=None, cwd=None, 
     cmd = quotecommand(cmd)
     env = shellenviron(environ)
     if out is None or isstdout(out):
-        rc = subprocess.call(cmd, shell=True, close_fds=closefds,
-                             env=env, cwd=cwd)
+        rc = subprocess.call(pycompat.rapply(tonativestr, cmd),
+                             shell=True, close_fds=closefds,
+                             env=tonativeenv(env), cwd=tonativestr(cwd))
     else:
-        proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
-                                env=env, cwd=cwd, stdout=subprocess.PIPE,
+        proc = subprocess.Popen(pycompat.rapply(tonativestr, cmd),
+                                shell=True, close_fds=closefds,
+                                env=tonativeenv(env), cwd=tonativestr(cwd),
+                                stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT)
         for line in iter(proc.stdout.readline, ''):
             out.write(line)