[Python-checkins] distutils2: merged spawn into util

tarek.ziade python-checkins at python.org
Sun Jul 25 00:01:03 CEST 2010


tarek.ziade pushed 23d074c6978d to distutils2:

http://hg.python.org/distutils2/rev/23d074c6978d
changeset:   385:23d074c6978d
tag:         tip
user:        Tarek Ziade <tarek at ziade.org>
date:        Sun Jul 25 00:00:54 2010 +0200
summary:     merged spawn into util
files:       src/distutils2/command/cmd.py, src/distutils2/command/upload.py, src/distutils2/compiler/ccompiler.py, src/distutils2/spawn.py, src/distutils2/tests/test_bdist.py, src/distutils2/tests/test_build_clib.py, src/distutils2/tests/test_sdist.py, src/distutils2/tests/test_spawn.py, src/distutils2/tests/test_util.py, src/distutils2/util.py

diff --git a/src/distutils2/command/cmd.py b/src/distutils2/command/cmd.py
--- a/src/distutils2/command/cmd.py
+++ b/src/distutils2/command/cmd.py
@@ -411,7 +411,7 @@
 
     def spawn(self, cmd, search_path=1, level=1):
         """Spawn an external command respecting dry-run flag."""
-        from distutils2.spawn import spawn
+        from distutils2.util import spawn
         spawn(cmd, search_path, dry_run= self.dry_run)
 
     def make_archive(self, base_name, format, root_dir=None, base_dir=None,
diff --git a/src/distutils2/command/upload.py b/src/distutils2/command/upload.py
--- a/src/distutils2/command/upload.py
+++ b/src/distutils2/command/upload.py
@@ -15,7 +15,7 @@
 
 from distutils2.errors import DistutilsOptionError
 from distutils2.core import PyPIRCCommand
-from distutils2.spawn import spawn
+from distutils2.util import spawn
 from distutils2 import log
 
 class upload(PyPIRCCommand):
diff --git a/src/distutils2/compiler/ccompiler.py b/src/distutils2/compiler/ccompiler.py
--- a/src/distutils2/compiler/ccompiler.py
+++ b/src/distutils2/compiler/ccompiler.py
@@ -11,8 +11,7 @@
 
 from distutils2.errors import (CompileError, LinkError, UnknownFileError,
                                DistutilsPlatformError, DistutilsModuleError)
-from distutils2.spawn import spawn
-from distutils2.util import split_quoted, execute, newer_group
+from distutils2.util import split_quoted, execute, newer_group, spawn
 from distutils2 import log
 from shutil import move
 
diff --git a/src/distutils2/spawn.py b/src/distutils2/spawn.py
deleted file mode 100644
--- a/src/distutils2/spawn.py
+++ /dev/null
@@ -1,192 +0,0 @@
-"""distutils.spawn
-
-Provides the 'spawn()' function, a front-end to various platform-
-specific functions for launching another program in a sub-process.
-Also provides the 'find_executable()' to search the path for a given
-executable name.
-"""
-
-__revision__ = "$Id: spawn.py 73147 2009-06-02 15:58:43Z tarek.ziade $"
-
-import sys
-import os
-
-from distutils2.errors import DistutilsPlatformError, DistutilsExecError
-from distutils2 import log
-
-def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None):
-    """Run another program, specified as a command list 'cmd', in a new process.
-
-    'cmd' is just the argument list for the new process, ie.
-    cmd[0] is the program to run and cmd[1:] are the rest of its arguments.
-    There is no way to run a program with a name different from that of its
-    executable.
-
-    If 'search_path' is true (the default), the system's executable
-    search path will be used to find the program; otherwise, cmd[0]
-    must be the exact path to the executable.  If 'dry_run' is true,
-    the command will not actually be run.
-
-    If 'env' is given, it's a environment dictionary used for the execution
-    environment.
-
-    Raise DistutilsExecError if running the program fails in any way; just
-    return on success.
-    """
-    if os.name == 'posix':
-        _spawn_posix(cmd, search_path, dry_run=dry_run, env=env)
-    elif os.name == 'nt':
-        _spawn_nt(cmd, search_path, dry_run=dry_run, env=env)
-    elif os.name == 'os2':
-        _spawn_os2(cmd, search_path, dry_run=dry_run, env=env)
-    else:
-        raise DistutilsPlatformError, \
-              "don't know how to spawn programs on platform '%s'" % os.name
-
-def _nt_quote_args(args):
-    """Quote command-line arguments for DOS/Windows conventions.
-
-    Just wraps every argument which contains blanks in double quotes, and
-    returns a new argument list.
-    """
-    # XXX this doesn't seem very robust to me -- but if the Windows guys
-    # say it'll work, I guess I'll have to accept it.  (What if an arg
-    # contains quotes?  What other magic characters, other than spaces,
-    # have to be escaped?  Is there an escaping mechanism other than
-    # quoting?)
-    for i, arg in enumerate(args):
-        if ' ' in arg:
-            args[i] = '"%s"' % arg
-    return args
-
-def _spawn_nt(cmd, search_path=1, verbose=0, dry_run=0, env=None):
-    executable = cmd[0]
-    cmd = _nt_quote_args(cmd)
-    if search_path:
-        # either we find one or it stays the same
-        executable = find_executable(executable) or executable
-    log.info(' '.join([executable] + cmd[1:]))
-    if not dry_run:
-        # spawn for NT requires a full path to the .exe
-        try:
-            if env is None:
-                rc = os.spawnv(os.P_WAIT, executable, cmd)
-            else:
-                rc = os.spawnve(os.P_WAIT, executable, cmd, env)
-
-        except OSError, exc:
-            # this seems to happen when the command isn't found
-            raise DistutilsExecError, \
-                  "command '%s' failed: %s" % (cmd[0], exc[-1])
-        if rc != 0:
-            # and this reflects the command running but failing
-            raise DistutilsExecError, \
-                  "command '%s' failed with exit status %d" % (cmd[0], rc)
-
-def _spawn_os2(cmd, search_path=1, verbose=0, dry_run=0, env=None):
-    executable = cmd[0]
-    if search_path:
-        # either we find one or it stays the same
-        executable = find_executable(executable) or executable
-    log.info(' '.join([executable] + cmd[1:]))
-    if not dry_run:
-        # spawnv for OS/2 EMX requires a full path to the .exe
-        try:
-            if env is None:
-                rc = os.spawnv(os.P_WAIT, executable, cmd)
-            else:
-                rc = os.spawnve(os.P_WAIT, executable, cmd, env)
-
-        except OSError, exc:
-            # this seems to happen when the command isn't found
-            raise DistutilsExecError, \
-                  "command '%s' failed: %s" % (cmd[0], exc[-1])
-        if rc != 0:
-            # and this reflects the command running but failing
-            log.debug("command '%s' failed with exit status %d" % (cmd[0], rc))
-            raise DistutilsExecError, \
-                  "command '%s' failed with exit status %d" % (cmd[0], rc)
-
-
-def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0, env=None):
-    log.info(' '.join(cmd))
-    if dry_run:
-        return
-
-    if env is None:
-        exec_fn = search_path and os.execvp or os.execv
-    else:
-        exec_fn = search_path and os.execvpe or os.execve
-
-    pid = os.fork()
-
-    if pid == 0:  # in the child
-        try:
-            if env is None:
-                exec_fn(cmd[0], cmd)
-            else:
-                exec_fn(cmd[0], cmd, env)
-        except OSError, e:
-            sys.stderr.write("unable to execute %s: %s\n" %
-                             (cmd[0], e.strerror))
-            os._exit(1)
-
-        sys.stderr.write("unable to execute %s for unknown reasons" % cmd[0])
-        os._exit(1)
-    else:   # in the parent
-        # Loop until the child either exits or is terminated by a signal
-        # (ie. keep waiting if it's merely stopped)
-        while 1:
-            try:
-                pid, status = os.waitpid(pid, 0)
-            except OSError, exc:
-                import errno
-                if exc.errno == errno.EINTR:
-                    continue
-                raise DistutilsExecError, \
-                      "command '%s' failed: %s" % (cmd[0], exc[-1])
-            if os.WIFSIGNALED(status):
-                raise DistutilsExecError, \
-                      "command '%s' terminated by signal %d" % \
-                      (cmd[0], os.WTERMSIG(status))
-
-            elif os.WIFEXITED(status):
-                exit_status = os.WEXITSTATUS(status)
-                if exit_status == 0:
-                    return   # hey, it succeeded!
-                else:
-                    raise DistutilsExecError, \
-                          "command '%s' failed with exit status %d" % \
-                          (cmd[0], exit_status)
-
-            elif os.WIFSTOPPED(status):
-                continue
-
-            else:
-                raise DistutilsExecError, \
-                      "unknown error executing '%s': termination status %d" % \
-                      (cmd[0], status)
-
-def find_executable(executable, path=None):
-    """Tries to find 'executable' in the directories listed in 'path'.
-
-    A string listing directories separated by 'os.pathsep'; defaults to
-    os.environ['PATH'].  Returns the complete filename or None if not found.
-    """
-    if path is None:
-        path = os.environ['PATH']
-    paths = path.split(os.pathsep)
-    base, ext = os.path.splitext(executable)
-
-    if (sys.platform == 'win32' or os.name == 'os2') and (ext != '.exe'):
-        executable = executable + '.exe'
-
-    if not os.path.isfile(executable):
-        for p in paths:
-            f = os.path.join(p, executable)
-            if os.path.isfile(f):
-                # the file exists, we have a shot at spawn working
-                return f
-        return None
-    else:
-        return executable
diff --git a/src/distutils2/tests/test_bdist.py b/src/distutils2/tests/test_bdist.py
--- a/src/distutils2/tests/test_bdist.py
+++ b/src/distutils2/tests/test_bdist.py
@@ -8,8 +8,7 @@
 from distutils2.command.bdist import bdist
 from distutils2.tests import support
 from distutils2.tests.support import unittest
