1 #!/usr/bin/env python |
1 #!/usr/bin/env python |
2 # -*- coding: utf-8 -*- |
2 # -*- coding: utf-8 -*- |
3 |
3 |
4 # subset of subprocess built-in module using posix_spawn rather than fork. |
4 # subset of subprocess built-in module using posix_spawn rather than fork. |
5 |
5 |
6 import posix_spawn |
6 from __future__ import absolute_import |
7 import os |
7 import os |
8 import signal |
8 import signal |
|
9 import posix_spawn |
9 |
10 |
10 PIPE = "42" |
11 PIPE = "42" |
11 |
12 |
|
13 |
12 class Popen(object): |
14 class Popen(object): |
13 def __init__(self, args,stdin=None, stdout=None): |
15 def __init__(self, args, stdin=None, stdout=None): |
14 self.returncode = None |
16 self.returncode = None |
15 self.stdout = None |
17 self.stdout = None |
16 self.stdin = None |
18 self.stdin = None |
17 # TODO: stderr |
19 # TODO: stderr |
18 file_actions = posix_spawn.FileActions() |
20 file_actions = posix_spawn.FileActions() |
38 self.stdin = os.fdopen(p2cwrite, 'w') |
40 self.stdin = os.fdopen(p2cwrite, 'w') |
39 os.close(p2cread) |
41 os.close(p2cread) |
40 |
42 |
41 def _wait(self): |
43 def _wait(self): |
42 if self.returncode is None: |
44 if self.returncode is None: |
43 self.returncode = os.waitpid(self.pid,0)[1] |
45 self.returncode = os.waitpid(self.pid, 0)[1] |
44 |
46 |
45 def communicate(self): |
47 def communicate(self): |
46 if self.stdin is not None: |
48 if self.stdin is not None: |
47 self.stdin.close() |
49 self.stdin.close() |
48 self.stdin = None |
50 self.stdin = None |
49 if self.stdout is not None: |
51 if self.stdout is not None: |
50 stdoutdata = self.stdout.read() |
52 stdoutdata = self.stdout.read() |
51 else: |
53 else: |
52 stdoutdata = "" |
54 stdoutdata = "" |
53 |
55 |
54 # TODO |
56 # TODO |
55 stderrdata = "" |
57 stderrdata = "" |
56 |
58 |
57 self._wait() |
59 self._wait() |
58 if self.stdout is not None: |
60 if self.stdout is not None: |
59 self.stdout.close() |
61 self.stdout.close() |
60 self.stdout = None |
62 self.stdout = None |
61 |
63 |
62 return (stdoutdata, stderrdata) |
64 return (stdoutdata, stderrdata) |
63 |
65 |
64 def wait(self): |
66 def wait(self): |
65 if self.stdin is not None: |
67 if self.stdin is not None: |
66 self.stdin.close() |
68 self.stdin.close() |
72 return self.returncode |
74 return self.returncode |
73 |
75 |
74 def poll(self): |
76 def poll(self): |
75 if self.returncode is None: |
77 if self.returncode is None: |
76 pid, ret = os.waitpid(self.pid, os.WNOHANG) |
78 pid, ret = os.waitpid(self.pid, os.WNOHANG) |
77 if (pid,ret) != (0,0): |
79 if (pid, ret) != (0, 0): |
78 self.returncode = ret |
80 self.returncode = ret |
79 |
81 |
80 if self.stdin is not None: |
82 if self.stdin is not None: |
81 self.stdin.close() |
83 self.stdin.close() |
82 self.stdin = None |
84 self.stdin = None |
83 if self.stdout is not None: |
85 if self.stdout is not None: |
84 self.stdout.close() |
86 self.stdout.close() |
85 self.stdout = None |
87 self.stdout = None |
86 |
88 |
87 return self.returncode |
89 return self.returncode |
88 |
90 |
89 def kill(self): |
91 def kill(self): |
90 os.kill(self.pid, signal.SIGKILL) |
92 os.kill(self.pid, signal.SIGKILL) |
91 |
93 |
92 if self.stdin is not None: |
94 if self.stdin is not None: |
93 self.stdin.close() |
95 self.stdin.close() |
94 self.stdin = None |
96 self.stdin = None |
95 if self.stdout is not None: |
97 if self.stdout is not None: |
96 self.stdout.close() |
98 self.stdout.close() |
97 self.stdout = None |
99 self.stdout = None |
98 |
100 |
99 |
|
100 |
101 |
101 def call(*args): |
102 def call(*args): |
102 cmd = [] |
103 cmd = [] |
103 if isinstance(args[0], str): |
104 if isinstance(args[0], str): |
104 if len(args)==1: |
105 if len(args) == 1: |
105 # oversimplified splitting of arguments, |
106 # oversimplified splitting of arguments, |
106 # TODO: care about use of simple and double quotes |
107 # TODO: care about use of simple and double quotes |
107 cmd = args[0].split() |
108 cmd = args[0].split() |
108 else: |
109 else: |
109 cmd = args |
110 cmd = args |
110 elif isinstance(args[0], list) and len(args)==1: |
111 elif isinstance(args[0], list) and len(args) == 1: |
111 cmd = args[0] |
112 cmd = args[0] |
112 else: |
113 else: |
113 raise Exception("Wrong arguments passed to subprocess.call") |
114 raise Exception("Wrong arguments passed to subprocess.call") |
114 pid = posix_spawn.posix_spawnp(cmd[0], cmd) |
115 pid = posix_spawn.posix_spawnp(cmd[0], cmd) |
115 return os.waitpid(pid,0) |
116 return os.waitpid(pid, 0) |
|
117 |
116 |
118 |
117 if __name__ == '__main__': |
119 if __name__ == '__main__': |
118 # unit test |
120 # unit test |
119 |
121 |
120 p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE) |
122 p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE) |
121 p.stdin.write("blah") |
123 p.stdin.write("blah") |
122 p.stdin.close() |
124 p.stdin.close() |
123 print p.stdout.read() |
125 print(p.stdout.read()) |
124 p.wait() |
126 p.wait() |
125 |
127 |
126 p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE) |
128 p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE) |
127 p.stdin.write("blah") |
129 p.stdin.write("blah") |
128 print p.communicate() |
130 print(p.communicate()) |
129 |
131 |
130 call("echo blah0") |
132 call("echo blah0") |
131 call(["echo", "blah1"]) |
133 call(["echo", "blah1"]) |
132 call("echo", "blah2") |
134 call("echo", "blah2") |