diff options
Diffstat (limited to 'src/distutils2')
| -rw-r--r-- | src/distutils2/command/cmd.py | 2 | ||||
| -rw-r--r-- | src/distutils2/command/upload.py | 2 | ||||
| -rw-r--r-- | src/distutils2/compiler/ccompiler.py | 3 | ||||
| -rw-r--r-- | src/distutils2/spawn.py | 192 | ||||
| -rw-r--r-- | src/distutils2/tests/test_bdist.py | 3 | ||||
| -rw-r--r-- | src/distutils2/tests/test_build_clib.py | 2 | ||||
| -rw-r--r-- | src/distutils2/tests/test_sdist.py | 2 | ||||
| -rw-r--r-- | src/distutils2/tests/test_spawn.py | 60 | ||||
| -rw-r--r-- | src/distutils2/tests/test_util.py | 55 | ||||
| -rw-r--r-- | src/distutils2/util.py | 181 |
10 files changed, 234 insertions, 268 deletions
diff --git a/src/distutils2/command/cmd.py b/src/distutils2/command/cmd.py index ea001b3..fa6f281 100644 --- a/src/distutils2/command/cmd.py +++ b/src/distutils2/command/cmd.py @@ -411,7 +411,7 @@ class Command(object): 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 index 14fe119..796ca73 100644 --- a/src/distutils2/command/upload.py +++ b/src/distutils2/command/upload.py @@ -15,7 +15,7 @@ except ImportError: 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 index adbf529..c9bb129 100644 --- a/src/distutils2/compiler/ccompiler.py +++ b/src/distutils2/compiler/ccompiler.py @@ -11,8 +11,7 @@ import re 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 index 08996fc..0000000 --- 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 index 345c74c..2be01e1 100644 --- a/src/distutils2/tests/test_bdist.py +++ b/src/distutils2/tests/test_bdist.py @@ -8,8 +8,7 @@ from distutils2.core import Distribution 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 index 48af7e1..348f700 100644 --- a/src/distutils2/tests/test_build_clib.py +++ b/src/distutils2/tests/test_build_clib.py @@ -5,7 +5,7 @@ import sys 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 index ec4c87a..8859a3d 100644 --- a/src/distutils2/tests/test_sdist.py +++ b/src/distutils2/tests/test_sdist.py @@ -30,7 +30,7 @@ from distutils2.core import Distribution 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 index 2c7f1ad..0000000 --- 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 index c770c59..51097a7 100644 --- a/src/distutils2/tests/test_util.py +++ b/src/distutils2/tests/test_util.py @@ -7,15 +7,18 @@ import subprocess 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 @@ class UtilTestCase(support.EnvironGuard, 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 index b9aa3f7..a249fee 100644 --- a/src/distutils2/util.py +++ b/src/distutils2/util.py @@ -13,8 +13,7 @@ from copy import copy 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 @@ class Mixin2to3: """ 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 |
