blob: 86ea3dfb501a0d744d0c2d05e76cf2103ed8983a [file] [log] [blame]
Greg Wardb4dbfb31999-08-14 23:57:17 +00001"""distutils.spawn
2
3Provides the 'spawn()' function, a front-end to various platform-
4specific functions for launching another program in a sub-process."""
5
6# created 1999/07/24, Greg Ward
7
Greg Ward3ce77fd2000-03-02 01:49:45 +00008__revision__ = "$Id$"
Greg Wardb4dbfb31999-08-14 23:57:17 +00009
10import sys, os, string
11from distutils.errors import *
12
13
14def spawn (cmd,
15 search_path=1,
16 verbose=0,
17 dry_run=0):
18
19 """Run another program, specified as a command list 'cmd', in a new
20 process. 'cmd' is just the argument list for the new process, ie.
21 cmd[0] is the program to run and cmd[1:] are the rest of its
22 arguments. There is no way to run a program with a name different
23 from that of its executable.
24
25 If 'search_path' is true (the default), the system's executable
26 search path will be used to find the program; otherwise, cmd[0] must
27 be the exact path to the executable. If 'verbose' is true, a
28 one-line summary of the command will be printed before it is run.
29 If 'dry_run' is true, the command will not actually be run.
30
31 Raise DistutilsExecError if running the program fails in any way;
32 just return on success."""
33
34 if os.name == 'posix':
35 _spawn_posix (cmd, search_path, verbose, dry_run)
Greg Warda4d132a1999-09-08 02:23:28 +000036 elif os.name == 'nt':
Greg Ward69628b01999-08-29 18:20:56 +000037 _spawn_nt (cmd, search_path, verbose, dry_run)
Greg Wardb4dbfb31999-08-14 23:57:17 +000038 else:
39 raise DistutilsPlatformError, \
40 "don't know how to spawn programs on platform '%s'" % os.name
41
42# spawn ()
43
Greg Warda4d132a1999-09-08 02:23:28 +000044
Greg Warde2b44522000-03-07 03:25:20 +000045def _nt_quote_args (args):
46 """Obscure quoting command line arguments on NT.
47 Simply quote every argument which contains blanks."""
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
55 for i in range (len (args)):
Greg Warde2a33072000-03-23 04:38:36 +000056 if string.find (args[i], ' ') != -1:
Greg Warde2b44522000-03-07 03:25:20 +000057 args[i] = '"%s"' % args[i]
Greg Warda3c8bf32000-03-26 21:47:00 +000058 return args
Greg Warde2b44522000-03-07 03:25:20 +000059
60def _spawn_nt (cmd,
61 search_path=1,
62 verbose=0,
63 dry_run=0):
64
Greg Ward69628b01999-08-29 18:20:56 +000065 executable = cmd[0]
Greg Warde2b44522000-03-07 03:25:20 +000066 cmd = _nt_quote_args (cmd)
Greg Ward69628b01999-08-29 18:20:56 +000067 if search_path:
68 paths = string.split( os.environ['PATH'], os.pathsep)
69 base,ext = os.path.splitext(executable)
70 if (ext != '.exe'):
71 executable = executable + '.exe'
72 if not os.path.isfile(executable):
73 paths.reverse() # go over the paths and keep the last one
74 for p in paths:
75 f = os.path.join( p, executable )
76 if os.path.isfile ( f ):
77 # the file exists, we have a shot at spawn working
78 executable = f
79 if verbose:
Greg Warde2b44522000-03-07 03:25:20 +000080 print string.join ([executable] + cmd[1:], ' ')
Greg Ward69628b01999-08-29 18:20:56 +000081 if not dry_run:
82 # spawn for NT requires a full path to the .exe
Greg Ward3b49c9b2000-01-17 21:57:55 +000083 try:
84 rc = os.spawnv (os.P_WAIT, executable, cmd)
85 except OSError, exc:
86 # this seems to happen when the command isn't found
87 raise DistutilsExecError, \
88 "command '%s' failed: %s" % (cmd[0], exc[-1])
Greg Ward69628b01999-08-29 18:20:56 +000089 if rc != 0:
Greg Ward3b49c9b2000-01-17 21:57:55 +000090 # and this reflects the command running but failing
91 raise DistutilsExecError, \
92 "command '%s' failed with exit status %d" % (cmd[0], rc)
Greg Wardb4dbfb31999-08-14 23:57:17 +000093
Greg Ward69628b01999-08-29 18:20:56 +000094
95
Greg Wardb4dbfb31999-08-14 23:57:17 +000096def _spawn_posix (cmd,
97 search_path=1,
98 verbose=0,
99 dry_run=0):
100
101 if verbose:
102 print string.join (cmd, ' ')
103 if dry_run:
104 return
105 exec_fn = search_path and os.execvp or os.execv
106
107 pid = os.fork ()
108
109 if pid == 0: # in the child
110 try:
111 #print "cmd[0] =", cmd[0]
112 #print "cmd =", cmd
113 exec_fn (cmd[0], cmd)
114 except OSError, e:
115 sys.stderr.write ("unable to execute %s: %s\n" %
116 (cmd[0], e.strerror))
117 os._exit (1)
118
119 sys.stderr.write ("unable to execute %s for unknown reasons" % cmd[0])
120 os._exit (1)
121
122
123 else: # in the parent
124 # Loop until the child either exits or is terminated by a signal
125 # (ie. keep waiting if it's merely stopped)
126 while 1:
127 (pid, status) = os.waitpid (pid, 0)
128 if os.WIFSIGNALED (status):
129 raise DistutilsExecError, \
Greg Ward3b49c9b2000-01-17 21:57:55 +0000130 "command '%s' terminated by signal %d" % \
Greg Wardb4dbfb31999-08-14 23:57:17 +0000131 (cmd[0], os.WTERMSIG (status))
132
133 elif os.WIFEXITED (status):
134 exit_status = os.WEXITSTATUS (status)
135 if exit_status == 0:
136 return # hey, it succeeded!
137 else:
138 raise DistutilsExecError, \
Greg Ward3b49c9b2000-01-17 21:57:55 +0000139 "command '%s' failed with exit status %d" % \
Greg Wardb4dbfb31999-08-14 23:57:17 +0000140 (cmd[0], exit_status)
141
142 elif os.WIFSTOPPED (status):
143 continue
144
145 else:
146 raise DistutilsExecError, \
Greg Ward3b49c9b2000-01-17 21:57:55 +0000147 "unknown error executing '%s': termination status %d" % \
Greg Wardb4dbfb31999-08-14 23:57:17 +0000148 (cmd[0], status)
149# _spawn_posix ()