| Greg Ward | b4dbfb3 | 1999-08-14 23:57:17 +0000 | [diff] [blame] | 1 | """distutils.spawn | 
 | 2 |  | 
 | 3 | Provides the 'spawn()' function, a front-end to various platform- | 
 | 4 | specific functions for launching another program in a sub-process.""" | 
 | 5 |  | 
 | 6 | # created 1999/07/24, Greg Ward | 
 | 7 |  | 
 | 8 | __rcsid__ = "$Id$" | 
 | 9 |  | 
 | 10 | import sys, os, string | 
 | 11 | from distutils.errors import * | 
 | 12 |  | 
 | 13 |  | 
 | 14 | def 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 Ward | a4d132a | 1999-09-08 02:23:28 +0000 | [diff] [blame] | 36 |     elif os.name == 'nt': | 
| Greg Ward | 69628b0 | 1999-08-29 18:20:56 +0000 | [diff] [blame] | 37 |         _spawn_nt (cmd, search_path, verbose, dry_run) | 
| Greg Ward | b4dbfb3 | 1999-08-14 23:57:17 +0000 | [diff] [blame] | 38 |     else: | 
 | 39 |         raise DistutilsPlatformError, \ | 
 | 40 |               "don't know how to spawn programs on platform '%s'" % os.name | 
 | 41 |  | 
 | 42 | # spawn () | 
 | 43 |  | 
| Greg Ward | a4d132a | 1999-09-08 02:23:28 +0000 | [diff] [blame] | 44 |  | 
| Greg Ward | 69628b0 | 1999-08-29 18:20:56 +0000 | [diff] [blame] | 45 | def _spawn_nt ( cmd, | 
 | 46 |                 search_path=1, | 
 | 47 |                 verbose=0, | 
 | 48 |                 dry_run=0): | 
| Greg Ward | 69628b0 | 1999-08-29 18:20:56 +0000 | [diff] [blame] | 49 |     executable = cmd[0] | 
 | 50 |     if search_path: | 
 | 51 |         paths = string.split( os.environ['PATH'], os.pathsep) | 
 | 52 |         base,ext = os.path.splitext(executable) | 
 | 53 |         if (ext != '.exe'): | 
 | 54 |             executable = executable + '.exe' | 
 | 55 |         if not os.path.isfile(executable): | 
 | 56 |             paths.reverse()         # go over the paths and keep the last one | 
 | 57 |             for p in paths: | 
 | 58 |                 f = os.path.join( p, executable ) | 
 | 59 |                 if os.path.isfile ( f ): | 
 | 60 |                     # the file exists, we have a shot at spawn working | 
 | 61 |                     executable = f | 
 | 62 |     if verbose: | 
 | 63 |         print string.join ( [executable] + cmd[1:], ' ') | 
 | 64 |     if not dry_run: | 
 | 65 |         # spawn for NT requires a full path to the .exe | 
 | 66 |         rc = os.spawnv (os.P_WAIT, executable, cmd) | 
 | 67 |         if rc != 0: | 
 | 68 |             raise DistutilsExecError("command failed: %d" % rc)  | 
| Greg Ward | b4dbfb3 | 1999-08-14 23:57:17 +0000 | [diff] [blame] | 69 |  | 
| Greg Ward | 69628b0 | 1999-08-29 18:20:56 +0000 | [diff] [blame] | 70 |      | 
 | 71 |                  | 
| Greg Ward | b4dbfb3 | 1999-08-14 23:57:17 +0000 | [diff] [blame] | 72 | def _spawn_posix (cmd, | 
 | 73 |                   search_path=1, | 
 | 74 |                   verbose=0, | 
 | 75 |                   dry_run=0): | 
 | 76 |  | 
 | 77 |     if verbose: | 
 | 78 |         print string.join (cmd, ' ') | 
 | 79 |     if dry_run: | 
 | 80 |         return | 
 | 81 |     exec_fn = search_path and os.execvp or os.execv | 
 | 82 |  | 
 | 83 |     pid = os.fork () | 
 | 84 |  | 
 | 85 |     if pid == 0:                        # in the child | 
 | 86 |         try: | 
 | 87 |             #print "cmd[0] =", cmd[0] | 
 | 88 |             #print "cmd =", cmd | 
 | 89 |             exec_fn (cmd[0], cmd) | 
 | 90 |         except OSError, e: | 
 | 91 |             sys.stderr.write ("unable to execute %s: %s\n" % | 
 | 92 |                               (cmd[0], e.strerror)) | 
 | 93 |             os._exit (1) | 
 | 94 |              | 
 | 95 |         sys.stderr.write ("unable to execute %s for unknown reasons" % cmd[0]) | 
 | 96 |         os._exit (1) | 
 | 97 |  | 
 | 98 |      | 
 | 99 |     else:                               # in the parent | 
 | 100 |         # Loop until the child either exits or is terminated by a signal | 
 | 101 |         # (ie. keep waiting if it's merely stopped) | 
 | 102 |         while 1: | 
 | 103 |             (pid, status) = os.waitpid (pid, 0) | 
 | 104 |             if os.WIFSIGNALED (status): | 
 | 105 |                 raise DistutilsExecError, \ | 
 | 106 |                       "command %s terminated by signal %d" % \ | 
 | 107 |                       (cmd[0], os.WTERMSIG (status)) | 
 | 108 |  | 
 | 109 |             elif os.WIFEXITED (status): | 
 | 110 |                 exit_status = os.WEXITSTATUS (status) | 
 | 111 |                 if exit_status == 0: | 
 | 112 |                     return              # hey, it succeeded! | 
 | 113 |                 else: | 
 | 114 |                     raise DistutilsExecError, \ | 
 | 115 |                           "command %s failed with exit status %d" % \ | 
 | 116 |                           (cmd[0], exit_status) | 
 | 117 |          | 
 | 118 |             elif os.WIFSTOPPED (status): | 
 | 119 |                 continue | 
 | 120 |  | 
 | 121 |             else: | 
 | 122 |                 raise DistutilsExecError, \ | 
 | 123 |                       "unknown error executing %s: termination status %d" % \ | 
 | 124 |                       (cmd[0], status) | 
 | 125 | # _spawn_posix () |