Package gmisclib :: Module g_exec
[frames] | no frames]

Source Code for Module gmisclib.g_exec

  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   
41 -class ExecError(Exception):
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
49 - def __init__(self, *s):
50 Exception.__init__(self, *s)
51 52 53 54 ERR = 'ERR:' #: This is the default for the prefix for error messages from the subprocess. 55 COMMENT = '#' #: This is the default for the prefix for comments from the subprocess. 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 # Note that this generator could terminate here! 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 # if sts is None: 137 # sts = 0 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
244 -def test():
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