]> granicus.if.org Git - python/commitdiff
Make distutils error messages more helpful (#11599).
authorÉric Araujo <merwok@netwok.org>
Thu, 13 Mar 2014 02:19:39 +0000 (22:19 -0400)
committerÉric Araujo <merwok@netwok.org>
Thu, 13 Mar 2014 02:19:39 +0000 (22:19 -0400)
When running external programs such as a C compiler and getting an
error code, distutils only prints the program name.  With this change,
one can get the full command line by setting the DISTUTILS_DEBUG
environment variable.

This should have no compatibility issues, unless there are tools
that depend on the exact format of distutils debug messages.

Doc/distutils/setupscript.rst
Doc/install/index.rst
Lib/distutils/spawn.py
Misc/NEWS

index 1d13a9cce94549e8b3f96250ef7363f36483c003..15f130fb4485a01c09c4128d0ce578d3dd8bb0a1 100644 (file)
@@ -684,6 +684,8 @@ include the following code fragment in your :file:`setup.py` before the
         DistributionMetadata.download_url = None
 
 
+.. _debug-setup-script:
+
 Debugging the setup script
 ==========================
 
@@ -699,7 +701,8 @@ installation is broken because they don't read all the way down to the bottom
 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.
index a5a4c2147513da692903b8bbd22e7ea712ea1df0..ad939ab23681f227b10698dfbbf31f2e934ca3c1 100644 (file)
@@ -58,7 +58,9 @@ new goodies to their toolbox.  You don't need to know Python to read this
 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:
index 7306099f6b6752c8267fea407aa8c5ae42410f3e..321344a3a5833f18a97c3596fbe8cbedb5c838c5 100644 (file)
@@ -12,6 +12,7 @@ import sys
 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):
@@ -30,6 +31,9 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0):
     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':
@@ -69,12 +73,16 @@ def _spawn_nt(cmd, search_path=1, verbose=0, dry_run=0):
             rc = os.spawnv(os.P_WAIT, executable, cmd)
         except OSError, 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[-1])
+                  "command %r failed: %s" % (cmd, exc[-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)
 
 def _spawn_os2(cmd, search_path=1, verbose=0, dry_run=0):
     executable = cmd[0]
@@ -88,13 +96,17 @@ def _spawn_os2(cmd, search_path=1, verbose=0, dry_run=0):
             rc = os.spawnv(os.P_WAIT, executable, cmd)
         except OSError, 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[-1])
+                  "command %r failed: %s" % (cmd, 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))
+            if not DEBUG:
+                cmd = executable
+            log.debug("command %r failed with exit status %d" % (cmd, rc))
             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
@@ -105,8 +117,9 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
     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:
@@ -127,18 +140,24 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
             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, 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
@@ -150,29 +169,37 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
                 import errno
                 if exc.errno == errno.EINTR:
                     continue
+                if not DEBUG:
+                    cmd = executable
                 raise DistutilsExecError, \
-                      "command '%s' failed: %s" % (cmd[0], exc[-1])
+                      "command %r failed: %s" % (cmd, exc[-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'.
index 2fce4379da073a55122e8d3442059c67e4ce0c3b..4e915f5f9ebccd713f0f5f80c3ef10dc19cc38e1 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -44,6 +44,10 @@ Library
   as documented.  The pattern and source keyword parameters are left as
   deprecated aliases.
 
+- 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.