8
8
9
9
import sys
10
10
import os
11
+ import subprocess
11
12
12
13
from distutils .errors import DistutilsPlatformError , DistutilsExecError
13
14
from distutils .debug import DEBUG
14
15
from distutils import log
15
16
17
+
18
+ if sys .platform == 'darwin' :
19
+ _cfg_target = None
20
+ _cfg_target_split = None
21
+
22
+
16
23
def spawn (cmd , search_path = 1 , verbose = 0 , dry_run = 0 ):
17
24
"""Run another program, specified as a command list 'cmd', in a new process.
18
25
@@ -32,64 +39,16 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0):
32
39
# cmd is documented as a list, but just in case some code passes a tuple
33
40
# in, protect our %-formatting code against horrible death
34
41
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
86
42
87
- def _spawn_posix (cmd , search_path = 1 , verbose = 0 , dry_run = 0 ):
88
43
log .info (' ' .join (cmd ))
89
44
if dry_run :
90
45
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
+
93
52
env = None
94
53
if sys .platform == 'darwin' :
95
54
global _cfg_target , _cfg_target_split
@@ -111,60 +70,17 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
111
70
raise DistutilsPlatformError (my_msg )
112
71
env = dict (os .environ ,
113
72
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 )
128
73
74
+ proc = subprocess .Popen (cmd , env = env )
75
+ proc .wait ()
76
+ exitcode = proc .returncode
77
+
78
+ if exitcode :
129
79
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
+
168
84
169
85
def find_executable (executable , path = None ):
170
86
"""Tries to find 'executable' in the directories listed in 'path'.
0 commit comments