|
2 | 2 | from subprocess import Popen, PIPE, STDOUT
|
3 | 3 | from tempfile import mkstemp
|
4 | 4 |
|
5 |
| -# A helper class that is used on Windows to represent the subprocess object that is the return value of Popen. |
6 |
| -class MockPopen: |
7 |
| - def __init__(self, stdout, stderr, returncode): |
8 |
| - self.returncode = returncode |
9 |
| - self.output = (stdout, stderr) |
10 |
| - def communicate(self): |
11 |
| - return self.output |
12 |
| - def poll(self): |
13 |
| - return self.returncode |
14 |
| - def kill(self): |
15 |
| - return # We've already communicate()d the process (waited for its completion), so can't kill() anymore. Therefore this is a no-op. |
16 |
| - |
17 | 5 | # On Windows python suffers from a particularly nasty bug if python is spawning new processes while python itself is spawned from some other non-console process.
|
18 | 6 | # Use a custom replacement for Popen on Windows to avoid the "WindowsError: [Error 6] The handle is invalid" errors when emcc is driven through cmake or mingw32-make.
|
19 | 7 | # See http://bugs.python.org/issue3905
|
20 |
| -def call_process(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, |
21 |
| - shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): |
22 |
| - # (stdin, stdout, stderr) store what the caller originally wanted to be done with the streams. |
23 |
| - # (stdin_, stdout_, stderr_) will store the fixed set of streams that workaround the bug. |
24 |
| - stdin_ = stdin |
25 |
| - stdout_ = stdout |
26 |
| - stderr_ = stderr |
27 |
| - |
28 |
| - # If the caller wants one of these PIPEd, we must PIPE them all to avoid the 'handle is invalid' bug. |
29 |
| - if stdin_ == PIPE or stdout_ == PIPE or stderr_ == PIPE: |
30 |
| - if stdin_ == None: |
31 |
| - stdin_ = PIPE |
32 |
| - if stdout_ == None: |
33 |
| - stdout_ = PIPE |
34 |
| - if stderr_ == None: |
35 |
| - stderr_ = PIPE |
36 |
| - |
37 |
| - # Call the process with fixed streams. |
38 |
| - process = subprocess.Popen(args, bufsize, executable, stdin_, stdout_, stderr_, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags) |
39 |
| - output = process.communicate() |
40 |
| - |
41 |
| - # If caller never wanted to PIPE stdout or stderr, route the output back to screen to avoid swallowing output. |
42 |
| - if stdout == None and stdout_ == PIPE and len(output[0].strip()) > 0: |
43 |
| - print >> sys.stdout, output[0] |
44 |
| - if stderr == None and stderr_ == PIPE and len(output[1].strip()) > 0: |
45 |
| - print >> sys.stderr, output[1] |
| 8 | +class WindowsPopen: |
| 9 | + def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, |
| 10 | + shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): |
| 11 | + self.stdin = stdin |
| 12 | + self.stdout = stdout |
| 13 | + self.stderr = stderr |
| 14 | + |
| 15 | + # (stdin, stdout, stderr) store what the caller originally wanted to be done with the streams. |
| 16 | + # (stdin_, stdout_, stderr_) will store the fixed set of streams that workaround the bug. |
| 17 | + self.stdin_ = stdin |
| 18 | + self.stdout_ = stdout |
| 19 | + self.stderr_ = stderr |
| 20 | + |
| 21 | + # If the caller wants one of these PIPEd, we must PIPE them all to avoid the 'handle is invalid' bug. |
| 22 | + if self.stdin_ == PIPE or self.stdout_ == PIPE or self.stderr_ == PIPE: |
| 23 | + if self.stdin_ == None: |
| 24 | + self.stdin_ = PIPE |
| 25 | + if self.stdout_ == None: |
| 26 | + self.stdout_ = PIPE |
| 27 | + if self.stderr_ == None: |
| 28 | + self.stderr_ = PIPE |
46 | 29 |
|
47 |
| - # Return a mock object to the caller. This works as long as all emscripten code immediately .communicate()s the result, and doesn't |
48 |
| - # leave the process object around for longer/more exotic uses. |
49 |
| - if stdout == None and stderr == None: |
50 |
| - return MockPopen(None, None, process.returncode) |
51 |
| - if stdout == None: |
52 |
| - return MockPopen(None, output[1], process.returncode) |
53 |
| - if stderr == None: |
54 |
| - return MockPopen(output[0], None, process.returncode) |
55 |
| - return MockPopen(output[0], output[1], process.returncode) |
| 30 | + # Call the process with fixed streams. |
| 31 | + self.process = subprocess.Popen(args, bufsize, executable, self.stdin_, self.stdout_, self.stderr_, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags) |
| 32 | + |
| 33 | + def communicate(self, input=None): |
| 34 | + output = self.process.communicate(input) |
| 35 | + self.returncode = self.process.returncode |
| 36 | + |
| 37 | + # If caller never wanted to PIPE stdout or stderr, route the output back to screen to avoid swallowing output. |
| 38 | + if self.stdout == None and self.stdout_ == PIPE and len(output[0].strip()) > 0: |
| 39 | + print >> sys.stdout, output[0] |
| 40 | + if self.stderr == None and self.stderr_ == PIPE and len(output[1].strip()) > 0: |
| 41 | + print >> sys.stderr, output[1] |
| 42 | + |
| 43 | + # Return a mock object to the caller. This works as long as all emscripten code immediately .communicate()s the result, and doesn't |
| 44 | + # leave the process object around for longer/more exotic uses. |
| 45 | + if self.stdout == None and self.stderr == None: |
| 46 | + return (None, None) |
| 47 | + if self.stdout == None: |
| 48 | + return (None, output[1]) |
| 49 | + if self.stderr == None: |
| 50 | + return (output[0], None) |
| 51 | + return (output[0], output[1]) |
| 52 | + |
| 53 | + def poll(self): |
| 54 | + return self.process.returncode |
| 55 | + |
| 56 | + def kill(self): |
| 57 | + return self.process.kill |
56 | 58 |
|
57 | 59 | # Install our replacement Popen handler if we are running on Windows to avoid python spawn process function.
|
58 | 60 | if os.name == 'nt':
|
59 |
| - Popen = call_process |
| 61 | + Popen = WindowsPopen |
60 | 62 |
|
61 | 63 | import js_optimizer
|
62 | 64 |
|
|
0 commit comments