1 """Run a Linux command and capture the result.
2 This module is thread-safe.
3
4 Other than the *_raw functions, these functions ignore comments lines
5 (e.g. ones starting with '#'), and if they see a line beginning with
6 an error prefix, they raise an L{ExecError} exception. The default
7 error prefix is L{ERR}, but you can set it for each call.
8 Likewise, the default comment prefix is L{COMMENT}, but you can also set
9 it with the C{comment} argument of any call.
10
11 The basic idea is that
12 - you start a subprocess.
13 - you feed in a bunch of strings (one at a time) to its standard
14 input. (These come from the C{input} argument.
15 You need to know, in advance, how much data to feed it.)
16 Note that newlines are not added to the C{input} entries,
17 so if you want the strings to be lines, they ought to end
18 in a newline.
19 - then loop over this:
20 - if C{perline} is not None, it feeds the subprocess's standard input
21 a string, taken from C{perline}. (Note that newlines are not
22 added; you need to include them if you want them, and you
23 probably want them.)
24 - it produces an output line
25 - repeat
26 - keep reading until the subprocess closes its standard output.
27 When C{perline} is empty, the subprocess's standard input is closed.
28 These functions continue reading the subprocess's output as long
29 as it keeps producing.
30
31 So, you can do this::
32
33 get(None, ['pwd']) # "/home/gpk/whatever"
34 getall(None, ['ls']) # Yields a listing of your directory
35 get(None, ['sum'], input=['wurgle']) # Same as typing "echo wurgle | sum" to bash.
36 getall(None, ['cat'], input=['wurgle\n'], perline=['biffle\n']) == ['wurgle\n', 'biffle\n']
37 """
38
39 import g_pipe
40
42 """Something went wrong. The subprocess did not produce
43 output when some was expected, or it generated an
44 error line (see L{ERR}, C{err} argument).
45 Perhaps, some of the input that you supplied could not be used.
46 Also, pipe creation might have failed.
47 """
48
51
52
53
54 ERR = 'ERR:'
55 COMMENT = '#'
56
57
58 -def getiter_raw(s, argv, input=None, perline=None, debug=False):
59 """Read a list of lines from a subprocess.
60
61 @note: If input or perline is badly chosen, one can
62 produce a locked loop of pipes. (Locked loops happen when you have
63 too much stuff waiting to be processed.)
64 @param s: the name of the program to execute. (Or L{None}, in
65 which case, it is taken from C{argv[0]}).
66 @type s: C{str} or L{None}
67 @param argv: an array of argument to execute.
68 @type argv: C{list(str)}
69 @param input: strings to feed
70 to the subprocess on startup, before the first output is read.
71 These are sent to the subprocess's standard input.
72 @type input: array, sequence or iterator, containing strings
73 @param perline: is a sequence/iterator of strings to feed in, one at a time,
74 as the subprocess is producing data. (These are fed to the subprocess's
75 standard input, one after each output line that it produces.)
76 @type perline: array, sequence or iterator, containing strings
77 @return: a sequence of the lines of output that the program produced.
78 (Newlines are not removed.)
79 @rtype: a generator of strings.
80 @param debug: Should it print some debugging information?
81 @type debug: bool
82 @raise ExecError: ZZZ
83 """
84
85 if s is None:
86 s = argv[0]
87
88 if debug:
89 print '#OPENING', s, argv
90 wpipe, rpipe = g_pipe.popen2(s, argv)
91
92 if wpipe is None or rpipe is None:
93 raise ExecError('Cannot spawn pipe for {%s}' % s, *argv)
94 if input is not None:
95 if debug:
96 for t in input:
97 print '#WRITING <%s>' % t
98 wpipe.write(t)
99 else:
100 for t in input:
101 wpipe.write(t)
102
103 if perline is None:
104 wpipe.close()
105 wpipe = None
106 else:
107 wpipe.flush()
108 perline = perline.__iter__()
109
110 while True:
111 if wpipe is not None:
112 try:
113 nxt = perline.next()
114 if debug:
115 print "#PERLINE: <%s>" % nxt
116 wpipe.write(nxt)
117 wpipe.flush()
118 except StopIteration:
119 wpipe.close()
120 wpipe = None
121 pass
122 line = rpipe.readline()
123 if debug:
124 print '#LINE: {%s}' % line.rstrip('\n')
125 if not line:
126 break
127 yield line
128
129
130 if wpipe is not None:
131 wpipe.close()
132 if perline is not None:
133 raise ExecError("Unused input: program {%s} terminated before perline ran out of data" % s,
134 *argv)
135 sts = rpipe.close()
136
137
138 if sts != 0 :
139 raise ExecError('spawned command fails with %d from {%s}' % (sts, s), *argv)
140
141
142 -def getiter(s, argv, input=None, perline=None, debug=False, err=ERR, comment='#'):
143 """Read a list of lines from a subprocess, after
144 dropping junk like comments. (Comment lines begin with the C{comment}
145 argument).
146 Raises an exception if the subprocess returns an error line (the beginning
147 of an error line is specified in the C{err} argument).
148
149 @note: If input or perline is badly chosen, one can
150 produce a locked loop of pipes. (Locked loops happen when you have
151 too much stuff waiting to be processed.)
152 @param s: the name of the program to execute. (Or L{None}, in
153 which case, it is taken from C{argv[0]}).
154 @type s: C{str} or L{None}
155 @param argv: an array of argument to execute.
156 @type argv: C{list(str)}
157 @param input: strings to feed
158 to the subprocess on startup, before the first output is read.
159 These are sent to the subprocess's standard input.
160 @type input: array, sequence or iterator, containing strings
161 @param perline: is a sequence/iterator of strings to feed in, one at a time,
162 as the subprocess is producing data. (These are fed to the subprocess's
163 standard input, one after each output line that it produces.)
164 @type perline: array, sequence or iterator, containing strings
165 @return: a sequence of the lines of output that the program produced.
166 (Newlines are not removed.)
167 @rtype: a generator of strings.
168 @param debug: Should it print some debugging information?
169 @type debug: bool
170 @raise ExecError: ZZZ
171 """
172 for line in getiter_raw(s, argv, input=input, perline=perline, debug=debug):
173 if line.startswith(comment):
174 continue;
175 line = line.rstrip()
176 if err and line.startswith(err):
177 raise ExecError('%s from {%s}' % (line, s), *argv)
178 yield line
179
180
181 -def get(s, argv=None, input=None, perline=None, debug=False, err=ERR, comment='#'):
182 """Read a single line from a subprocess, after dropping junk like comments.
183 Raises an exception if the subprocess produces an error line (see L{getiter}, L{ERR})
184 or no output. See L{getiter} for arguments.
185 @return: the subprocess's first output line (after dropping comment lines).
186 @rtype: C{str}
187 @raise ExecError: if the subprocess produces no output, or an error line.
188 """
189 try:
190 return getiter(s, argv, input, perline=perline,
191 debug=debug, err=err, comment=comment).next()
192 except StopIteration:
193 raise ExecError('no output fron {%s}' % s, *argv)
194
195
196 -def get_raw(s, argv=None, input=None, perline=False, debug=False):
197 """Read a single line from a subprocess. (One normally uses this for
198 processes that are always supposed to produce a single line of output.)
199 See L{getiter_raw} for arguments.
200 @return: the subprocess's first output line.
201 @rtype: C{str}
202 @raise ExecError: if the subprocess produces no output.
203 """
204 try:
205 return getiter_raw(s, argv, input, perline=perline, debug=debug).next()
206 except StopIteration:
207 raise ExecError('no output fron {%s}' % s, *argv)
208
209
210 -def getlast(s, argv=None, input=None, perline=False, debug=False, err=ERR, comment='#'):
211 """Read the last line from a subprocess, after dropping junk like comments.
212 Raises an exception if the subprocess produces an error line (see L{getiter}, L{ERR})
213 or no output. See L{getiter} for arguments.
214 @return: the subprocess's first output line (after dropping comment lines).
215 @rtype: C{str}
216 @raise ExecError: if the subprocess produces no output, or an error line.
217 """
218 ok = False
219 for q in getiter(s, argv, input, perline=perline,
220 debug=debug, err=err, comment=comment):
221 ok = True
222 if ok:
223 return q
224 else:
225 raise ExecError('no output fron {%s}' % s, *argv)
226
227
228 -def getall(s, argv, input=None, perline=None, debug=False, err=ERR, comment='#'):
229 """Read the text lines produced by a subprocess, after dropping junk like comments.
230 Raises an exception if the process produces an error line (see L{getiter}, L{ERR}).
231 See L{getiter} for arguments.
232 @return: the subprocess's first output line (after dropping comment lines).
233 @rtype: C{list(str)}
234 @raise ExecError: if the process produces an error line.
235 """
236 return list(getiter(s, argv, input=input,
237 perline=perline, debug=debug,
238 err=err, comment=comment
239 )
240 )
241
242
243
245 import die
246 inp = ['once\n', 'upon\n', 'a\n', 'time.\n']
247 die.note('inp', inp)
248 oup = getall(None, ['cat'], input=inp)
249 die.note('oup', oup)
250 if oup != ["%s" % q for q in oup]:
251 die.die('bad cat')
252 if get(None, ['sum'], input=['wurgle'])!='02254 1':
253 die.die('bad input sum')
254
255
256 if __name__ == '__main__':
257 test()
258 test()
259 print 'OK'
260