-from distutils2.spawn import find_executable
-from distutils2 import spawn
+from distutils2.util import find_executable
 from distutils2.errors import DistutilsExecError
 
 class BuildTestCase(support.TempdirManager,
diff --git a/src/distutils2/tests/test_build_clib.py b/src/distutils2/tests/test_build_clib.py
--- a/src/distutils2/tests/test_build_clib.py
+++ b/src/distutils2/tests/test_build_clib.py
@@ -5,7 +5,7 @@
 from distutils2.command.build_clib import build_clib
 from distutils2.errors import DistutilsSetupError
 from distutils2.tests import support
-from distutils2.spawn import find_executable
+from distutils2.util import find_executable
 from distutils2.tests.support import unittest
 
 class BuildCLibTestCase(support.TempdirManager,
diff --git a/src/distutils2/tests/test_sdist.py b/src/distutils2/tests/test_sdist.py
--- a/src/distutils2/tests/test_sdist.py
+++ b/src/distutils2/tests/test_sdist.py
@@ -30,7 +30,7 @@
 from distutils2.tests.support import unittest
 from distutils2.tests.test_config import PyPIRCCommandTestCase
 from distutils2.errors import DistutilsExecError, DistutilsOptionError
-from distutils2.spawn import find_executable
+from distutils2.util import find_executable
 from distutils2.tests import support
 from distutils2.log import WARN
 try:
diff --git a/src/distutils2/tests/test_spawn.py b/src/distutils2/tests/test_spawn.py
deleted file mode 100644
--- a/src/distutils2/tests/test_spawn.py
+++ /dev/null
@@ -1,60 +0,0 @@
-"""Tests for distutils.spawn."""
-import os
-import time
-from distutils2.tests import captured_stdout
-
-from distutils2.spawn import _nt_quote_args
-from distutils2.spawn import spawn, find_executable
-from distutils2.errors import DistutilsExecError
-from distutils2.tests import support
-from distutils2.tests.support import unittest
-
-class SpawnTestCase(support.TempdirManager,
-                    support.LoggingSilencer,
-                    unittest.TestCase):
-
-    def test_nt_quote_args(self):
-
-        for (args, wanted) in ((['with space', 'nospace'],
-                                ['"with space"', 'nospace']),
-                               (['nochange', 'nospace'],
-                                ['nochange', 'nospace'])):
-            res = _nt_quote_args(args)
-            self.assertEqual(res, wanted)
-
-
-    @unittest.skipUnless(os.name in ('nt', 'posix'),
-                         'Runs only under posix or nt')
-    def test_spawn(self):
-        tmpdir = self.mkdtemp()
-
-        # creating something executable
-        # through the shell that returns 1
-        if os.name == 'posix':
-            exe = os.path.join(tmpdir, 'foo.sh')
-            self.write_file(exe, '#!/bin/sh\nexit 1')
-            os.chmod(exe, 0777)
-        else:
-            exe = os.path.join(tmpdir, 'foo.bat')
-            self.write_file(exe, 'exit 1')
-
-        os.chmod(exe, 0777)
-        self.assertRaises(DistutilsExecError, spawn, [exe])
-
-        # now something that works
-        if os.name == 'posix':
-            exe = os.path.join(tmpdir, 'foo.sh')
-            self.write_file(exe, '#!/bin/sh\nexit 0')
-            os.chmod(exe, 0777)
-        else:
-            exe = os.path.join(tmpdir, 'foo.bat')
-            self.write_file(exe, 'exit 0')
-
-        os.chmod(exe, 0777)
-        spawn([exe])  # should work without any error
-
-def test_suite():
-    return unittest.makeSuite(SpawnTestCase)
-
-if __name__ == "__main__":
-    unittest.main(defaultTest="test_suite")
diff --git a/src/distutils2/tests/test_util.py b/src/distutils2/tests/test_util.py
--- a/src/distutils2/tests/test_util.py
+++ b/src/distutils2/tests/test_util.py
@@ -7,15 +7,18 @@
 import tempfile
 import time
 
+from distutils2.tests import captured_stdout
+from distutils2.tests.support import unittest
 from distutils2.errors import (DistutilsPlatformError,
                                DistutilsByteCompileError,
-                               DistutilsFileError)
-
+                               DistutilsFileError,
+                               DistutilsExecError)
 from distutils2.util import (convert_path, change_root,
-                            check_environ, split_quoted, strtobool,
-                            rfc822_escape, get_compiler_versions,
-                            _find_exe_version, _MAC_OS_X_LD_VERSION,
-                            byte_compile, find_packages)
+                             check_environ, split_quoted, strtobool,
+                             rfc822_escape, get_compiler_versions,
+                             _find_exe_version, _MAC_OS_X_LD_VERSION,
+                             byte_compile, find_packages, spawn, find_executable,
+                             _nt_quote_args)
 from distutils2 import util
 from distutils2.tests import support
 from distutils2.tests.support import unittest
