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