1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """A set of functions performing routine administrative I/O tasks."""
17
18 import logging
19 import os
20 import re
21 import signal
22 import subprocess
23 import sys
24 import StringIO
25 import sys
26 import time
27
28 try:
29
30 import madgraph
31 from madgraph import MadGraph5Error
32 import madgraph.iolibs.files as files
33 except:
34
35 import internal as madgraph
36 from internal import MadGraph5Error
37 import internal.files as files
38
39 logger = logging.getLogger('cmdprint.ext_program')
40 pjoin = os.path.join
46 """Parse a newline separated list of "param=value" as a dictionnary
47 """
48
49 info_dict = {}
50 pattern = re.compile("(?P<name>\w*)\s*=\s*(?P<value>.*)",
51 re.IGNORECASE | re.VERBOSE)
52 for entry in fsock:
53 entry = entry.strip()
54 if len(entry) == 0: continue
55 m = pattern.match(entry)
56 if m is not None:
57 info_dict[m.group('name')] = m.group('value')
58 else:
59 raise IOError, "String %s is not a valid info string" % entry
60
61 return info_dict
62
68 """Returns the current version information of the MadGraph package,
69 as written in the VERSION text file. If the file cannot be found,
70 a dictionary with empty values is returned. As an option, an info
71 string can be passed to be read instead of the file content.
72 """
73
74 if info_str is None:
75 info_dict = files.read_from_file(os.path.join(madgraph.__path__[0],
76 "VERSION"),
77 parse_info_str,
78 print_error=False)
79 else:
80 info_dict = parse_info_str(StringIO.StringIO(info_str))
81
82 return info_dict
83
88 """Returns the present time info for use in MG5 command history header.
89 """
90
91 creation_time = time.asctime()
92 time_info = {'time': creation_time,
93 'fill': ' ' * (26 - len(creation_time))}
94
95 return time_info
96
97
98
99
100 -def which(program):
101 def is_exe(fpath):
102 return os.path.exists(fpath) and os.access(fpath, os.X_OK)
103
104 if not program:
105 return None
106
107 fpath, fname = os.path.split(program)
108 if fpath:
109 if is_exe(program):
110 return program
111 else:
112 for path in os.environ["PATH"].split(os.pathsep):
113 exe_file = os.path.join(path, program)
114 if is_exe(exe_file):
115 return exe_file
116
117 return None
118
123 """ Return nice information on the current variable """
124
125
126 info = [('type',type(var)),('str', var)]
127 if hasattr(var, 'func_doc'):
128 info.append( ('DOC', var.func_doc) )
129 if hasattr(var, '__doc__'):
130 info.append( ('DOC', var.__doc__) )
131 if hasattr(var, '__dict__'):
132 info.append( ('ATTRIBUTE', var.__dict__.keys() ))
133
134 spaces = ' ' * nb_space
135
136 outstr=''
137 for name, value in info:
138 outstr += '%s%3s : %s\n' % (spaces,name, value)
139
140 return outstr
141
142
143
144
145
146 -def compile(arg=[], cwd=None, mode='fortran', **opt):
147 """compile a given directory"""
148
149 try:
150 p = subprocess.Popen(['make'] + arg, stdout=subprocess.PIPE,
151 stderr=subprocess.STDOUT, cwd=cwd, **opt)
152 (out, err) = p.communicate()
153 except OSError, error:
154 if cwd and not os.path.exists(cwd):
155 raise OSError, 'Directory %s doesn\'t exists. Impossible to run make' % cwd
156 else:
157 error_text = "Impossible to compile %s directory\n" % cwd
158 error_text += "Trying to launch make command returns:\n"
159 error_text += " " + str(error) + "\n"
160 error_text += "In general this means that your computer is not able to compile."
161 if sys.platform == "darwin":
162 error_text += "Note that MacOSX doesn\'t have gmake/gfortan install by default.\n"
163 error_text += "Xcode3 contains those require program"
164 raise MadGraph5Error, error_text
165
166 if p.returncode:
167
168 if not cwd:
169 cwd = os.getcwd()
170 all_file = [f.lower() for f in os.listdir(cwd)]
171 if 'makefile' not in all_file:
172 raise OSError, 'no makefile present in %s' % os.path.realpath(cwd)
173
174 if mode == 'fortran' and not (which('g77') or which('gfortran')):
175 error_msg = 'A fortran compilator (g77 or gfortran) is required to create this output.\n'
176 error_msg += 'Please install g77 or gfortran on your computer and retry.'
177 raise MadGraph5Error, error_msg
178 elif mode == 'cpp' and not which('g++'):
179 error_msg ='A C++ compilator (g++) is required to create this output.\n'
180 error_msg += 'Please install g++ (which is part of the gcc package) on your computer and retry.'
181 raise MadGraph5Error, error_msg
182
183
184
185 error_text = 'A compilation Error occurs '
186 if cwd:
187 error_text += 'when trying to compile %s.\n' % cwd
188 error_text += 'The compilation fails with the following output message:\n'
189 error_text += ' '+out.replace('\n','\n ')+'\n'
190 error_text += 'Please try to fix this compilations issue and retry.\n'
191 error_text += 'Help might be found at https://answers.launchpad.net/madgraph5.\n'
192 error_text += 'If you think that this is a bug, you can report this at https://bugs.launchpad.net/madgraph5'
193
194 raise MadGraph5Error, error_text
195 return p.returncode
196
199 def deco_check(f):
200 def deco_f(arg, *args, **opt):
201 try:
202 return f(arg, *args, **opt)
203 except OSError, error:
204 if isinstance(arg, list):
205 prog = arg[0]
206 else:
207 prog = arg[0]
208
209
210 if error.errno == 13:
211 if os.path.exists(prog):
212 os.system('chmod +x %s' % prog)
213 elif 'cwd' in opt and opt['cwd'] and \
214 os.path.isfile(pjoin(opt['cwd'],arg[0])):
215 os.system('chmod +x %s' % pjoin(opt['cwd'],arg[0]))
216 return f(arg, *args, **opt)
217
218 elif error.errno == 2:
219
220 raise Exception, '%s fails with no such file or directory' \
221 % arg
222 else:
223 raise
224 return deco_f
225 return deco_check
226
227
228 @check_system_error()
229 -def call(arg, *args, **opt):
230 """nice way to call an external program with nice error treatment"""
231 return subprocess.call(arg, *args, **opt)
232
233 @check_system_error()
234 -def Popen(arg, *args, **opt):
235 """nice way to call an external program with nice error treatment"""
236 return subprocess.Popen(arg, *args, **opt)
237
238
239
240
241
242
243
244
245 -def tail(f, n, offset=None):
246 """Reads a n lines from f with an offset of offset lines. The return
247 value is a tuple in the form ``lines``.
248 """
249 avg_line_length = 74
250 to_read = n + (offset or 0)
251
252 while 1:
253 try:
254 f.seek(-(avg_line_length * to_read), 2)
255 except IOError:
256
257
258 f.seek(0)
259 pos = f.tell()
260 lines = f.read().splitlines()
261 if len(lines) >= to_read or pos == 0:
262 return lines[-to_read:offset and -offset or None]
263 avg_line_length *= 1.3
264 avg_line_length = int(avg_line_length)
265
270 """return the last line of a file"""
271
272 return tail(fsock, 1)[0]
273
275 """read a file returning the lines in reverse order for each call of readline()
276 This actually just reads blocks (4096 bytes by default) of data from the end of
277 the file and returns last line in an internal buffer."""
278
279
281 """ readline in a backward way """
282
283 while len(self.data) == 1 and ((self.blkcount * self.blksize) < self.size):
284 self.blkcount = self.blkcount + 1
285 line = self.data[0]
286 try:
287 self.seek(-self.blksize * self.blkcount, 2)
288 self.data = (self.read(self.blksize) + line).split('\n')
289 except IOError:
290 self.seek(0)
291 data = self.read(self.size - (self.blksize * (self.blkcount-1))) + line
292 self.data = data.split('\n')
293
294 if len(self.data) == 0:
295 return ""
296
297 line = self.data.pop()
298 return line + '\n'
299
300 - def __init__(self, filepos, blksize=4096):
301 """initialize the internal structures"""
302
303
304 self.size = os.stat(filepos)[6]
305
306 self.blksize = blksize
307
308 self.blkcount = 1
309 file.__init__(self, filepos, 'rb')
310
311
312 if self.size > self.blksize:
313 self.seek(-self.blksize * self.blkcount, 2)
314 self.data = self.read(self.blksize).split('\n')
315
316
317 if not self.data[-1]:
318 self.data.pop()
319
321 line = self.readline()
322 if line:
323 return line
324 else:
325 raise StopIteration
326
327
328
329
330
331
332
333 -class open_file(object):
334 """ a convinient class to open a file """
335
336 web_browser = None
337 eps_viewer = None
338 text_editor = None
339 configured = False
340
342 """open a file"""
343
344
345 if not self.configured:
346 self.configure()
347
348 try:
349 extension = filename.rsplit('.',1)[1]
350 except IndexError:
351 extension = ''
352
353
354
355 if extension in ['html','htm','php']:
356 self.open_program(self.web_browser, filename, background=True)
357 elif extension in ['ps','eps']:
358 self.open_program(self.eps_viewer, filename, background=True)
359 else:
360 self.open_program(self.text_editor,filename, mac_check=False)
361
362
363 @classmethod
386
387 @classmethod
425
426
427 @staticmethod
429 """find a valid shell program in the list"""
430
431 for p in possibility:
432 if which(p):
433 logger.info('Using default %s \"%s\". ' % (program, p) + \
434 'Set another one in ./input/mg5_configuration.txt')
435 return p
436
437 logger.info('No valid %s found. ' % program + \
438 'Please set in ./input/mg5_configuration.txt')
439 return None
440
441
442 - def open_program(self, program, file_path, mac_check=True, background=False):
443 """ open a file with a given program """
444
445 if mac_check==True and sys.platform == 'darwin':
446 return self.open_mac_program(program, file_path)
447
448
449 if program:
450 arguments = program.split()
451 arguments.append(file_path)
452
453 if not background:
454 subprocess.call(arguments)
455 else:
456 import thread
457 thread.start_new_thread(subprocess.call,(arguments,))
458 else:
459 logger.warning('Not able to open file %s since no program configured.' % file_path + \
460 'Please set one in ./input/mg5_configuration.txt')
461
463 """ open a text with the text editor """
464
465 if not program:
466
467 os.system('open %s' % file_path)
468 elif which(program):
469
470 arguments = program.split()
471 arguments.append(file_path)
472 subprocess.call(arguments)
473 else:
474
475 os.system('open -a %s %s' % (program, file_path))
476
478 """ check if a path is executable"""
479 try:
480 return os.access(path, os.X_OK)
481 except:
482 return False
483