| 
									
										
										
										
											1999-08-14 23:57:17 +00:00
										 |  |  | """distutils.spawn
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Provides the 'spawn()' function, a front-end to various platform- | 
					
						
							|  |  |  | specific functions for launching another program in a sub-process."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # created 1999/07/24, Greg Ward | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-02 01:49:45 +00:00
										 |  |  | __revision__ = "$Id$" | 
					
						
							| 
									
										
										
										
											1999-08-14 23:57:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import sys, os, string | 
					
						
							|  |  |  | from distutils.errors import * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def spawn (cmd, | 
					
						
							|  |  |  |            search_path=1, | 
					
						
							|  |  |  |            verbose=0, | 
					
						
							|  |  |  |            dry_run=0): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """Run another program, specified as a command list 'cmd', in a new
 | 
					
						
							|  |  |  |        process.  'cmd' is just the argument list for the new process, ie. | 
					
						
							|  |  |  |        cmd[0] is the program to run and cmd[1:] are the rest of its | 
					
						
							|  |  |  |        arguments.  There is no way to run a program with a name different | 
					
						
							|  |  |  |        from that of its executable. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        If 'search_path' is true (the default), the system's executable | 
					
						
							|  |  |  |        search path will be used to find the program; otherwise, cmd[0] must | 
					
						
							|  |  |  |        be the exact path to the executable.  If 'verbose' is true, a | 
					
						
							|  |  |  |        one-line summary of the command will be printed before it is run. | 
					
						
							|  |  |  |        If 'dry_run' is true, the command will not actually be run. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        Raise DistutilsExecError if running the program fails in any way; | 
					
						
							|  |  |  |        just return on success."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if os.name == 'posix': | 
					
						
							|  |  |  |         _spawn_posix (cmd, search_path, verbose, dry_run) | 
					
						
							| 
									
										
										
										
											1999-09-08 02:23:28 +00:00
										 |  |  |     elif os.name == 'nt': | 
					
						
							| 
									
										
										
										
											1999-08-29 18:20:56 +00:00
										 |  |  |         _spawn_nt (cmd, search_path, verbose, dry_run) | 
					
						
							| 
									
										
										
										
											1999-08-14 23:57:17 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         raise DistutilsPlatformError, \ | 
					
						
							|  |  |  |               "don't know how to spawn programs on platform '%s'" % os.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # spawn () | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-09-08 02:23:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-07 03:25:20 +00:00
										 |  |  | def _nt_quote_args (args): | 
					
						
							|  |  |  |     """Obscure quoting command line arguments on NT.
 | 
					
						
							|  |  |  |        Simply quote every argument which contains blanks."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # XXX this doesn't seem very robust to me -- but if the Windows guys | 
					
						
							|  |  |  |     # say it'll work, I guess I'll have to accept it.  (What if an arg | 
					
						
							|  |  |  |     # contains quotes?  What other magic characters, other than spaces, | 
					
						
							|  |  |  |     # have to be escaped?  Is there an escaping mechanism other than | 
					
						
							|  |  |  |     # quoting?) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for i in range (len (args)): | 
					
						
							|  |  |  |         if string.find (args[i], ' ') == -1: | 
					
						
							|  |  |  |             args[i] = '"%s"' % args[i] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _spawn_nt (cmd, | 
					
						
							|  |  |  |                search_path=1, | 
					
						
							|  |  |  |                verbose=0, | 
					
						
							|  |  |  |                dry_run=0): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-08-29 18:20:56 +00:00
										 |  |  |     executable = cmd[0] | 
					
						
							| 
									
										
										
										
											2000-03-07 03:25:20 +00:00
										 |  |  |     cmd = _nt_quote_args (cmd) | 
					
						
							| 
									
										
										
										
											1999-08-29 18:20:56 +00:00
										 |  |  |     if search_path: | 
					
						
							|  |  |  |         paths = string.split( os.environ['PATH'], os.pathsep) | 
					
						
							|  |  |  |         base,ext = os.path.splitext(executable) | 
					
						
							|  |  |  |         if (ext != '.exe'): | 
					
						
							|  |  |  |             executable = executable + '.exe' | 
					
						
							|  |  |  |         if not os.path.isfile(executable): | 
					
						
							|  |  |  |             paths.reverse()         # go over the paths and keep the last one | 
					
						
							|  |  |  |             for p in paths: | 
					
						
							|  |  |  |                 f = os.path.join( p, executable ) | 
					
						
							|  |  |  |                 if os.path.isfile ( f ): | 
					
						
							|  |  |  |                     # the file exists, we have a shot at spawn working | 
					
						
							|  |  |  |                     executable = f | 
					
						
							|  |  |  |     if verbose: | 
					
						
							| 
									
										
										
										
											2000-03-07 03:25:20 +00:00
										 |  |  |         print string.join ([executable] + cmd[1:], ' ') | 
					
						
							| 
									
										
										
										
											1999-08-29 18:20:56 +00:00
										 |  |  |     if not dry_run: | 
					
						
							|  |  |  |         # spawn for NT requires a full path to the .exe | 
					
						
							| 
									
										
										
										
											2000-01-17 21:57:55 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             rc = os.spawnv (os.P_WAIT, executable, cmd) | 
					
						
							|  |  |  |         except OSError, exc: | 
					
						
							|  |  |  |             # this seems to happen when the command isn't found | 
					
						
							|  |  |  |             raise DistutilsExecError, \ | 
					
						
							|  |  |  |                   "command '%s' failed: %s" % (cmd[0], exc[-1]) | 
					
						
							| 
									
										
										
										
											1999-08-29 18:20:56 +00:00
										 |  |  |         if rc != 0: | 
					
						
							| 
									
										
										
										
											2000-01-17 21:57:55 +00:00
										 |  |  |             # and this reflects the command running but failing | 
					
						
							|  |  |  |             raise DistutilsExecError, \ | 
					
						
							|  |  |  |                   "command '%s' failed with exit status %d" % (cmd[0], rc) | 
					
						
							| 
									
										
										
										
											1999-08-14 23:57:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-08-29 18:20:56 +00:00
										 |  |  |      | 
					
						
							|  |  |  |                  | 
					
						
							| 
									
										
										
										
											1999-08-14 23:57:17 +00:00
										 |  |  | def _spawn_posix (cmd, | 
					
						
							|  |  |  |                   search_path=1, | 
					
						
							|  |  |  |                   verbose=0, | 
					
						
							|  |  |  |                   dry_run=0): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if verbose: | 
					
						
							|  |  |  |         print string.join (cmd, ' ') | 
					
						
							|  |  |  |     if dry_run: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     exec_fn = search_path and os.execvp or os.execv | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pid = os.fork () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if pid == 0:                        # in the child | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             #print "cmd[0] =", cmd[0] | 
					
						
							|  |  |  |             #print "cmd =", cmd | 
					
						
							|  |  |  |             exec_fn (cmd[0], cmd) | 
					
						
							|  |  |  |         except OSError, e: | 
					
						
							|  |  |  |             sys.stderr.write ("unable to execute %s: %s\n" % | 
					
						
							|  |  |  |                               (cmd[0], e.strerror)) | 
					
						
							|  |  |  |             os._exit (1) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |         sys.stderr.write ("unable to execute %s for unknown reasons" % cmd[0]) | 
					
						
							|  |  |  |         os._exit (1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     else:                               # in the parent | 
					
						
							|  |  |  |         # Loop until the child either exits or is terminated by a signal | 
					
						
							|  |  |  |         # (ie. keep waiting if it's merely stopped) | 
					
						
							|  |  |  |         while 1: | 
					
						
							|  |  |  |             (pid, status) = os.waitpid (pid, 0) | 
					
						
							|  |  |  |             if os.WIFSIGNALED (status): | 
					
						
							|  |  |  |                 raise DistutilsExecError, \ | 
					
						
							| 
									
										
										
										
											2000-01-17 21:57:55 +00:00
										 |  |  |                       "command '%s' terminated by signal %d" % \ | 
					
						
							| 
									
										
										
										
											1999-08-14 23:57:17 +00:00
										 |  |  |                       (cmd[0], os.WTERMSIG (status)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             elif os.WIFEXITED (status): | 
					
						
							|  |  |  |                 exit_status = os.WEXITSTATUS (status) | 
					
						
							|  |  |  |                 if exit_status == 0: | 
					
						
							|  |  |  |                     return              # hey, it succeeded! | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     raise DistutilsExecError, \ | 
					
						
							| 
									
										
										
										
											2000-01-17 21:57:55 +00:00
										 |  |  |                           "command '%s' failed with exit status %d" % \ | 
					
						
							| 
									
										
										
										
											1999-08-14 23:57:17 +00:00
										 |  |  |                           (cmd[0], exit_status) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |             elif os.WIFSTOPPED (status): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 raise DistutilsExecError, \ | 
					
						
							| 
									
										
										
										
											2000-01-17 21:57:55 +00:00
										 |  |  |                       "unknown error executing '%s': termination status %d" % \ | 
					
						
							| 
									
										
										
										
											1999-08-14 23:57:17 +00:00
										 |  |  |                       (cmd[0], status) | 
					
						
							|  |  |  | # _spawn_posix () |