changeset: 89627:c04260b59e8c parent: 89624:f22e1d89486d parent: 89626:43b06352221b user: Éric Araujo date: Thu Mar 13 05:59:31 2014 -0400 files: Lib/distutils/spawn.py Misc/NEWS description: Merge 3.3 (#11599) diff -r f22e1d89486d -r c04260b59e8c Doc/distutils/setupscript.rst --- a/Doc/distutils/setupscript.rst Thu Mar 13 10:54:18 2014 +0100 +++ b/Doc/distutils/setupscript.rst Thu Mar 13 05:59:31 2014 -0400 @@ -685,6 +685,8 @@ DistributionMetadata.download_url = None +.. _debug-setup-script: + Debugging the setup script ========================== @@ -700,7 +702,8 @@ and see that it's a permission problem. On the other hand, this doesn't help the developer to find the cause of the -failure. For this purpose, the DISTUTILS_DEBUG environment variable can be set +failure. For this purpose, the :envvar:`DISTUTILS_DEBUG` environment variable can be set to anything except an empty string, and distutils will now print detailed -information what it is doing, and prints the full traceback in case an exception -occurs. +information about what it is doing, dump the full traceback when an exception +occurs, and print the whole command line when an external program (like a C +compiler) fails. diff -r f22e1d89486d -r c04260b59e8c Doc/install/index.rst --- a/Doc/install/index.rst Thu Mar 13 10:54:18 2014 +0100 +++ b/Doc/install/index.rst Thu Mar 13 05:59:31 2014 -0400 @@ -58,7 +58,8 @@ document; there will be some brief forays into using Python's interactive mode to explore your installation, but that's it. If you're looking for information on how to distribute your own Python modules so that others may use them, see -the :ref:`distutils-index` manual. +the :ref:`distutils-index` manual. :ref:`debug-setup-script` may also be of +interest. .. _inst-trivial-install: diff -r f22e1d89486d -r c04260b59e8c Lib/distutils/spawn.py --- a/Lib/distutils/spawn.py Thu Mar 13 10:54:18 2014 +0100 +++ b/Lib/distutils/spawn.py Thu Mar 13 05:59:31 2014 -0400 @@ -10,6 +10,7 @@ import os from distutils.errors import DistutilsPlatformError, DistutilsExecError +from distutils.debug import DEBUG from distutils import log def spawn(cmd, search_path=1, verbose=0, dry_run=0): @@ -28,10 +29,15 @@ Raise DistutilsExecError if running the program fails in any way; just return on success. """ + # cmd is documented as a list, but just in case some code passes a tuple + # in, protect our %-formatting code against horrible death + cmd = list(cmd) if os.name == 'posix': _spawn_posix(cmd, search_path, dry_run=dry_run) elif os.name == 'nt': _spawn_nt(cmd, search_path, dry_run=dry_run) + elif os.name == 'os2': + _spawn_os2(cmd, search_path, dry_run=dry_run) else: raise DistutilsPlatformError( "don't know how to spawn programs on platform '%s'" % os.name) @@ -65,12 +71,16 @@ rc = os.spawnv(os.P_WAIT, executable, cmd) except OSError as exc: # this seems to happen when the command isn't found + if not DEBUG: + cmd = executable raise DistutilsExecError( - "command '%s' failed: %s" % (cmd[0], exc.args[-1])) + "command %r failed: %s" % (cmd, exc.args[-1])) if rc != 0: # and this reflects the command running but failing + if not DEBUG: + cmd = executable raise DistutilsExecError( - "command '%s' failed with exit status %d" % (cmd[0], rc)) + "command %r failed with exit status %d" % (cmd, rc)) if sys.platform == 'darwin': from distutils import sysconfig @@ -81,8 +91,9 @@ log.info(' '.join(cmd)) if dry_run: return + executable = cmd[0] exec_fn = search_path and os.execvp or os.execv - exec_args = [cmd[0], cmd] + env = None if sys.platform == 'darwin': global _cfg_target, _cfg_target_split if _cfg_target is None: @@ -103,17 +114,23 @@ env = dict(os.environ, MACOSX_DEPLOYMENT_TARGET=cur_target) exec_fn = search_path and os.execvpe or os.execve - exec_args.append(env) pid = os.fork() if pid == 0: # in the child try: - exec_fn(*exec_args) + if env is None: + exec_fn(executable, cmd) + else: + exec_fn(executable, cmd, env) except OSError as e: - sys.stderr.write("unable to execute %s: %s\n" - % (cmd[0], e.strerror)) + if not DEBUG: + cmd = executable + sys.stderr.write("unable to execute %r: %s\n" + % (cmd, e.strerror)) os._exit(1) - sys.stderr.write("unable to execute %s for unknown reasons" % cmd[0]) + if not DEBUG: + cmd = executable + sys.stderr.write("unable to execute %r for unknown reasons" % cmd) os._exit(1) else: # in the parent # Loop until the child either exits or is terminated by a signal @@ -125,26 +142,34 @@ import errno if exc.errno == errno.EINTR: continue + if not DEBUG: + cmd = executable raise DistutilsExecError( - "command '%s' failed: %s" % (cmd[0], exc.args[-1])) + "command %r failed: %s" % (cmd, exc.args[-1])) if os.WIFSIGNALED(status): + if not DEBUG: + cmd = executable raise DistutilsExecError( - "command '%s' terminated by signal %d" - % (cmd[0], os.WTERMSIG(status))) + "command %r terminated by signal %d" + % (cmd, os.WTERMSIG(status))) elif os.WIFEXITED(status): exit_status = os.WEXITSTATUS(status) if exit_status == 0: return # hey, it succeeded! else: + if not DEBUG: + cmd = executable raise DistutilsExecError( - "command '%s' failed with exit status %d" - % (cmd[0], exit_status)) + "command %r failed with exit status %d" + % (cmd, exit_status)) elif os.WIFSTOPPED(status): continue else: + if not DEBUG: + cmd = executable raise DistutilsExecError( - "unknown error executing '%s': termination status %d" - % (cmd[0], status)) + "unknown error executing %r: termination status %d" + % (cmd, status)) def find_executable(executable, path=None): """Tries to find 'executable' in the directories listed in 'path'. diff -r f22e1d89486d -r c04260b59e8c Misc/NEWS --- a/Misc/NEWS Thu Mar 13 10:54:18 2014 +0100 +++ b/Misc/NEWS Thu Mar 13 05:59:31 2014 -0400 @@ -23,6 +23,10 @@ - Issue #19157: Include the broadcast address in the usuable hosts for IPv6 in ipaddress. +- Issue #11599: When an external command (e.g. compiler) fails, distutils now + prints out the whole command line (instead of just the command name) if the + environment variable DISTUTILS_DEBUG is set. + - Issue #4931: distutils should not produce unhelpful "error: None" messages anymore. distutils.util.grok_environment_error is kept but doc-deprecated.