Package madgraph :: Package interface :: Module extended_cmd
[hide private]
[frames] | no frames]

Source Code for Module madgraph.interface.extended_cmd

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2011 The MadGraph5_aMC@NLO Development team and Contributors 
   4  # 
   5  # This file is a part of the MadGraph5_aMC@NLO project, an application which  
   6  # automatically generates Feynman diagrams and matrix elements for arbitrary 
   7  # high-energy processes in the Standard Model and beyond. 
   8  # 
   9  # It is subject to the MadGraph5_aMC@NLO license which should accompany this  
  10  # distribution. 
  11  # 
  12  # For more information, visit madgraph.phys.ucl.ac.be and amcatnlo.web.cern.ch 
  13  # 
  14  ################################################################################ 
  15  """  A file containing different extension of the cmd basic python library""" 
  16   
  17   
  18  import cmd 
  19  import logging 
  20  import os 
  21  import pydoc 
  22  import re 
  23  import signal 
  24  import subprocess 
  25  import sys 
  26  import traceback 
  27  try: 
  28      import readline 
  29      GNU_SPLITTING = ('GNU' in readline.__doc__) 
  30  except: 
  31      readline = None 
  32      GNU_SPLITTING = True 
  33   
  34   
  35  logger = logging.getLogger('cmdprint') # for stdout 
  36  logger_stderr = logging.getLogger('fatalerror') # for stderr 
  37   
  38  try: 
  39      import madgraph.various.misc as misc 
  40      from madgraph import MG5DIR 
  41      MADEVENT = False 
  42  except ImportError, error: 
  43      try: 
  44          import internal.misc as misc 
  45      except: 
  46          raise error 
  47      MADEVENT = True 
  48   
  49   
  50  pjoin = os.path.join 
