[PATCH] util.system: Use subprocess instead of os.system

Mads Kiilerich mads at kiilerich.com
Sun Sep 20 15:20:53 CDT 2009


# HG changeset patch
# User Mads Kiilerich <mads at kiilerich.com>
# Date 1253477958 -7200
# Node ID 91287ee20c7f34349648e09210b3eccd96a4cfd5
# Parent  bccf780f78ed7cab3fac47bfac68fdd56a059ba7
util.system: Use subprocess instead of os.system

subprocess allows the environment and working directory to be specified
directly, so the hacks for making temporary changes while forking is no longer
necessary.

This also fixes failures on solaris where the temporary changes can't be undone
because there is no unsetenv.

diff --git a/mercurial/posix.py b/mercurial/posix.py
--- a/mercurial/posix.py
+++ b/mercurial/posix.py
@@ -165,17 +165,11 @@
         return inst.errno != errno.ESRCH
 
 def explain_exit(code):
-    """return a 2-tuple (desc, code) describing a process's status"""
-    if os.WIFEXITED(code):
-        val = os.WEXITSTATUS(code)
-        return _("exited with status %d") % val, val
-    elif os.WIFSIGNALED(code):
-        val = os.WTERMSIG(code)
-        return _("killed by signal %d") % val, val
-    elif os.WIFSTOPPED(code):
-        val = os.WSTOPSIG(code)
-        return _("stopped by signal %d") % val, val
-    raise ValueError(_("invalid exit code"))
+    """return a 2-tuple (desc, code) describing a subprocess status
+    (codes from kill are negative - not os.system/wait encoding)"""
+    if code >= 0:
+        return _("exited with status %d") % code, code
+    return _("killed by signal %d") % -code, -code
 
 def isowner(st):
     """Return True if the stat object st is from the current user."""
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -357,41 +357,26 @@
         if val is True:
             return '1'
         return str(val)
-    oldenv = {}
-    for k in environ:
-        oldenv[k] = os.environ.get(k)
-    if cwd is not None:
-        oldcwd = os.getcwd()
     origcmd = cmd
     if os.name == 'nt':
         cmd = '"%s"' % cmd
-    try:
-        for k, v in environ.iteritems():
-            os.environ[k] = py2shell(v)
-        os.environ['HG'] = hgexecutable()
-        if cwd is not None and oldcwd != cwd:
-            os.chdir(cwd)
-        rc = os.system(cmd)
-        if sys.platform == 'OpenVMS' and rc & 1:
-            rc = 0
-        if rc and onerr:
-            errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
-                                explain_exit(rc)[0])
-            if errprefix:
-                errmsg = '%s: %s' % (errprefix, errmsg)
-            try:
-                onerr.warn(errmsg + '\n')
-            except AttributeError:
-                raise onerr(errmsg)
-        return rc
-    finally:
-        for k, v in oldenv.iteritems():
-            if v is None:
-                del os.environ[k]
-            else:
-                os.environ[k] = v
-        if cwd is not None and oldcwd != cwd:
-            os.chdir(oldcwd)
+    env = dict(os.environ)
+    env.update((k, py2shell(v)) for k, v in environ.iteritems())
+    env['HG'] = hgexecutable()
+    rc = subprocess.call(cmd, shell=True, close_fds=closefds,
+                         env=env, cwd=cwd)
+    if sys.platform == 'OpenVMS' and rc & 1:
+        rc = 0
+    if rc and onerr:
+        errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
+                            explain_exit(rc)[0])
+        if errprefix:
+            errmsg = '%s: %s' % (errprefix, errmsg)
+        try:
+            onerr.warn(errmsg + '\n')
+        except AttributeError:
+            raise onerr(errmsg)
+    return rc
 
 def checksignature(func):
     '''wrap a function with code to check for calling errors'''


More information about the Mercurial-devel mailing list