spawn.py revision a4d132a868902ee2f1d73bf50de7af229ae72991
1"""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
8__rcsid__ = "$Id$"
9
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)
36    elif os.name == 'nt':
37        _spawn_nt (cmd, search_path, verbose, dry_run)
38    else:
39        raise DistutilsPlatformError, \
40              "don't know how to spawn programs on platform '%s'" % os.name
41
42# spawn ()
43
44
45def _spawn_nt ( cmd,
46                search_path=1,
47                verbose=0,
48                dry_run=0):
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)
69
70
71
72def _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 ()
126