51 52 -class TimeOutError(Exception):
53 """Class for run-time error"""
54
55 -def debug(debug_only=True):
56 57 def deco_debug(f): 58 59 if debug_only and not __debug__: 60 return f 61 62 def deco_f(*args, **opt): 63 try: 64 return f(*args, **opt) 65 except Exception, error: 66 logger.error(error) 67 logger.error(traceback.print_exc(file=sys.stdout)) 68 return
69 return deco_f 70 return deco_debug 71
72 73 #=============================================================================== 74 # CmdExtended 75 #=============================================================================== 76 -class BasicCmd(cmd.Cmd):
77 """Simple extension for the readline""" 78
79 - def preloop(self):
80 if readline and not 'libedit' in readline.__doc__: 81 readline.set_completion_display_matches_hook(self.print_suggestions)
82
83 - def deal_multiple_categories(self, dico, forceCategory=False):
84 """convert the multiple category in a formatted list understand by our 85 specific readline parser""" 86 87 if 'libedit' in readline.__doc__: 88 # No parser in this case, just send all the valid options 89 out = [] 90 for name, opt in dico.items(): 91 out += opt 92 return out 93 94 # check if more than one categories but only one value: 95 if not forceCategory and all(len(s) <= 1 for s in dico.values() ): 96 values = set((s[0] for s in dico.values() if len(s)==1)) 97 if len(values) == 1: 98 return values 99 100 # That's the real work 101 out = [] 102 valid=0 103 # if the key starts with number order the key with that number. 104 for name, opt in dico.items(): 105 if not opt: 106 continue 107 name = name.replace(' ', '_') 108 valid += 1 109 out.append(opt[0].rstrip()+'@@'+name+'@@') 110 # Remove duplicate 111 d = {} 112 for x in opt: 113 d[x] = 1 114 opt = list(d.keys()) 115 opt.sort() 116 out += opt 117 118 if not forceCategory and valid == 1: 119 out = out[1:] 120 121 return out
122 123 @debug()
124 - def print_suggestions(self, substitution, matches, longest_match_length) :
125 """print auto-completions by category""" 126 if not hasattr(self, 'completion_prefix'): 127 self.completion_prefix = '' 128 longest_match_length += len(self.completion_prefix) 129 try: 130 if len(matches) == 1: 131 self.stdout.write(matches[0]+' ') 132 return 133 self.stdout.write('\n') 134 l2 = [a[-2:] for a in matches] 135 if '@@' in l2: 136 nb_column = self.getTerminalSize()//(longest_match_length+1) 137 pos=0 138 for val in self.completion_matches: 139 if val.endswith('@@'): 140 category = val.rsplit('@@',2)[1] 141 category = category.replace('_',' ') 142 self.stdout.write('\n %s:\n%s\n' % (category, '=' * (len(category)+2))) 143 start = 0 144 pos = 0 145 continue 146 elif pos and pos % nb_column ==0: 147 self.stdout.write('\n') 148 self.stdout.write(self.completion_prefix + val + \ 149 ' ' * (longest_match_length +1 -len(val))) 150 pos +=1 151 self.stdout.write('\n') 152 else: 153 # nb column 154 nb_column = self.getTerminalSize()//(longest_match_length+1) 155 for i,val in enumerate(matches): 156 if i and i%nb_column ==0: 157 self.stdout.write('\n') 158 self.stdout.write(self.completion_prefix + val + \ 159 ' ' * (longest_match_length +1 -len(val))) 160 self.stdout.write('\n') 161 162 self.stdout.write(self.prompt+readline.get_line_buffer()) 163 self.stdout.flush() 164 except Exception, error: 165 if __debug__: 166 logger.error(error)
167
168 - def getTerminalSize(self):
169 def ioctl_GWINSZ(fd): 170 try: 171 import fcntl, termios, struct 172 cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, 173 '1234')) 174 except Exception: 175 return None 176 return cr
177 cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) 178 if not cr: 179 try: 180 fd = os.open(os.ctermid(), os.O_RDONLY) 181 cr = ioctl_GWINSZ(fd) 182 os.close(fd) 183 except Exception: 184 pass 185 if not cr: 186 try: 187 cr = (os.environ['LINES'], os.environ['COLUMNS']) 188 except Exception: 189 cr = (25, 80) 190 return int(cr[1])
191
192 - def complete(self, text, state):
193 """Return the next possible completion for 'text'. 194 If a command has not been entered, then complete against command list. 195 Otherwise try to call complete_<command> to get list of completions. 196 """ 197 198 if state == 0: 199 import readline 200 origline = readline.get_line_buffer() 201 line = origline.lstrip() 202 stripped = len(origline) - len(line) 203 begidx = readline.get_begidx() - stripped 204 endidx = readline.get_endidx() - stripped 205 206 if ';' in line: 207 begin, line = line.rsplit(';',1) 208 begidx = begidx - len(begin) - 1 209 endidx = endidx - len(begin) - 1 210 if line[:begidx] == ' ' * begidx: 211 begidx=0 212 213 if begidx>0: 214 cmd, args, foo = self.parseline(line) 215 if cmd == '': 216 compfunc = self.completedefault 217 else: 218 try: 219 compfunc = getattr(self, 'complete_' + cmd) 220 except AttributeError, error: 221 misc.sprint(error) 222 compfunc = self.completedefault 223 except Exception, error: 224 misc.sprint(error) 225 else: 226 compfunc = self.completenames 227 228 # correct wrong splittion with '\ ' 229 if line and begidx > 2 and line[begidx-2:begidx] == '\ ': 230 Ntext = line.split(os.path.sep)[-1] 231 self.completion_prefix = Ntext.rsplit('\ ', 1)[0] + '\ ' 232 to_rm = len(self.completion_prefix) - 1 233 Nbegidx = len(line.rsplit(os.path.sep, 1)[0]) + 1 234 data = compfunc(Ntext.replace('\ ', ' '), line, Nbegidx, endidx) 235 self.completion_matches = [p[to_rm:] for p in data 236 if len(p)>to_rm] 237 # correct wrong splitting with '-' 238 elif line and line[begidx-1] == '-': 239 try: 240 Ntext = line.split()[-1] 241 self.completion_prefix = Ntext.rsplit('-',1)[0] +'-' 242 to_rm = len(self.completion_prefix) 243 Nbegidx = len(line.rsplit(None, 1)[0]) 244 data = compfunc(Ntext, line, Nbegidx, endidx) 245 self.completion_matches = [p[to_rm:] for p in data 246 if len(p)>to_rm] 247 except Exception, error: 248 print error 249 else: 250 self.completion_prefix = '' 251 self.completion_matches = compfunc(text, line, begidx, endidx) 252 253 self.completion_matches = [ l if l[-1] in [' ','@','=',os.path.sep] 254 else ((l + ' ') if not l.endswith('\\$') else l[:-2]) 255 for l in self.completion_matches if l] 256 257 try: 258 return self.completion_matches[state] 259 except IndexError, error: 260 # if __debug__: 261 # logger.error('\n Completion ERROR:') 262 # logger.error( error) 263 return None
264 265 @staticmethod
266 - def split_arg(line):
267 """Split a line of arguments""" 268 269 split = line.split() 270 out=[] 271 tmp='' 272 for data in split: 273 if data[-1] == '\\': 274 tmp += data[:-1]+' ' 275 elif tmp: 276 tmp += data 277 tmp = os.path.expanduser(os.path.expandvars(tmp)) 278 out.append(tmp) 279 # Reinitialize tmp in case there is another differen argument 280 # containing escape characters 281 tmp = '' 282 else: 283 out.append(data) 284 return out
285 286 @staticmethod
287 - def list_completion(text, list, line=''):
288 """Propose completions of text in list""" 289 290 if not text: 291 completions = list 292 else: 293 completions = [ f 294 for f in list 295 if f.startswith(text) 296 ] 297 298 return completions
299 300 301 @staticmethod
302 - def path_completion(text, base_dir = None, only_dirs = False, 303 relative=True):
304 """Propose completions of text to compose a valid path""" 305 306 if base_dir is None: 307 base_dir = os.getcwd() 308 base_dir = os.path.expanduser(os.path.expandvars(base_dir)) 309 310 if text == '~': 311 text = '~/' 312 prefix, text = os.path.split(text) 313 prefix = os.path.expanduser(os.path.expandvars(prefix)) 314 base_dir = os.path.join(base_dir, prefix) 315 if prefix: 316 prefix += os.path.sep 317 318 if only_dirs: 319 completion = [prefix + f 320 for f in os.listdir(base_dir) 321 if f.startswith(text) and \ 322 os.path.isdir(os.path.join(base_dir, f)) and \ 323 (not f.startswith('.') or text.startswith('.')) 324 ] 325 else: 326 completion = [ prefix + f 327 for f in os.listdir(base_dir) 328 if f.startswith(text) and \ 329 os.path.isfile(os.path.join(base_dir, f)) and \ 330 (not f.startswith('.') or text.startswith('.')) 331 ] 332 333 completion = completion + \ 334 [prefix + f + os.path.sep 335 for f in os.listdir(base_dir) 336 if f.startswith(text) and \ 337 os.path.isdir(os.path.join(base_dir, f)) and \ 338 (not f.startswith('.') or text.startswith('.')) 339 ] 340 341 if relative: 342 completion += [prefix + f for f in ['.'+os.path.sep, '..'+os.path.sep] if \ 343 f.startswith(text) and not prefix.startswith('.')] 344 345 completion = [a.replace(' ','\ ') for a in completion] 346 return completion
347
348 349 350 351 -class CheckCmd(object):
352 """Extension of the cmd object for only the check command""" 353
354 - def check_history(self, args):
355 """check the validity of line""" 356 357 if len(args) > 1: 358 self.help_history() 359 raise self.InvalidCmd('\"history\" command takes at most one argument') 360 361 if not len(args): 362 return 363 364 if args[0] =='.': 365 if not self._export_dir: 366 raise self.InvalidCmd("No default directory is defined for \'.\' option") 367 elif args[0] != 'clean': 368 dirpath = os.path.dirname(args[0]) 369 if dirpath and not os.path.exists(dirpath) or \ 370 os.path.isdir(args[0]): 371 raise self.InvalidCmd("invalid path %s " % dirpath)
372
373 - def check_save(self, args):
374 """check that the line is compatible with save options""" 375 376 if len(args) > 2: 377 self.help_save() 378 raise self.InvalidCmd, 'too many arguments for save command.' 379 380 if len(args) == 2: 381 if args[0] != 'options': 382 self.help_save() 383 raise self.InvalidCmd, '\'%s\' is not recognized as first argument.' % \ 384 args[0] 385 else: 386 args.pop(0)
387
388 -class HelpCmd(object):
389 """Extension of the cmd object for only the help command""" 390
391 - def help_quit(self):
392 logger.info("-- terminates the application",'$MG:color:BLUE') 393 logger.info("syntax: quit",'$MG:color:BLACK')
394 395 help_EOF = help_quit 396
397 - def help_history(self):
398 logger.info("-- interact with the command history.",'$MG:color:BLUE') 399 logger.info("syntax: history [FILEPATH|clean|.] ",'$MG:color:BLACK') 400 logger.info(" > If FILEPATH is \'.\' and \'output\' is done,") 401 logger.info(" Cards/proc_card_mg5.dat will be used.") 402 logger.info(" > If FILEPATH is omitted, the history will be output to stdout.") 403 logger.info(" \"clean\" will remove all entries from the history.")
404
405 - def help_help(self):
406 logger.info("-- access to the in-line help",'$MG:color:BLUE') 407 logger.info("syntax: help",'$MG:color:BLACK')
408
409 - def help_save(self):
410 """help text for save""" 411 logger.info("-- save options configuration to filepath.",'$MG:color:BLUE') 412 logger.info("syntax: save [options] [FILEPATH]",'$MG:color:BLACK')
413
414 - def help_display(self):
415 """help for display command""" 416 logger.info("-- display a the status of various internal state variables",'$MG:color:BLUE') 417 logger.info("syntax: display " + "|".join(self._display_opts),'$MG:color:BLACK')
418
419 -class CompleteCmd(object):
420 """Extension of the cmd object for only the complete command""" 421
422 - def complete_display(self,text, line, begidx, endidx):
423 args = self.split_arg(line[0:begidx]) 424 # Format 425 if len(args) == 1: 426 return self.list_completion(text, self._display_opts)
427
428 - def complete_history(self, text, line, begidx, endidx):
429 "Complete the history command" 430 431 args = self.split_arg(line[0:begidx]) 432 433 # Directory continuation 434 if args[-1].endswith(os.path.sep): 435 return self.path_completion(text, 436 os.path.join('.',*[a for a in args \ 437 if a.endswith(os.path.sep)])) 438 439 if len(args) == 1: 440 return self.path_completion(text)
441
442 - def complete_save(self, text, line, begidx, endidx):
443 "Complete the save command" 444 445 args = self.split_arg(line[0:begidx]) 446 447 # Format 448 if len(args) == 1: 449 return self.list_completion(text, ['options']) 450 451 # Directory continuation 452 if args[-1].endswith(os.path.sep): 453 return self.path_completion(text, 454 pjoin('.',*[a for a in args if a.endswith(os.path.sep)]), 455 only_dirs = True) 456 457 # Filename if directory is not given 458 if len(args) == 2: 459 return self.path_completion(text)
460
461 -class Cmd(CheckCmd, HelpCmd, CompleteCmd, BasicCmd):
462 """Extension of the cmd.Cmd command line. 463 This extensions supports line breaking, history, comments, 464 internal call to cmdline, path completion,... 465 this class should be MG5 independent""" 466 467 #suggested list of command 468 next_possibility = {} # command : [list of suggested command] 469 history_header = "" 470 471 _display_opts = ['options','variable'] 472 allow_notification_center = True 473
474 - class InvalidCmd(Exception):
475 """expected error for wrong command""" 476 pass
477 478 ConfigurationError = InvalidCmd 479 480 debug_output = 'debug' 481 error_debug = """Please report this bug to developers\n 482 More information is found in '%(debug)s'.\n 483 Please attach this file to your report.""" 484 config_debug = error_debug 485 486 keyboard_stop_msg = """stopping all current operation 487 in order to quit the program please enter exit""" 488 489
490 - def __init__(self, *arg, **opt):
491 """Init history and line continuation""" 492 493 self.log = True 494 self.history = [] 495 self.save_line = '' # for line splitting 496 cmd.Cmd.__init__(self, *arg, **opt) 497 self.__initpos = os.path.abspath(os.getcwd()) 498 self.child = None # sub CMD interface call from this one 499 self.mother = None #This CMD interface was called from another one 500 self.inputfile = None # input file (in non interactive mode) 501 self.haspiping = not sys.stdin.isatty() # check if mg5 is piped 502 self.stored_line = '' # for be able to treat answer to question in input file 503 # answer which are not required. 504 if not hasattr(self, 'helporder'): 505 self.helporder = ['Documented commands']
506
507 - def preloop(self):
508 """Hook method executed once when the cmdloop() method is called.""" 509 if self.completekey: 510 try: 511 import readline 512 self.old_completer = readline.get_completer() 513 readline.set_completer(self.complete) 514 readline.parse_and_bind(self.completekey+": complete") 515 except ImportError: 516 pass 517 if readline and not 'libedit' in readline.__doc__: 518 readline.set_completion_display_matches_hook(self.print_suggestions)
519 520
521 - def cmdloop(self, intro=None):
522 523 self.preloop() 524 if intro is not None: 525 self.intro = intro 526 if self.intro: 527 print self.intro 528 stop = None 529 while not stop: 530 if self.cmdqueue: 531 line = self.cmdqueue[0] 532 del self.cmdqueue[0] 533 else: 534 if self.use_rawinput: 535 try: 536 line = raw_input(self.prompt) 537 except EOFError: 538 line = 'EOF' 539 else: 540 sys.stdout.write(self.prompt) 541 sys.stdout.flush() 542 line = sys.stdin.readline() 543 if not len(line): 544 line = 'EOF' 545 else: 546 line = line[:-1] # chop \n 547 try: 548 line = self.precmd(line) 549 stop = self.onecmd(line) 550 except BaseException, error: 551 self.error_handling(error, line) 552 if isinstance(error, KeyboardInterrupt): 553 stop = True 554 finally: 555 stop = self.postcmd(stop, line) 556 self.postloop()
557
558 - def no_notification(self):
559 """avoid to have html opening / notification""" 560 self.allow_notification_center = False 561 try: 562 self.options['automatic_html_opening'] = False 563 self.options['notification_center'] = False 564 565 except: 566 pass
567 568
569 - def precmd(self, line):
570 """ A suite of additional function needed for in the cmd 571 this implement history, line breaking, comment treatment,... 572 """ 573 574 if not line: 575 return line 576 577 # Check if we are continuing a line: 578 if self.save_line: 579 line = self.save_line + line 580 self.save_line = '' 581 582 line = line.lstrip() 583 # Check if the line is complete 584 if line.endswith('\\'): 585 self.save_line = line[:-1] 586 return '' # do nothing 587 588 # Remove comment 589 if '#' in line: 590 line = line.split('#')[0] 591 592 # Deal with line splitting 593 if ';' in line: 594 lines = line.split(';') 595 for subline in lines: 596 if not (subline.startswith("history") or subline.startswith('help') \ 597 or subline.startswith('#*')): 598 self.history.append(subline) 599 stop = self.onecmd_orig(subline) 600 stop = self.postcmd(stop, subline) 601 return '' 602 603 # execute the line command 604 self.history.append(line) 605 return line
606
607 - def postcmd(self,stop, line):
608 """ finishing a command 609 This looks if the command add a special post part.""" 610 611 if line.strip(): 612 try: 613 cmd, subline = line.split(None, 1) 614 except ValueError: 615 pass 616 else: 617 if hasattr(self,'post_%s' %cmd): 618 stop = getattr(self, 'post_%s' % cmd)(stop, subline) 619 return stop
620
621 - def define_child_cmd_interface(self, obj_instance, interface=True):
622 """Define a sub cmd_interface""" 623 624 # We are in a file reading mode. So we need to redirect the cmd 625 self.child = obj_instance 626 self.child.mother = self 627 628 #ensure that notification are sync: 629 self.child.allow_notification_center = self.allow_notification_center 630 631 if self.use_rawinput and interface: 632 # We are in interactive mode -> simply call the child 633 obj_instance.cmdloop() 634 stop = obj_instance.postloop() 635 return stop 636 if self.inputfile: 637 # we are in non interactive mode -> so pass the line information 638 obj_instance.inputfile = self.inputfile 639 640 obj_instance.haspiping = self.haspiping 641 642 if not interface: 643 return self.child
644 645 #=============================================================================== 646 # Ask a question with nice options handling 647 #===============================================================================
648 - def ask(self, question, default, choices=[], path_msg=None, 649 timeout = True, fct_timeout=None, ask_class=None, alias={}, 650 first_cmd=None, text_format='4', **opt):
651 """ ask a question with some pre-define possibility 652 path info is 653 """ 654 655 if path_msg: 656 path_msg = [path_msg] 657 else: 658 path_msg = [] 659 660 if timeout: 661 try: 662 timeout = self.options['timeout'] 663 except Exception: 664 pass 665 666 # add choice info to the question 667 if choices + path_msg: 668 question += ' [' 669 question += "\033[%sm%s\033[0m, " % (text_format, default) 670 for data in choices[:9] + path_msg: 671 if default == data: 672 continue 673 else: 674 question += "%s, " % data 675 676 if len(choices) > 9: 677 question += '... , ' 678 question = question[:-2]+']' 679 else: 680 question += "[\033[%sm%s\033[0m] " % (text_format, default) 681 if ask_class: 682 obj = ask_class 683 elif path_msg: 684 obj = OneLinePathCompletion 685 else: 686 obj = SmartQuestion 687 688 if alias: 689 choices += alias.keys() 690 691 question_instance = obj(question, allow_arg=choices, default=default, 692 mother_interface=self, **opt) 693 694 if first_cmd: 695 if isinstance(first_cmd, str): 696 question_instance.onecmd(first_cmd) 697 else: 698 for line in first_cmd: 699 question_instance.onecmd(line) 700 if not self.haspiping: 701 if hasattr(obj, "haspiping"): 702 obj.haspiping = self.haspiping 703 704 705 706 707 answer = self.check_answer_in_input_file(question_instance, default, path_msg) 708 if answer is not None: 709 if answer in alias: 710 answer = alias[answer] 711 if ask_class: 712 answer = question_instance.default(answer) 713 if hasattr(question_instance, 'check_answer_consistency'): 714 question_instance.check_answer_consistency() 715 return answer 716 717 question = question_instance.question 718 value = Cmd.timed_input(question, default, timeout=timeout, 719 fct=question_instance, fct_timeout=fct_timeout) 720 721 try: 722 if value in alias: 723 value = alias[value] 724 except TypeError: 725 pass 726 if value == default and ask_class: 727 value = question_instance.default(default) 728 return value
729
730 - def do_import(self, line):
731 """Advanced commands: Import command files""" 732 733 args = self.split_arg(line) 734 # Check argument's validity 735 self.check_import(args) 736 737 # Execute the card 738 self.import_command_file(args[1])
739
740 - def check_import(self, args):
741 """check import command""" 742 743 if '-f' in args: 744 self.force = True 745 args.remove('-f') 746 if args[0] != 'command': 747 args.set(0, 'command') 748 if len(args) != 2: 749 raise self.InvalidCmd('import command requires one filepath argument') 750 if not os.path.exists(args[1]): 751 raise 'No such file or directory %s' % args[1]
752 753
754 - def check_answer_in_input_file(self, question_instance, default, path=False):
755 """Questions can have answer in output file (or not)""" 756 757 if not self.inputfile: 758 return None# interactive mode 759 760 line = self.get_stored_line() 761 # line define if a previous answer was not answer correctly 762 if not line: 763 try: 764 line = self.inputfile.next() 765 except StopIteration: 766 if self.haspiping: 767 logger.debug('piping') 768 self.store_line(line) 769 return None # print the question and use the pipe 770 logger.info(question_instance.question) 771 logger.info('The answer to the previous question is not set in your input file', '$MG:color:BLACK') 772 logger.info('Use %s value' % default, '$MG:color:BLACK') 773 return str(default) 774 775 line = line.replace('\n','').strip() 776 if '#' in line: 777 line = line.split('#')[0] 778 if not line: 779 # Comment or empty line, pass to the next one 780 return self.check_answer_in_input_file(question_instance, default, path) 781 options = question_instance.allow_arg 782 if line in options: 783 return line 784 elif hasattr(question_instance, 'do_%s' % line.split()[0]): 785 #This is a command line, exec it and check next line 786 logger.info(line) 787 fct = getattr(question_instance, 'do_%s' % line.split()[0]) 788 fct(' '.join(line.split()[1:])) 789 return self.check_answer_in_input_file(question_instance, default, path) 790 elif path: 791 line = os.path.expanduser(os.path.expandvars(line)) 792 if os.path.isfile(line): 793 return line 794 elif any(line.lower()==opt.lower() for opt in options): 795 possibility = [opt for opt in options if line.lower()==opt.lower()] 796 if len (possibility)==1: 797 return possibility[0] 798 799 # No valid answer provides 800 if self.haspiping: 801 self.store_line(line) 802 return None # print the question and use the pipe 803 else: 804 logger.info(question_instance.question) 805 logger.warning('The answer to the previous question is not set in your input file') 806 logger.warning('Use %s value' % default) 807 self.store_line(line) 808 return str(default)
809
810 - def store_line(self, line):
811 """store a line of the input file which should be executed by the higher mother""" 812 813 if self.mother: 814 self.mother.store_line(line) 815 else: 816 self.stored_line = line
817
818 - def get_stored_line(self):
819 """return stored line and clean it""" 820 if self.mother: 821 value = self.mother.get_stored_line() 822 self.mother.stored_line = None 823 else: 824 value = self.stored_line 825 self.stored_line = None 826 return value
827 828 829
830 - def nice_error_handling(self, error, line):
831 """ """ 832 # Make sure that we are at the initial position 833 if self.child: 834 return self.child.nice_error_handling(error, line) 835 836 os.chdir(self.__initpos) 837 # Create the debug files 838 self.log = False 839 if os.path.exists(self.debug_output): 840 os.remove(self.debug_output) 841 try: 842 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output.replace(' ', '\ ')) 843 except Exception, error: 844 logger.error(error) 845 846 debug_file = open(self.debug_output, 'a') 847 traceback.print_exc(file=debug_file) 848 if hasattr(error, 'filename'): 849 debug_file.write("Related File: %s\n" % error.filename) 850 # Create a nice error output 851 if self.history and line == self.history[-1]: 852 error_text = 'Command \"%s\" interrupted with error:\n' % line 853 elif self.history: 854 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line 855 error_text += '\"%s\" with error:\n' % self.history[-1] 856 else: 857 error_text = '' 858 error_text += '%s : %s\n' % (error.__class__.__name__, 859 str(error).replace('\n','\n\t')) 860 error_text += self.error_debug % {'debug':self.debug_output} 861 logger_stderr.critical(error_text) 862 863 864 # Add options status to the debug file 865 try: 866 self.do_display('options', debug_file) 867 except Exception, error: 868 debug_file.write('Fail to write options with error %s' % error) 869 870 #add the cards: 871 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']: 872 try: 873 ff = open(pjoin(self.me_dir, 'Cards', card)) 874 debug_file.write(ff.read()) 875 ff.close() 876 except Exception: 877 pass 878 879 #stop the execution if on a non interactive mode 880 if self.use_rawinput == False: 881 return True 882 return False
883 884 885
886 - def nice_user_error(self, error, line):
887 if self.child: 888 return self.child.nice_user_error(error, line) 889 # Make sure that we are at the initial position 890 os.chdir(self.__initpos) 891 if line == self.history[-1]: 892 error_text = 'Command \"%s\" interrupted with error:\n' % line 893 else: 894 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line 895 error_text += '\"%s\" with error:\n' % self.history[-1] 896 error_text += '%s : %s' % (error.__class__.__name__, 897 str(error).replace('\n','\n\t')) 898 logger_stderr.error(error_text) 899 #stop the execution if on a non interactive mode 900 if self.use_rawinput == False: 901 return True 902 # Remove failed command from history 903 self.history.pop() 904 return False
905
906 - def nice_config_error(self, error, line):
907 if self.child: 908 return self.child.nice_user_error(error, line) 909 # Make sure that we are at the initial position 910 os.chdir(self.__initpos) 911 if not self.history or line == self.history[-1]: 912 error_text = 'Error detected in \"%s\"\n' % line 913 else: 914 error_text = 'Error detected in sub-command %s\n' % self.history[-1] 915 error_text += 'write debug file %s \n' % self.debug_output 916 self.log = False 917 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output) 918 debug_file = open(self.debug_output, 'a') 919 traceback.print_exc(file=debug_file) 920 error_text += self.config_debug % {'debug' :self.debug_output} 921 error_text += '%s : %s' % (error.__class__.__name__, 922 str(error).replace('\n','\n\t')) 923 logger_stderr.error(error_text) 924 925 # Add options status to the debug file 926 try: 927 self.do_display('options', debug_file) 928 except Exception, error: 929 debug_file.write('Fail to write options with error %s' % error) 930 #stop the execution if on a non interactive mode 931 if self.use_rawinput == False: 932 return True 933 # Remove failed command from history 934 if self.history: 935 self.history.pop() 936 return False
937
938 - def onecmd_orig(self, line, **opt):
939 """Interpret the argument as though it had been typed in response 940 to the prompt. 941 942 The return value is a flag indicating whether interpretation of 943 commands by the interpreter should stop. 944 945 This allow to pass extra argument for internal call. 946 """ 947 if '~/' in line and os.environ.has_key('HOME'): 948 line = line.replace('~/', '%s/' % os.environ['HOME']) 949 if '#' in line: 950 line = line.split('#')[0] 951 952 line = os.path.expandvars(line) 953 cmd, arg, line = self.parseline(line) 954 if not line: 955 return self.emptyline() 956 if cmd is None: 957 return self.default(line) 958 self.lastcmd = line 959 if cmd == '': 960 return self.default(line) 961 else: 962 try: 963 func = getattr(self, 'do_' + cmd) 964 except AttributeError: 965 return self.default(line) 966 return func(arg, **opt)
967
968 - def error_handling(self, error, line):
969 970 me_dir = '' 971 if hasattr(self, 'me_dir'): 972 me_dir = os.path.basename(me_dir) + ' ' 973 974 975 try: 976 raise 977 except self.InvalidCmd as error: 978 if __debug__: 979 self.nice_error_handling(error, line) 980 self.history.pop() 981 else: 982 self.nice_user_error(error, line) 983 if self.allow_notification_center: 984 misc.apple_notify('Run %sfailed' % me_dir, 985 'Invalid Command: %s' % error.__class__.__name__) 986 987 except self.ConfigurationError as error: 988 self.nice_config_error(error, line) 989 if self.allow_notification_center: 990 misc.apple_notify('Run %sfailed' % me_dir, 991 'Configuration error') 992 except Exception as error: 993 self.nice_error_handling(error, line) 994 if self.mother: 995 self.do_quit('') 996 if self.allow_notification_center: 997 misc.apple_notify('Run %sfailed' % me_dir, 998 'Exception: %s' % error.__class__.__name__) 999 except KeyboardInterrupt as error: 1000 self.stop_on_keyboard_stop() 1001 if __debug__: 1002 self.nice_config_error(error, line) 1003 logger.error(self.keyboard_stop_msg)
1004 1005 1006
1007 - def onecmd(self, line, **opt):
1008 """catch all error and stop properly command accordingly""" 1009 1010 try: 1011 return self.onecmd_orig(line, **opt) 1012 except BaseException, error: 1013 self.error_handling(error, line)
1014 1015
1016 - def stop_on_keyboard_stop(self):
1017 """action to perform to close nicely on a keyboard interupt""" 1018 pass # dummy function
1019
1020 - def exec_cmd(self, line, errorhandling=False, printcmd=True, 1021 precmd=False, postcmd=True, **opt):
1022 """for third party call, call the line with pre and postfix treatment 1023 without global error handling """ 1024 1025 if printcmd and not line.startswith('#'): 1026 logger.info(line) 1027 if self.child: 1028 current_interface = self.child 1029 else: 1030 current_interface = self 1031 1032 if precmd: 1033 line = current_interface.precmd(line) 1034 if errorhandling: 1035 stop = current_interface.onecmd(line, **opt) 1036 else: 1037 stop = Cmd.onecmd_orig(current_interface, line, **opt) 1038 if postcmd: 1039 stop = current_interface.postcmd(stop, line) 1040 return stop
1041
1042 - def run_cmd(self, line):
1043 """for third party call, call the line with pre and postfix treatment 1044 with global error handling""" 1045 1046 return self.exec_cmd(line, errorhandling=True, precmd=True)
1047
1048 - def emptyline(self):
1049 """If empty line, do nothing. Default is repeat previous command.""" 1050 pass
1051
1052 - def default(self, line, log=True):
1053 """Default action if line is not recognized""" 1054 1055 # Faulty command 1056 if log: 1057 logger.warning("Command \"%s\" not recognized, please try again" % \ 1058 line.split()[0]) 1059 if line.strip() in ['q', '.q', 'stop']: 1060 logger.info("If you want to quit mg5 please type \"exit\".") 1061 1062 if self.history and self.history[-1] == line: 1063 self.history.pop()
1064 1065 1066 1067 1068 1069 # Write the list of command line use in this session
1070 - def do_history(self, line):
1071 """write in a file the suite of command that was used""" 1072 1073 args = self.split_arg(line) 1074 # Check arguments validity 1075 self.check_history(args) 1076 1077 if len(args) == 0: 1078 logger.info('\n'.join(self.history)) 1079 return 1080 elif args[0] == 'clean': 1081 self.history = [] 1082 logger.info('History is cleaned') 1083 return 1084 elif args[0] == '.': 1085 output_file = os.path.join(self._export_dir, 'Cards', \ 1086 'proc_card_mg5.dat') 1087 output_file = open(output_file, 'w') 1088 else: 1089 output_file = open(args[0], 'w') 1090 1091 # Create the command file 1092 text = self.get_history_header() 1093 text += ('\n'.join(self.history) + '\n') 1094 1095 #write this information in a file 1096 output_file.write(text) 1097 output_file.close() 1098 1099 if self.log: 1100 logger.info("History written to " + output_file.name)
1101
1102 - def compile(self, *args, **opts):
1103 """ """ 1104 1105 return misc.compile(nb_core=self.options['nb_core'], *args, **opts)
1106
1107 - def avoid_history_duplicate(self, line, no_break=[]):
1108 """remove all line in history (but the last) starting with line. 1109 up to the point when a line didn't start by something in no_break. 1110 (reading in reverse order)""" 1111 1112 new_history = [] 1113 for i in range(1, len(self.history)+1): 1114 cur_line = self.history[-i] 1115 if i == 1: 1116 new_history.append(cur_line) 1117 elif not any((cur_line.startswith(text) for text in no_break)): 1118 to_add = self.history[:-i+1] 1119 to_add.reverse() 1120 new_history += to_add 1121 break 1122 elif cur_line.startswith(line): 1123 continue 1124 else: 1125 new_history.append(cur_line) 1126 1127 new_history.reverse() 1128 self.history[:] = new_history
1129 1130
1131 - def import_command_file(self, filepath):
1132 # remove this call from history 1133 if self.history: 1134 self.history.pop() 1135 1136 #avoid that command of other file interfere with this one. 1137 previous_store_line = self.get_stored_line() 1138 1139 # Read the lines of the file and execute them 1140 if isinstance(filepath, str): 1141 commandline = open(filepath).readlines() 1142 else: 1143 commandline = filepath 1144 oldinputfile = self.inputfile 1145 oldraw = self.use_rawinput 1146 self.inputfile = (l for l in commandline) # make a generator 1147 self.use_rawinput = False 1148 # Note using "for line in open(filepath)" is not safe since the file 1149 # filepath can be overwritten during the run (leading to weird results) 1150 # Note also that we need a generator and not a list. 1151 for line in self.inputfile: 1152 #remove pointless spaces and \n 1153 line = line.replace('\n', '').strip() 1154 # execute the line 1155 if line: 1156 self.exec_cmd(line, precmd=True) 1157 stored = self.get_stored_line() 1158 while stored: 1159 line = stored 1160 self.exec_cmd(line, precmd=True) 1161 stored = self.get_stored_line() 1162 1163 # If a child was open close it 1164 if self.child: 1165 self.child.exec_cmd('quit') 1166 self.inputfile = oldinputfile 1167 self.use_rawinput = oldraw 1168 1169 # restore original store line 1170 cmd = self 1171 while hasattr(cmd, 'mother') and cmd.mother: 1172 cmd = cmd.mother 1173 cmd.stored_line = previous_store_line 1174 return
1175
1176 - def get_history_header(self):
1177 """Default history header""" 1178 1179 return self.history_header
1180
1181 - def postloop(self):
1182 """ """ 1183 1184 args = self.split_arg(self.lastcmd) 1185 if args and args[0] in ['quit','exit']: 1186 if 'all' in args: 1187 return True 1188 if len(args) >1 and args[1].isdigit(): 1189 if args[1] not in ['0', '1']: 1190 return True 1191 return False
1192 1193 #=============================================================================== 1194 # Ask a question with a maximum amount of time to answer 1195 #=============================================================================== 1196 @staticmethod
1197 - def timed_input(question, default, timeout=None, noerror=True, fct=None, 1198 fct_timeout=None):
1199 """ a question with a maximal time to answer take default otherwise""" 1200 1201 def handle_alarm(signum, frame): 1202 raise TimeOutError
1203 1204 signal.signal(signal.SIGALRM, handle_alarm) 1205 1206 if fct is None: 1207 fct = raw_input 1208 1209 if timeout: 1210 signal.alarm(timeout) 1211 question += '[%ss to answer] ' % (timeout) 1212 try: 1213 result = fct(question) 1214 except TimeOutError: 1215 if noerror: 1216 logger.info('\nuse %s' % default) 1217 if fct_timeout: 1218 fct_timeout(True) 1219 return default 1220 else: 1221 signal.alarm(0) 1222 raise 1223 finally: 1224 signal.alarm(0) 1225 if fct_timeout: 1226 fct_timeout(False) 1227 return result
1228 1229 1230 1231 1232 1233 1234 # Quit
1235 - def do_quit(self, line):
1236 """Not in help: exit the mainloop() """ 1237 1238 if self.child: 1239 self.child.exec_cmd('quit ' + line, printcmd=False) 1240 return 1241 elif self.mother: 1242 self.mother.child = None 1243 if line == 'all': 1244 pass 1245 elif line: 1246 level = int(line) - 1 1247 if level: 1248 self.mother.lastcmd = 'quit %s' % level 1249 logger.info(' ') 1250 return True
1251 1252 # Aliases 1253 do_EOF = do_quit 1254 do_exit = do_quit 1255
1256 - def do_help(self, line):
1257 """Not in help: propose some usefull possible action """ 1258 1259 # if they are an argument use the default help 1260 if line: 1261 return cmd.Cmd.do_help(self, line) 1262 1263 1264 names = self.get_names() 1265 cmds = {} 1266 names.sort() 1267 # There can be duplicates if routines overridden 1268 prevname = '' 1269 for name in names: 1270 if name[:3] == 'do_': 1271 if name == prevname: 1272 continue 1273 prevname = name 1274 cmdname=name[3:] 1275 try: 1276 doc = getattr(self.cmd, name).__doc__ 1277 except Exception: 1278 doc = None 1279 if not doc: 1280 doc = getattr(self, name).__doc__ 1281 if not doc: 1282 tag = "Documented commands" 1283 elif ':' in doc: 1284 tag = doc.split(':',1)[0] 1285 else: 1286 tag = "Documented commands" 1287 if tag in cmds: 1288 cmds[tag].append(cmdname) 1289 else: 1290 cmds[tag] = [cmdname] 1291 1292 self.stdout.write("%s\n"%str(self.doc_leader)) 1293 for tag in self.helporder: 1294 if tag not in cmds: 1295 continue 1296 header = "%s (type help <topic>):" % tag 1297 self.print_topics(header, cmds[tag], 15,80) 1298 for name, item in cmds.items(): 1299 if name in self.helporder: 1300 continue 1301 if name == "Not in help": 1302 continue 1303 header = "%s (type help <topic>):" % name 1304 self.print_topics(header, item, 15,80) 1305 1306 1307 ## Add contextual help 1308 if len(self.history) == 0: 1309 last_action_2 = last_action = 'start' 1310 else: 1311 last_action_2 = last_action = 'none' 1312 1313 pos = 0 1314 authorize = self.next_possibility.keys() 1315 while last_action_2 not in authorize and last_action not in authorize: 1316 pos += 1 1317 if pos > len(self.history): 1318 last_action_2 = last_action = 'start' 1319 break 1320 1321 args = self.history[-1 * pos].split() 1322 last_action = args[0] 1323 if len(args)>1: 1324 last_action_2 = '%s %s' % (last_action, args[1]) 1325 else: 1326 last_action_2 = 'none' 1327 1328 logger.info('Contextual Help') 1329 logger.info('===============') 1330 if last_action_2 in authorize: 1331 options = self.next_possibility[last_action_2] 1332 elif last_action in authorize: 1333 options = self.next_possibility[last_action] 1334 else: 1335 return 1336 text = 'The following command(s) may be useful in order to continue.\n' 1337 for option in options: 1338 text+='\t %s \n' % option 1339 logger.info(text)
1340
1341 - def do_display(self, line, output=sys.stdout):
1342 """Advanced commands: basic display""" 1343 1344 args = self.split_arg(line) 1345 #check the validity of the arguments 1346 1347 if len(args) == 0: 1348 self.help_display() 1349 raise self.InvalidCmd, 'display require at least one argument' 1350 1351 if args[0] == "options": 1352 outstr = "Value of current Options:\n" 1353 for key, value in self.options.items(): 1354 outstr += '%25s \t:\t%s\n' %(key,value) 1355 output.write(outstr) 1356 1357 elif args[0] == "variable": 1358 outstr = "Value of Internal Variable:\n" 1359 try: 1360 var = eval(args[1]) 1361 except Exception: 1362 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1] 1363 else: 1364 outstr += 'GLOBAL:\n' 1365 outstr += misc.nice_representation(var, nb_space=4) 1366 1367 try: 1368 var = eval('self.%s' % args[1]) 1369 except Exception: 1370 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1] 1371 else: 1372 outstr += 'LOCAL:\n' 1373 outstr += misc.nice_representation(var, nb_space=4) 1374 split = args[1].split('.') 1375 for i, name in enumerate(split): 1376 try: 1377 __import__('.'.join(split[:i+1])) 1378 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1]))) 1379 except ImportError: 1380 try: 1381 var = eval(args[1]) 1382 except Exception, error: 1383 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1] 1384 break 1385 else: 1386 outstr += 'EXTERNAL:\n' 1387 outstr += misc.nice_representation(var, nb_space=4) 1388 else: 1389 var = eval(args[1]) 1390 outstr += 'EXTERNAL:\n' 1391 outstr += misc.nice_representation(var, nb_space=4) 1392 1393 pydoc.pager(outstr)
1394 1395
1396 - def do_save(self, line, check=True):
1397 """Save the configuration file""" 1398 1399 args = self.split_arg(line) 1400 # Check argument validity 1401 if check: 1402 Cmd.check_save(self, args) 1403 1404 # find base file for the configuration 1405 if'HOME' in os.environ and os.environ['HOME'] and \ 1406 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')): 1407 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt') 1408 if hasattr(self, 'me_dir'): 1409 basedir = self.me_dir 1410 elif not MADEVENT: 1411 basedir = MG5DIR 1412 else: 1413 basedir = os.getcwd() 1414 elif MADEVENT: 1415 # launch via ./bin/madevent 1416 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']: 1417 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)): 1418 base = pjoin(self.me_dir, 'Cards', config_file) 1419 basedir = self.me_dir 1420 else: 1421 if hasattr(self, 'me_dir'): 1422 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 1423 if len(args) == 0 and os.path.exists(base): 1424 self.write_configuration(base, base, self.me_dir) 1425 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 1426 basedir = MG5DIR 1427 1428 if len(args) == 0: 1429 args.append(base) 1430 self.write_configuration(args[0], base, basedir, self.options)
1431
1432 - def write_configuration(self, filepath, basefile, basedir, to_keep):
1433 """Write the configuration file""" 1434 # We use the default configuration file as a template. 1435 # to ensure that all configuration information are written we 1436 # keep track of all key that we need to write. 1437 1438 logger.info('save configuration file to %s' % filepath) 1439 to_write = to_keep.keys() 1440 text = "" 1441 # Use local configuration => Need to update the path 1442 for line in file(basefile): 1443 if '=' in line: 1444 data, value = line.split('=',1) 1445 else: 1446 text += line 1447 continue 1448 data = data.strip() 1449 if data.startswith('#'): 1450 key = data[1:].strip() 1451 else: 1452 key = data 1453 if '#' in value: 1454 value, comment = value.split('#',1) 1455 else: 1456 comment = '' 1457 if key in to_keep: 1458 value = str(to_keep[key]) 1459 else: 1460 text += line 1461 continue 1462 try: 1463 to_write.remove(key) 1464 except Exception: 1465 pass 1466 if '_path' in key: 1467 # special case need to update path 1468 # check if absolute path 1469 if not os.path.isabs(value): 1470 value = os.path.realpath(os.path.join(basedir, value)) 1471 text += '%s = %s # %s \n' % (key, value, comment) 1472 for key in to_write: 1473 if key in to_keep: 1474 text += '%s = %s \n' % (key, to_keep[key]) 1475 1476 if not MADEVENT: 1477 text += """\n# MG5 MAIN DIRECTORY\n""" 1478 text += "mg5_path = %s\n" % MG5DIR 1479 1480 writer = open(filepath,'w') 1481 writer.write(text) 1482 writer.close()
1483
1484 1485 1486 1487 -class CmdShell(Cmd):
1488 """CMD command with shell activate""" 1489 1490 # Access to shell
1491 - def do_shell(self, line):
1492 "Run a shell command" 1493 1494 if line.strip() is '': 1495 self.help_shell() 1496 else: 1497 logging.info("running shell command: " + line) 1498 subprocess.call(line, shell=True)
1499
1500 - def complete_shell(self, text, line, begidx, endidx):
1501 """ add path for shell """ 1502 1503 # Filename if directory is given 1504 # 1505 if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep: 1506 if not text: 1507 text = '' 1508 output = self.path_completion(text, 1509 base_dir=\ 1510 self.split_arg(line[0:begidx])[-1]) 1511 else: 1512 output = self.path_completion(text) 1513 return output
1514
1515 - def help_shell(self):
1516 """help for the shell""" 1517 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE') 1518 logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
1519
1520 1521 1522 1523 #=============================================================================== 1524 # Question with auto-completion 1525 #=============================================================================== 1526 -class SmartQuestion(BasicCmd):
1527 """ a class for answering a question with the path autocompletion""" 1528
1529 - def preloop(self):
1530 """Initializing before starting the main loop""" 1531 self.prompt = '>' 1532 self.value = None 1533 BasicCmd.preloop(self)
1534 1535
1536 - def __init__(self, question, allow_arg=[], default=None, 1537 mother_interface=None, *arg, **opt):
1538 self.question = question 1539 self.wrong_answer = 0 # forbids infinite loop 1540 self.allow_arg = [str(a) for a in allow_arg] 1541 self.history_header = '' 1542 self.default_value = str(default) 1543 self.mother_interface = mother_interface 1544 cmd.Cmd.__init__(self, *arg, **opt)
1545
1546 - def __call__(self, question, reprint_opt=True, **opts):
1547 1548 self.question = question 1549 for key,value in opts: 1550 setattr(self, key, value) 1551 if reprint_opt: 1552 print question 1553 return self.cmdloop()
1554 1555
1556 - def completenames(self, text, line, *ignored):
1557 prev_timer = signal.alarm(0) # avoid timer if any 1558 if prev_timer: 1559 nb_back = len(line) 1560 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1561 self.stdout.write(line) 1562 self.stdout.flush() 1563 try: 1564 out = {} 1565 out[' Options'] = Cmd.list_completion(text, self.allow_arg) 1566 out[' Recognized command'] = BasicCmd.completenames(self, text) 1567 1568 return self.deal_multiple_categories(out) 1569 except Exception, error: 1570 print error
1571
1572 - def get_names(self):
1573 # This method used to pull in base class attributes 1574 # at a time dir() didn't do it yet. 1575 return dir(self)
1576
1577 - def onecmd(self, line, **opt):
1578 """catch all error and stop properly command accordingly 1579 Interpret the argument as though it had been typed in response 1580 to the prompt. 1581 1582 The return value is a flag indicating whether interpretation of 1583 commands by the interpreter should stop. 1584 1585 This allow to pass extra argument for internal call. 1586 """ 1587 try: 1588 if '~/' in line and os.environ.has_key('HOME'): 1589 line = line.replace('~/', '%s/' % os.environ['HOME']) 1590 line = os.path.expandvars(line) 1591 cmd, arg, line = self.parseline(line) 1592 if not line: 1593 return self.emptyline() 1594 if cmd is None: 1595 return self.default(line) 1596 self.lastcmd = line 1597 if cmd == '': 1598 return self.default(line) 1599 else: 1600 try: 1601 func = getattr(self, 'do_' + cmd) 1602 except AttributeError: 1603 return self.default(line) 1604 return func(arg, **opt) 1605 except Exception as error: 1606 logger.warning(error)
1607
1608 - def reask(self, reprint_opt=True):
1609 pat = re.compile('\[(\d*)s to answer\]') 1610 prev_timer = signal.alarm(0) # avoid timer if any 1611 1612 if prev_timer: 1613 if pat.search(self.question): 1614 timeout = int(pat.search(self.question).groups()[0]) 1615 else: 1616 timeout=20 1617 print 1618 signal.alarm(timeout) 1619 if reprint_opt: 1620 if not prev_timer: 1621 self.question = pat.sub('',self.question) 1622 print self.question 1623 return False
1624
1625 - def default(self, line):
1626 """Default action if line is not recognized""" 1627 1628 if line.strip() == '' and self.default_value is not None: 1629 self.value = self.default_value 1630 else: 1631 self.value = line
1632
1633 - def emptyline(self):
1634 """If empty line, return default""" 1635 1636 if self.default_value is not None: 1637 self.value = self.default_value
1638 1639
1640 - def postcmd(self, stop, line):
1641 1642 try: 1643 if self.value in self.allow_arg: 1644 return True 1645 elif str(self.value) == 'EOF': 1646 self.value = self.default_value 1647 return True 1648 elif line and hasattr(self, 'do_%s' % line.split()[0]): 1649 return self.reask() 1650 elif self.value == 'repeat': 1651 return self.reask() 1652 elif len(self.allow_arg)==0: 1653 return True 1654 else: 1655 raise Exception 1656 except Exception,error: 1657 if self.wrong_answer < 100: 1658 self.wrong_answer += 1 1659 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \ 1660 % (self.value,','.join(self.allow_arg))) 1661 logger.warning('please retry') 1662 return False 1663 else: 1664 self.value = self.default_value 1665 return True
1666
1667 - def cmdloop(self, intro=None):
1668 cmd.Cmd.cmdloop(self, intro) 1669 return self.value
1670
1671 # a function helper 1672 -def smart_input(input_text, allow_arg=[], default=None):
1673 print input_text 1674 obj = SmartQuestion(allow_arg=allow_arg, default=default) 1675 return obj.cmdloop()
1676
1677 #=============================================================================== 1678 # Question in order to return a path with auto-completion 1679 #=============================================================================== 1680 -class OneLinePathCompletion(SmartQuestion):
1681 """ a class for answering a question with the path autocompletion""" 1682 1683 completion_prefix='' 1684
1685 - def completenames(self, text, line, begidx, endidx):
1686 prev_timer = signal.alarm(0) # avoid timer if any 1687 if prev_timer: 1688 nb_back = len(line) 1689 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1690 self.stdout.write(line) 1691 self.stdout.flush() 1692 1693 try: 1694 out = {} 1695 out[' Options'] = Cmd.list_completion(text, self.allow_arg) 1696 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False) 1697 out[' Recognized command'] = BasicCmd.completenames(self, text) 1698 1699 return self.deal_multiple_categories(out) 1700 except Exception, error: 1701 print error
1702
1703 - def precmd(self, *args):
1704 """ """ 1705 1706 signal.alarm(0) 1707 return SmartQuestion.precmd(self, *args)
1708
1709 - def completedefault(self,text, line, begidx, endidx):
1710 prev_timer = signal.alarm(0) # avoid timer if any 1711 if prev_timer: 1712 nb_back = len(line) 1713 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1714 self.stdout.write(line) 1715 self.stdout.flush() 1716 try: 1717 args = Cmd.split_arg(line[0:begidx]) 1718 except Exception, error: 1719 print error 1720 1721 # Directory continuation 1722 if args[-1].endswith(os.path.sep): 1723 1724 return Cmd.path_completion(text, 1725 os.path.join('.',*[a for a in args \ 1726 if a.endswith(os.path.sep)])) 1727 self.completenames(line+text)
1728 1729
1730 - def postcmd(self, stop, line):
1731 try: 1732 if self.value in self.allow_arg: 1733 return True 1734 elif self.value and os.path.isfile(self.value): 1735 return os.path.relpath(self.value) 1736 elif self.value and str(self.value) == 'EOF': 1737 self.value = self.default_value 1738 return True 1739 elif line and hasattr(self, 'do_%s' % line.split()[0]): 1740 # go to retry 1741 reprint_opt = True 1742 elif self.value == 'repeat': 1743 reprint_opt = True 1744 else: 1745 raise Exception 1746 except Exception, error: 1747 print """not valid argument. Valid argument are file path or value in (%s).""" \ 1748 % ','.join(self.allow_arg) 1749 print 'please retry' 1750 reprint_opt = False 1751 1752 return self.reask(reprint_opt)
1753
1754 1755 # a function helper 1756 -def raw_path_input(input_text, allow_arg=[], default=None):
1757 print input_text 1758 obj = OneLinePathCompletion(allow_arg=allow_arg, default=default ) 1759 return obj.cmdloop()
1760
1761 #=============================================================================== 1762 # 1763 #=============================================================================== 1764 -class CmdFile(file):
1765 """ a class for command input file -in order to debug cmd \n problem""" 1766
1767 - def __init__(self, name, opt='rU'):
1768 1769 file.__init__(self, name, opt) 1770 self.text = file.read(self) 1771 self.close() 1772 self.lines = self.text.split('\n')
1773
1774 - def readline(self, *arg, **opt):
1775 """readline method treating correctly a line whithout \n at the end 1776 (add it) 1777 """ 1778 if self.lines: 1779 line = self.lines.pop(0) 1780 else: 1781 return '' 1782 1783 if line.endswith('\n'): 1784 return line 1785 else: 1786 return line + '\n'
1787
1788 - def __next__(self):
1789 return self.lines.__next__()
1790
1791 - def __iter__(self):
1792 return self.lines.__iter__()
1793