blob: 651124d6825a26c7f544209208d3bc745addfd0a [file] [log] [blame]
Greg Wardb4dbfb31999-08-14 23:57:17 +00001"""distutils.spawn
2
3Provides the 'spawn()' function, a front-end to various platform-
Greg Ward88608ca2000-08-02 01:08:02 +00004specific functions for launching another program in a sub-process.
5Also provides the 'find_executable()' to search the path for a given
6executable name. """
Greg Wardb4dbfb31999-08-14 23:57:17 +00007
8# created 1999/07/24, Greg Ward
9
Greg Ward3ce77fd2000-03-02 01:49:45 +000010__revision__ = "$Id$"
Greg Wardb4dbfb31999-08-14 23:57:17 +000011
12import sys, os, string
13from distutils.errors import *
14
15
16def spawn (cmd,
17 search_path=1,
18 verbose=0,
19 dry_run=0):
20
21 """Run another program, specified as a command list 'cmd', in a new
22 process. 'cmd' is just the argument list for the new process, ie.
23 cmd[0] is the program to run and cmd[1:] are the rest of its
24 arguments. There is no way to run a program with a name different
25 from that of its executable.
26
27 If 'search_path' is true (the default), the system's executable
28 search path will be used to find the program; otherwise, cmd[0] must
29 be the exact path to the executable. If 'verbose' is true, a
30 one-line summary of the command will be printed before it is run.
31 If 'dry_run' is true, the command will not actually be run.
32
33 Raise DistutilsExecError if running the program fails in any way;
34 just return on success."""
35
36 if os.name == 'posix':
37 _spawn_posix (cmd, search_path, verbose, dry_run)
Greg Warda4d132a1999-09-08 02:23:28 +000038 elif os.name == 'nt':
Greg Ward69628b01999-08-29 18:20:56 +000039 _spawn_nt (cmd, search_path, verbose, dry_run)
Greg Wardb4dbfb31999-08-14 23:57:17 +000040 else:
41 raise DistutilsPlatformError, \
42 "don't know how to spawn programs on platform '%s'" % os.name
43
44# spawn ()
45
Greg Warda4d132a1999-09-08 02:23:28 +000046
Greg Warde2b44522000-03-07 03:25:20 +000047def _nt_quote_args (args):
48 """Obscure quoting command line arguments on NT.
49 Simply quote every argument which contains blanks."""
50
51 # XXX this doesn't seem very robust to me -- but if the Windows guys
52 # say it'll work, I guess I'll have to accept it. (What if an arg
53 # contains quotes? What other magic characters, other than spaces,
54 # have to be escaped? Is there an escaping mechanism other than
55 # quoting?)
56
57 for i in range (len (args)):
Greg Warde2a33072000-03-23 04:38:36 +000058 if string.find (args[i], ' ') != -1:
Greg Warde2b44522000-03-07 03:25:20 +000059 args[i] = '"%s"' % args[i]
Greg Warda3c8bf32000-03-26 21:47:00 +000060 return args
Greg Warde2b44522000-03-07 03:25:20 +000061
62def _spawn_nt (cmd,
63 search_path=1,
64 verbose=0,
65 dry_run=0):
66
Greg Ward69628b01999-08-29 18:20:56 +000067 executable = cmd[0]
Greg Warde2b44522000-03-07 03:25:20 +000068 cmd = _nt_quote_args (cmd)
Greg Ward69628b01999-08-29 18:20:56 +000069 if search_path:
Greg Ward88608ca2000-08-02 01:08:02 +000070 # either we find one or it stays the same
71 executable = find_executable(executable) or executable
Greg Ward69628b01999-08-29 18:20:56 +000072 if verbose:
Greg Warde2b44522000-03-07 03:25:20 +000073 print string.join ([executable] + cmd[1:], ' ')
Greg Ward69628b01999-08-29 18:20:56 +000074 if not dry_run:
75 # spawn for NT requires a full path to the .exe
Greg Ward3b49c9b2000-01-17 21:57:55 +000076 try:
77 rc = os.spawnv (os.P_WAIT, executable, cmd)
78 except OSError, exc:
79 # this seems to happen when the command isn't found
80 raise DistutilsExecError, \
81 "command '%s' failed: %s" % (cmd[0], exc[-1])
Greg Ward69628b01999-08-29 18:20:56 +000082 if rc != 0:
Greg Ward3b49c9b2000-01-17 21:57:55 +000083 # and this reflects the command running but failing
84 raise DistutilsExecError, \
85 "command '%s' failed with exit status %d" % (cmd[0], rc)
Greg Wardb4dbfb31999-08-14 23:57:17 +000086
Greg Ward69628b01999-08-29 18:20:56 +000087
Greg Wardb4dbfb31999-08-14 23:57:17 +000088def _spawn_posix (cmd,
89 search_path=1,
90 verbose=0,
91 dry_run=0):
92
93 if verbose:
94 print string.join (cmd, ' ')
95 if dry_run:
96 return
97 exec_fn = search_path and os.execvp or os.execv
98
99 pid = os.fork ()
100
101 if pid == 0: # in the child
102 try:
103 #print "cmd[0] =", cmd[0]
104 #print "cmd =", cmd
105 exec_fn (cmd[0], cmd)
106 except OSError, e:
107 sys.stderr.write ("unable to execute %s: %s\n" %
108 (cmd[0], e.strerror))
109 os._exit (1)
110
111 sys.stderr.write ("unable to execute %s for unknown reasons" % cmd[0])
112 os._exit (1)
113
114
115 else: # in the parent
116 # Loop until the child either exits or is terminated by a signal
117 # (ie. keep waiting if it's merely stopped)
118 while 1:
119 (pid, status) = os.waitpid (pid, 0)
120 if os.WIFSIGNALED (status):
121 raise DistutilsExecError, \
Greg Ward3b49c9b2000-01-17 21:57:55 +0000122 "command '%s' terminated by signal %d" % \
Greg Wardb4dbfb31999-08-14 23:57:17 +0000123 (cmd[0], os.WTERMSIG (status))
124
125 elif os.WIFEXITED (status):
126 exit_status = os.WEXITSTATUS (status)
127 if exit_status == 0:
128 return # hey, it succeeded!
129 else:
130 raise DistutilsExecError, \
Greg Ward3b49c9b2000-01-17 21:57:55 +0000131 "command '%s' failed with exit status %d" % \
Greg Wardb4dbfb31999-08-14 23:57:17 +0000132 (cmd[0], exit_status)
133
134 elif os.WIFSTOPPED (status):
135 continue
136
137 else:
138 raise DistutilsExecError, \
Greg Ward3b49c9b2000-01-17 21:57:55 +0000139 "unknown error executing '%s': termination status %d" % \
Greg Wardb4dbfb31999-08-14 23:57:17 +0000140 (cmd[0], status)
141# _spawn_posix ()
Greg Ward88608ca2000-08-02 01:08:02 +0000142
143
144def find_executable(executable, path=None):
145 """Try to find 'executable' in the directories listed in 'path' (a
146 string listing directories separated by 'os.pathsep'; defaults to
147 os.environ['PATH']). Returns the complete filename or None if not
148 found.
149 """
150 if path is None:
151 path = os.environ['PATH']
152 paths = string.split(path, os.pathsep)
153 (base, ext) = os.path.splitext(executable)
154 if (sys.platform == 'win32') and (ext != '.exe'):
155 executable = executable + '.exe'
156 if not os.path.isfile(executable):
157 for p in paths:
158 f = os.path.join(p, executable)
159 if os.path.isfile(f):
160 # the file exists, we have a shot at spawn working
161 return f
162 return None
163 else:
164 return executable
165
166# find_executable()