1 __all__ = ['Process', 'sh', 'AlreadyExecuted', 'InvalidCommand']
2
3 import os
4 import shlex
5 from cStringIO import StringIO
6 from subprocess import Popen, PIPE
9 """A command that doesn't exist has been called."""
11 """A command that doesn't exist has been called."""
12
14 """
15 Turn the C{cmd} into a list suitable for subprocess.
16
17 @param cmd: The command to be split into a list
18 @type cmd: str, list
19 @return: The split command, or the command passed if no splitting was
20 necessary
21 @rtype: list
22 """
23 if isinstance(cmd, (str, unicode)):
24 cmd = shlex.split(cmd)
25 return cmd
26
28 """
29 A wrapper for subprocess.Popen that allows bash-like pipe syntax and
30 simplified output retrieval.
31
32 Processes will be executed automatically when and if stdout, stderr or a
33 return code are requested. This removes the necessity of calling
34 C{Popen().wait()} manually, or of capturing stdout and stderr from a
35 C{communicate()} call. A small change, to be sure, but it helps reduce
36 overhead for a common pattern.
37
38 One may use the C{|} operator to pipe the output of one L{Process} into
39 another:
40
41 >>> p = Process("echo 'one two three'") | Process("wc -w")
42 >>> print p.stdout
43 3
44
45 """
46 _stdin = PIPE
47 _stdout = PIPE
48 _stderr = PIPE
49 _retcode = None
50
52 """
53 @param cmd: A string or list containing the command to be executed.
54 @type cmd: str, list
55 @param stdin: An optional open file object representing input to the
56 process.
57 @type stdin: file
58 @rtype: void
59 """
60 self._command = _normalize(cmd)
61 if stdin is not None:
62 self._stdin = stdin
63 self._refreshProcess()
64
66 """
67 Shortcut to get process output.
68
69 @return: Process output
70 @rtype: str
71 """
72 return self.stdout
73
75 """
76 Override default C{or} comparison so that the C{|} operator will work.
77 Don't call this directly.
78
79 @return: Process with C{self}'s stdin as stdout pipe.
80 @rtype: L{Process}
81 """
82 if self.hasExecuted or proc.hasExecuted:
83 raise AlreadyExecuted("You can't pipe processes after they've been"
84 "executed.")
85 proc._stdin = self._process.stdout
86 proc._refreshProcess()
87 return proc
88
89 @property
91 """
92 A boolean indicating whether or not the process has already run.
93
94 @rtype: bool
95 """
96 return self._retcode is not None
97
110
114
117
120
121 @property
123 """
124 Retrieve the contents of stdout, executing the process first if
125 necessary.
126
127 @return: The process output
128 @rtype: str
129 """
130 self._execute()
131 if not hasattr(self, '_stdoutstorage'):
132 self._stdoutstorage = StringIO(self._process.stdout.read().strip())
133 return self._stdoutstorage.getvalue()
134
135 @property
137 """
138 Retrieve the contents of stderr, executing the process first if
139 necessary.
140
141 @rtype: str
142 @return: The process error output
143 """
144 self._execute()
145 if not hasattr(self, '_stderrstorage'):
146 self._stdoutstorage = StringIO(self._process.stderr.read().strip())
147 return self._stderrstorage.getvalue()
148
149 @property
151 """
152 Get the exit code of the executed process, executing the process
153 first if necessary.
154
155 @rtype: int
156 @return: The exit code of the process
157 """
158 self._execute()
159 return self._retcode
160
161 @property
163 """
164 Get the pid of the executed process.
165
166 @return: The process pid
167 @rtype: int
168 """
169 self._execute()
170 return self._process.pid
171
173 """
174 Make dead sure the process has been cleaned up when garbage is
175 collected.
176 """
177 if self.hasExecuted:
178 try: os.kill(self.pid, 9)
179 except: pass
180
183 """
184 Singleton class that creates Process objects for commands passed.
185
186 Not meant to be instantiated; use the C{sh} instance.
187
188 >>> p = sh.wc("-w")
189 >>> p.__class__
190 <class 'cliutils.process.Process'>
191 >>> p._command
192 ['wc', '-w']
193
194 """
196 def inner(cmd=()):
197 command = [attr]
198 command.extend(_normalize(cmd))
199 return Process(command)
200 return inner
201 sh = _shell()
202