@@ -332,6 +335,46 @@
         file_handle.close()
         self.assertEquals(new_content, converted_content)
 
+    def test_nt_quote_args(self):
+
+        for (args, wanted) in ((['with space', 'nospace'],
+                                ['"with space"', 'nospace']),
+                               (['nochange', 'nospace'],
+                                ['nochange', 'nospace'])):
+            res = _nt_quote_args(args)
+            self.assertEqual(res, wanted)
+
+
+    @unittest.skipUnless(os.name in ('nt', 'posix'),
+                         'Runs only under posix or nt')
+    def test_spawn(self):
+        tmpdir = self.mkdtemp()
+
+        # creating something executable
+        # through the shell that returns 1
+        if os.name == 'posix':
+            exe = os.path.join(tmpdir, 'foo.sh')
+            self.write_file(exe, '#!/bin/sh\nexit 1')
+            os.chmod(exe, 0777)
+        else:
+            exe = os.path.join(tmpdir, 'foo.bat')
+            self.write_file(exe, 'exit 1')
+
+        os.chmod(exe, 0777)
+        self.assertRaises(DistutilsExecError, spawn, [exe])
+
+        # now something that works
+        if os.name == 'posix':
+            exe = os.path.join(tmpdir, 'foo.sh')
+            self.write_file(exe, '#!/bin/sh\nexit 0')
+            os.chmod(exe, 0777)
+        else:
+            exe = os.path.join(tmpdir, 'foo.bat')
+            self.write_file(exe, 'exit 0')
+
+        os.chmod(exe, 0777)
+        spawn([exe])  # should work without any error
+
 
 def test_suite():
     return unittest.makeSuite(UtilTestCase)
