88
99import sys
1010import os
11+ import subprocess
1112
1213from distutils .errors import DistutilsPlatformError , DistutilsExecError
1314from distutils .debug import DEBUG
1415from distutils import log
1516
17+
18+ if sys .platform == 'darwin' :
19+ _cfg_target = None
20+ _cfg_target_split = None
21+
22+
1623def spawn (cmd , search_path = 1 , verbose = 0 , dry_run = 0 ):
1724 """Run another program, specified as a command list 'cmd', in a new process.
1825
@@ -32,64 +39,16 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0):
3239 # cmd is documented as a list, but just in case some code passes a tuple
3340 # in, protect our %-formatting code against horrible death
3441 cmd = list (cmd )
35- if os .name == 'posix' :
36- _spawn_posix (cmd , search_path , dry_run = dry_run )
37- elif os .name == 'nt' :
38- _spawn_nt (cmd , search_path , dry_run = dry_run )
39- else :
40- raise DistutilsPlatformError (
41- "don't know how to spawn programs on platform '%s'" % os .name )
42-
43- def _nt_quote_args (args ):
44- """Quote command-line arguments for DOS/Windows conventions.
45-
46- Just wraps every argument which contains blanks in double quotes, and
47- returns a new argument list.
48- """
49- # XXX this doesn't seem very robust to me -- but if the Windows guys
50- # say it'll work, I guess I'll have to accept it. (What if an arg
51- # contains quotes? What other magic characters, other than spaces,
52- # have to be escaped? Is there an escaping mechanism other than
53- # quoting?)
54- for i , arg in enumerate (args ):
55- if ' ' in arg :
56- args [i ] = '"%s"' % arg
57- return args
58-
59- def _spawn_nt (cmd , search_path = 1 , verbose = 0 , dry_run = 0 ):
60- executable = cmd [0 ]
61- cmd = _nt_quote_args (cmd )
62- if search_path :
63- # either we find one or it stays the same
64- executable = find_executable (executable ) or executable
65- log .info (' ' .join ([executable ] + cmd [1 :]))
66- if not dry_run :
67- # spawn for NT requires a full path to the .exe
68- try :
69- rc = os .spawnv (os .P_WAIT , executable , cmd )
70- except OSError as exc :
71- # this seems to happen when the command isn't found
72- if not DEBUG :
73- cmd = executable
74- raise DistutilsExecError (
75- "command %r failed: %s" % (cmd , exc .args [- 1 ]))
76- if rc != 0 :
77- # and this reflects the command running but failing
78- if not DEBUG :
79- cmd = executable
80- raise DistutilsExecError (
81- "command %r failed with exit status %d" % (cmd , rc ))
82-
83- if sys .platform == 'darwin' :
84- _cfg_target = None
85- _cfg_target_split = None
8642
87- def _spawn_posix (cmd , search_path = 1 , verbose = 0 , dry_run = 0 ):
8843 log .info (' ' .join (cmd ))
8944 if dry_run :
9045 return
91- executable = cmd [0 ]
92- exec_fn = search_path and os .execvp or os .execv
46+
47+ if search_path :
48+ executable = find_executable (cmd [0 ])
49+ if executable is not None :
50+ cmd [0 ] = executable
51+
9352 env = None
9453 if sys .platform == 'darwin' :
9554 global _cfg_target , _cfg_target_split
@@ -111,60 +70,17 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
11170 raise DistutilsPlatformError (my_msg )
11271 env = dict (os .environ ,
11372 MACOSX_DEPLOYMENT_TARGET = cur_target )
114- exec_fn = search_path and os .execvpe or os .execve
115- pid = os .fork ()
116- if pid == 0 : # in the child
117- try :
118- if env is None :
119- exec_fn (executable , cmd )
120- else :
121- exec_fn (executable , cmd , env )
122- except OSError as e :
123- if not DEBUG :
124- cmd = executable
125- sys .stderr .write ("unable to execute %r: %s\n "
126- % (cmd , e .strerror ))
127- os ._exit (1 )
12873
74+ proc = subprocess .Popen (cmd , env = env )
75+ proc .wait ()
76+ exitcode = proc .returncode
77+
78+ if exitcode :
12979 if not DEBUG :
130- cmd = executable
131- sys .stderr .write ("unable to execute %r for unknown reasons" % cmd )
132- os ._exit (1 )
133- else : # in the parent
134- # Loop until the child either exits or is terminated by a signal
135- # (ie. keep waiting if it's merely stopped)
136- while True :
137- try :
138- pid , status = os .waitpid (pid , 0 )
139- except OSError as exc :
140- if not DEBUG :
141- cmd = executable
142- raise DistutilsExecError (
143- "command %r failed: %s" % (cmd , exc .args [- 1 ]))
144- if os .WIFSIGNALED (status ):
145- if not DEBUG :
146- cmd = executable
147- raise DistutilsExecError (
148- "command %r terminated by signal %d"
149- % (cmd , os .WTERMSIG (status )))
150- elif os .WIFEXITED (status ):
151- exit_status = os .WEXITSTATUS (status )
152- if exit_status == 0 :
153- return # hey, it succeeded!
154- else :
155- if not DEBUG :
156- cmd = executable
157- raise DistutilsExecError (
158- "command %r failed with exit status %d"
159- % (cmd , exit_status ))
160- elif os .WIFSTOPPED (status ):
161- continue
162- else :
163- if not DEBUG :
164- cmd = executable
165- raise DistutilsExecError (
166- "unknown error executing %r: termination status %d"
167- % (cmd , status ))
80+ cmd = cmd [0 ]
81+ raise DistutilsExecError (
82+ "command %r failed with exit code %s" % (cmd , exitcode ))
83+
16884
16985def find_executable (executable , path = None ):
17086 """Tries to find 'executable' in the directories listed in 'path'.
0 commit comments