ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/CRAB/python/crab_util.py
Revision: 1.16
Committed: Tue Dec 6 16:47:25 2005 UTC (19 years, 4 months ago) by slacapra
Content type: text/x-python
Branch: MAIN
Changes since 1.15: +52 -19 lines
Log Message:
improved runCommand plus cosmetics

File Contents

# User Rev Content
1 nsmirnov 1.1 ###########################################################################
2     #
3     # C O N V E N I E N C E F U N C T I O N S
4     #
5     ###########################################################################
6    
7 slacapra 1.12 import string, sys, os, time
8 slacapra 1.16 import ConfigParser, re, popen2, select, fcntl
9 nsmirnov 1.1
10 nsmirnov 1.2 import common
11 nsmirnov 1.1
12     ###########################################################################
13     def parseOptions(argv):
14     """
15     Parses command-line options.
16     Returns a dictionary with specified options as keys:
17     -opt1 --> 'opt1' : None
18     -opt2 val --> 'opt2' : 'val'
19     -opt3=val --> 'opt3' : 'val'
20     Usually called as
21     options = parseOptions(sys.argv[1:])
22     """
23     options = {}
24     argc = len(argv)
25     i = 0
26     while ( i < argc ):
27     if argv[i][0] != '-':
28     i = i + 1
29     continue
30     eq = string.find(argv[i], '=')
31     if eq > 0 :
32     opt = argv[i][:eq]
33     val = argv[i][eq+1:]
34     pass
35     else:
36     opt = argv[i]
37     val = None
38     if ( i+1 < argc and argv[i+1][0] != '-' ):
39     i = i + 1
40     val = argv[i]
41     pass
42     pass
43     options[opt] = val
44     i = i + 1
45     pass
46     return options
47    
48     ###########################################################################
49     def loadConfig(file):
50     """
51     returns a dictionary with keys of the form
52     <section>.<option> and the corresponding values
53     """
54     config={}
55     cp = ConfigParser.ConfigParser()
56     cp.read(file)
57     for sec in cp.sections():
58     # print 'Section',sec
59     for opt in cp.options(sec):
60     #print 'config['+sec+'.'+opt+'] = '+string.strip(cp.get(sec,opt))
61     config[sec+'.'+opt] = string.strip(cp.get(sec,opt))
62     return config
63    
64     ###########################################################################
65     def isInt(str):
66     """ Is the given string an integer ?"""
67     try: int(str)
68     except ValueError: return 0
69     return 1
70    
71     ###########################################################################
72     def isBool(str):
73     """ Is the given string 0 or 1 ?"""
74     if (str in ('0','1')): return 1
75     return 0
76    
77     ###########################################################################
78 nsmirnov 1.3 def parseRange(range):
79     """
80     Takes as the input a string with two integers separated by
81     the minus sign and returns the tuple with these numbers:
82     'n1-n2' -> (n1, n2)
83     'n1' -> (n1, n1)
84     """
85     start = None
86     end = None
87     minus = string.find(range, '-')
88     if ( minus < 0 ):
89     if isInt(range):
90     start = int(range)
91     end = start
92     pass
93     pass
94     else:
95     if isInt(range[:minus]) and isInt(range[minus+1:]):
96     start = int(range[:minus])
97     end = int(range[minus+1:])
98     pass
99     pass
100     return (start, end)
101    
102     ###########################################################################
103 nsmirnov 1.4 def parseRange2(range):
104     """
105     Takes as the input a string in the form of a comma-separated
106     numbers and ranges
107     and returns a list with all specified numbers:
108     'n1' -> [n1]
109     'n1-n2' -> [n1, n1+1, ..., n2]
110     'n1,n2-n3,n4' -> [n1, n2, n2+1, ..., n3, n4]
111     """
112     list = []
113     if not range: return list
114    
115     comma = string.find(range, ',')
116     if comma == -1: left = range
117     else: left = range[:comma]
118    
119     (n1, n2) = parseRange(left)
120     while ( n1 <= n2 ):
121 slacapra 1.11 try:
122     list.append(n1)
123     n1 += 1
124     pass
125     except:
126     msg = 'Syntax error in range <'+range+'>'
127     raise CrabException(msg)
128 nsmirnov 1.4
129     if comma != -1:
130 slacapra 1.11 try:
131     list.extend(parseRange2(range[comma+1:]))
132     pass
133     except:
134     msg = 'Syntax error in range <'+range+'>'
135     raise CrabException(msg)
136 nsmirnov 1.4
137     return list
138    
139     ###########################################################################
140 nsmirnov 1.3 def crabJobStatusToString(crab_status):
141     """
142     Convert one-letter crab job status into more readable string.
143     """
144     if crab_status == 'C': status = 'Created'
145 slacapra 1.6 elif crab_status == 'D': status = 'Done'
146 nsmirnov 1.3 elif crab_status == 'S': status = 'Submitted'
147     elif crab_status == 'K': status = 'Killed'
148     elif crab_status == 'X': status = 'None'
149     elif crab_status == 'Y': status = 'Output retrieved'
150 slacapra 1.5 elif crab_status == 'A': status = 'Aborted'
151 spiga 1.7 elif crab_status == 'RC': status = 'ReCreated'
152 nsmirnov 1.3 else: status = '???'
153     return status
154    
155     ###########################################################################
156 nsmirnov 1.1 def findLastWorkDir(dir_prefix, where = None):
157    
158     if not where: where = os.getcwd() + '/'
159     # dir_prefix usually has the form 'crab_0_'
160     pattern = re.compile(dir_prefix)
161    
162     file_list = []
163     for fl in os.listdir(where):
164     if pattern.match(fl):
165     file_list.append(fl)
166     pass
167     pass
168    
169     if len(file_list) == 0: return None
170    
171     file_list.sort()
172    
173     wdir = where + file_list[len(file_list)-1]
174     return wdir
175    
176     ###########################################################################
177     def importName(module_name, name):
178     """
179     Import a named object from a Python module,
180     i.e., it is an equivalent of 'from module_name import name'.
181     """
182     module = __import__(module_name, globals(), locals(), [name])
183     return vars(module)[name]
184    
185 spiga 1.9
186 slacapra 1.11 ###########################################################################
187 slacapra 1.12 def runBossCommand(cmd, printout=0, timeout=240):
188 slacapra 1.11 """
189     Cd to correct directory before running a boss command
190     """
191     cwd = os.getcwd()
192     os.chdir(common.work_space.shareDir())
193     out = runCommand(cmd, printout, timeout)
194     os.chdir(cwd)
195     return out
196 spiga 1.9
197 nsmirnov 1.1 ###########################################################################
198 slacapra 1.16 def readable(fd):
199     return bool(select.select([fd], [], [], 0))
200    
201     ###########################################################################
202     def makeNonBlocking(fd):
203     fl = fcntl.fcntl(fd, fcntl.F_GETFL)
204     try:
205     fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY)
206     except AttributeError:
207     fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.FNDELAY)
208    
209     ###########################################################################
210 slacapra 1.11 def runCommand(cmd, printout=0, timeout=-1):
211 nsmirnov 1.1 """
212     Run command 'cmd'.
213     Returns command stdoutput+stderror string on success,
214     or None if an error occurred.
215 slacapra 1.16 Following recipe on http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52296
216 nsmirnov 1.1 """
217 fanzago 1.15
218 slacapra 1.11 if printout:
219     common.logger.message(cmd)
220     else:
221 slacapra 1.13 common.logger.debug(10,cmd)
222 slacapra 1.11 common.logger.write(cmd)
223    
224 slacapra 1.16 child = popen2.Popen3(cmd, 1) # capture stdout and stderr from command
225     child.tochild.close() # don't need to talk to child
226     outfile = child.fromchild
227     outfd = outfile.fileno()
228     errfile = child.childerr
229     errfd = errfile.fileno()
230     makeNonBlocking(outfd) # don't deadlock!
231     makeNonBlocking(errfd)
232     outdata = []
233     errdata = []
234     outeof = erreof = 0
235    
236     if timeout > 0 :
237     maxwaittime = time.time() + timeout
238    
239     err = -1
240     while (timeout == -1 or time.time() < maxwaittime):
241     ready = select.select([outfd,errfd],[],[]) # wait for input
242     if outfd in ready[0]:
243     outchunk = outfile.read()
244     if outchunk == '': outeof = 1
245     outdata.append(outchunk)
246     if errfd in ready[0]:
247     errchunk = errfile.read()
248     if errchunk == '': erreof = 1
249     errdata.append(errchunk)
250     if outeof and erreof:
251     err = child.wait()
252     break
253     select.select([],[],[],.1) # give a little time for buffers to fill
254     if err == -1:
255     # kill the pid
256     common.logger.message('killing process '+(cmd)+' with timeout '+timeout)
257     os.kill (child.pid, 9)
258 slacapra 1.11 err = child.wait()
259 slacapra 1.16
260 slacapra 1.11 if err:
261     common.logger.message('`'+cmd+'`\n failed with exit code '
262     +`err`+'='+`(err&0xff)`+'(signal)+'
263     +`(err>>8)`+'(status)')
264     common.logger.message(cmd_out)
265     common.logger.message(cmd_err)
266 nsmirnov 1.1 return None
267    
268 slacapra 1.16 cmd_out = string.join(outdata,"")
269     cmd_err = string.join(errdata,"")
270 nsmirnov 1.1 cmd_out = cmd_out + cmd_err
271 slacapra 1.11 if printout:
272     common.logger.message(cmd_out)
273     else:
274 slacapra 1.13 common.logger.debug(10,cmd_out)
275 slacapra 1.11 common.logger.write(cmd_out)
276 slacapra 1.16 #print "<"+cmd_out+">"
277 nsmirnov 1.1 return cmd_out
278 nsmirnov 1.4
279 slacapra 1.11 ####################################
280 nsmirnov 1.4 if __name__ == '__main__':
281     import sys
282     print 'sys.argv[1] =',sys.argv[1]
283     list = parseRange2(sys.argv[1])
284     print list
285