diff --git a/src/distutils2/util.py b/src/distutils2/util.py
--- a/src/distutils2/util.py
+++ b/src/distutils2/util.py
@@ -13,8 +13,7 @@
 from fnmatch import fnmatchcase
 
 from distutils2.errors import (DistutilsPlatformError, DistutilsFileError,
-                               DistutilsByteCompileError)
-from distutils2.spawn import spawn, find_executable
+                               DistutilsByteCompileError, DistutilsExecError)
 from distutils2 import log
 from distutils2._backport import sysconfig as _sysconfig
 
@@ -688,3 +687,181 @@
         """ Issues a call to util.run_2to3. """
         return run_2to3(files, doctests_only, self.fixer_names,
                         self.options, self.explicit)
+
+
+def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None):
+    """Run another program, specified as a command list 'cmd', in a new process.
+
+    'cmd' is just the argument list for the new process, ie.
+    cmd[0] is the program to run and cmd[1:] are the rest of its arguments.
+    There is no way to run a program with a name different from that of its
+    executable.
+
+    If 'search_path' is true (the default), the system's executable
+    search path will be used to find the program; otherwise, cmd[0]
+    must be the exact path to the executable.  If 'dry_run' is true,
+    the command will not actually be run.
+
+    If 'env' is given, it's a environment dictionary used for the execution
+    environment.
+
+    Raise DistutilsExecError if running the program fails in any way; just
+    return on success.
+    """
+    if os.name == 'posix':
+        _spawn_posix(cmd, search_path, dry_run=dry_run, env=env)
+    elif os.name == 'nt':
+        _spawn_nt(cmd, search_path, dry_run=dry_run, env=env)
+    elif os.name == 'os2':
+        _spawn_os2(cmd, search_path, dry_run=dry_run, env=env)
+    else:
+        raise DistutilsPlatformError, \
+              "don't know how to spawn programs on platform '%s'" % os.name
+
+def _nt_quote_args(args):
+    """Quote command-line arguments for DOS/Windows conventions.
+
+    Just wraps every argument which contains blanks in double quotes, and
+    returns a new argument list.
+    """
+    # XXX this doesn't seem very robust to me -- but if the Windows guys
+    # say it'll work, I guess I'll have to accept it.  (What if an arg
+    # contains quotes?  What other magic characters, other than spaces,
+    # have to be escaped?  Is there an escaping mechanism other than
+    # quoting?)
+    for i, arg in enumerate(args):
+        if ' ' in arg:
+            args[i] = '"%s"' % arg
+    return args
+
+def _spawn_nt(cmd, search_path=1, verbose=0, dry_run=0, env=None):
+    executable = cmd[0]
+    cmd = _nt_quote_args(cmd)
+    if search_path:
+        # either we find one or it stays the same
+        executable = find_executable(executable) or executable
+    log.info(' '.join([executable] + cmd[1:]))
+    if not dry_run:
+        # spawn for NT requires a full path to the .exe
+        try:
+            if env is None:
+                rc = os.spawnv(os.P_WAIT, executable, cmd)
+            else:
+                rc = os.spawnve(os.P_WAIT, executable, cmd, env)
+
+        except OSError, exc:
+            # this seems to happen when the command isn't found
+            raise DistutilsExecError, \
+                  "command '%s' failed: %s" % (cmd[0], exc[-1])
+        if rc != 0:
+            # and this reflects the command running but failing
+            raise DistutilsExecError, \
+                  "command '%s' failed with exit status %d" % (cmd[0], rc)
+
+def _spawn_os2(cmd, search_path=1, verbose=0, dry_run=0, env=None):
+    executable = cmd[0]
+    if search_path:
+        # either we find one or it stays the same
+        executable = find_executable(executable) or executable
+    log.info(' '.join([executable] + cmd[1:]))
+    if not dry_run:
+        # spawnv for OS/2 EMX requires a full path to the .exe
+        try:
+            if env is None:
+                rc = os.spawnv(os.P_WAIT, executable, cmd)
+            else:
+                rc = os.spawnve(os.P_WAIT, executable, cmd, env)
+
+        except OSError, exc:
+            # this seems to happen when the command isn't found
+            raise DistutilsExecError, \
+                  "command '%s' failed: %s" % (cmd[0], exc[-1])
+        if rc != 0:
+            # and this reflects the command running but failing
+            log.debug("command '%s' failed with exit status %d" % (cmd[0], rc))
+            raise DistutilsExecError, \
+                  "command '%s' failed with exit status %d" % (cmd[0], rc)
+
+
+def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0, env=None):
+    log.info(' '.join(cmd))
+    if dry_run:
+        return
+
+    if env is None:
+        exec_fn = search_path and os.execvp or os.execv
+    else:
+        exec_fn = search_path and os.execvpe or os.execve
+
+    pid = os.fork()
+
+    if pid == 0:  # in the child
+        try:
+            if env is None:
+                exec_fn(cmd[0], cmd)
+            else:
+                exec_fn(cmd[0], cmd, env)
+        except OSError, e:
+            sys.stderr.write("unable to execute %s: %s\n" %
+                             (cmd[0], e.strerror))
+            os._exit(1)
+
+        sys.stderr.write("unable to execute %s for unknown reasons" % cmd[0])
+        os._exit(1)
+    else:   # in the parent
+        # Loop until the child either exits or is terminated by a signal
+        # (ie. keep waiting if it's merely stopped)
+        while 1:
+            try:
+                pid, status = os.waitpid(pid, 0)
+            except OSError, exc:
+                import errno
+                if exc.errno == errno.EINTR:
+                    continue
+                raise DistutilsExecError, \
+                      "command '%s' failed: %s" % (cmd[0], exc[-1])
+            if os.WIFSIGNALED(status):
+                raise DistutilsExecError, \
+                      "command '%s' terminated by signal %d" % \
+                      (cmd[0], os.WTERMSIG(status))
+
+            elif os.WIFEXITED(status):
+                exit_status = os.WEXITSTATUS(status)
+                if exit_status == 0:
+                    return   # hey, it succeeded!
+                else:
+                    raise DistutilsExecError, \
+                          "command '%s' failed with exit status %d" % \
+                          (cmd[0], exit_status)
+
+            elif os.WIFSTOPPED(status):
+                continue
+
+            else:
+                raise DistutilsExecError, \
+                      "unknown error executing '%s': termination status %d" % \
+                      (cmd[0], status)
+
+def find_executable(executable, path=None):
+    """Tries to find 'executable' in the directories listed in 'path'.
+
+    A string listing directories separated by 'os.pathsep'; defaults to
+    os.environ['PATH'].  Returns the complete filename or None if not found.
+    """
+    if path is None:
+        path = os.environ['PATH']
+    paths = path.split(os.pathsep)
+    base, ext = os.path.splitext(executable)
+
+    if (sys.platform == 'win32' or os.name == 'os2') and (ext != '.exe'):
+        executable = executable + '.exe'
+
+    if not os.path.isfile(executable):
+        for p in paths:
+            f = os.path.join(p, executable)
+            if os.path.isfile(f):
+                # the file exists, we have a shot at spawn working
+                return f
+        return None
+    else:
+        return executable

--
Repository URL: http://hg.python.org/distutils2


More information about the Python-checkins mailing list