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 # Create a nice error output 849 if self.history and line == self.history[-1]: 850 error_text = 'Command \"%s\" interrupted with error:\n' % line 851 elif self.history: 852 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line 853 error_text += '\"%s\" with error:\n' % self.history[-1] 854 else: 855 error_text = '' 856 error_text += '%s : %s\n' % (error.__class__.__name__, 857 str(error).replace('\n','\n\t')) 858 error_text += self.error_debug % {'debug':self.debug_output} 859 logger_stderr.critical(error_text) 860 861 862 # Add options status to the debug file 863 try: 864 self.do_display('options', debug_file) 865 except Exception, error: 866 debug_file.write('Fail to write options with error %s' % error) 867 868 #add the cards: 869 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']: 870 try: 871 ff = open(pjoin(self.me_dir, 'Cards', card)) 872 debug_file.write(ff.read()) 873 ff.close() 874 except Exception: 875 pass 876 877 #stop the execution if on a non interactive mode 878 if self.use_rawinput == False: 879 return True 880 return False
881 882 883
884 - def nice_user_error(self, error, line):
885 if self.child: 886 return self.child.nice_user_error(error, line) 887 # Make sure that we are at the initial position 888 os.chdir(self.__initpos) 889 if line == self.history[-1]: 890 error_text = 'Command \"%s\" interrupted with error:\n' % line 891 else: 892 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line 893 error_text += '\"%s\" with error:\n' % self.history[-1] 894 error_text += '%s : %s' % (error.__class__.__name__, 895 str(error).replace('\n','\n\t')) 896 logger_stderr.error(error_text) 897 #stop the execution if on a non interactive mode 898 if self.use_rawinput == False: 899 return True 900 # Remove failed command from history 901 self.history.pop() 902 return False
903
904 - def nice_config_error(self, error, line):
905 if self.child: 906 return self.child.nice_user_error(error, line) 907 # Make sure that we are at the initial position 908 os.chdir(self.__initpos) 909 if not self.history or line == self.history[-1]: 910 error_text = 'Error detected in \"%s\"\n' % line 911 else: 912 error_text = 'Error detected in sub-command %s\n' % self.history[-1] 913 error_text += 'write debug file %s \n' % self.debug_output 914 self.log = False 915 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output) 916 debug_file = open(self.debug_output, 'a') 917 traceback.print_exc(file=debug_file) 918 error_text += self.config_debug % {'debug' :self.debug_output} 919 error_text += '%s : %s' % (error.__class__.__name__, 920 str(error).replace('\n','\n\t')) 921 logger_stderr.error(error_text) 922 923 # Add options status to the debug file 924 try: 925 self.do_display('options', debug_file) 926 except Exception, error: 927 debug_file.write('Fail to write options with error %s' % error) 928 #stop the execution if on a non interactive mode 929 if self.use_rawinput == False: 930 return True 931 # Remove failed command from history 932 if self.history: 933 self.history.pop() 934 return False
935
936 - def onecmd_orig(self, line, **opt):
937 """Interpret the argument as though it had been typed in response 938 to the prompt. 939 940 The return value is a flag indicating whether interpretation of 941 commands by the interpreter should stop. 942 943 This allow to pass extra argument for internal call. 944 """ 945 if '~/' in line and os.environ.has_key('HOME'): 946 line = line.replace('~/', '%s/' % os.environ['HOME']) 947 if '#' in line: 948 line = line.split('#')[0] 949 950 line = os.path.expandvars(line) 951 cmd, arg, line = self.parseline(line) 952 if not line: 953 return self.emptyline() 954 if cmd is None: 955 return self.default(line) 956 self.lastcmd = line 957 if cmd == '': 958 return self.default(line) 959 else: 960 try: 961 func = getattr(self, 'do_' + cmd) 962 except AttributeError: 963 return self.default(line) 964 return func(arg, **opt)
965
966 - def error_handling(self, error, line):
967 968 me_dir = '' 969 if hasattr(self, 'me_dir'): 970 me_dir = os.path.basename(me_dir) + ' ' 971 972 973 try: 974 raise 975 except self.InvalidCmd as error: 976 if __debug__: 977 self.nice_error_handling(error, line) 978 self.history.pop() 979 else: 980 self.nice_user_error(error, line) 981 if self.allow_notification_center: 982 misc.apple_notify('Run %sfailed' % me_dir, 983 'Invalid Command: %s' % error.__class__.__name__) 984 985 except self.ConfigurationError as error: 986 self.nice_config_error(error, line) 987 if self.allow_notification_center: 988 misc.apple_notify('Run %sfailed' % me_dir, 989 'Configuration error') 990 except Exception as error: 991 self.nice_error_handling(error, line) 992 if self.mother: 993 self.do_quit('') 994 if self.allow_notification_center: 995 misc.apple_notify('Run %sfailed' % me_dir, 996 'Exception: %s' % error.__class__.__name__) 997 except KeyboardInterrupt as error: 998 self.stop_on_keyboard_stop() 999 if __debug__: 1000 self.nice_config_error(error, line) 1001 logger.error(self.keyboard_stop_msg)
1002 1003 1004
1005 - def onecmd(self, line, **opt):
1006 """catch all error and stop properly command accordingly""" 1007 1008 try: 1009 return self.onecmd_orig(line, **opt) 1010 except BaseException, error: 1011 self.error_handling(error, line)
1012 1013
1014 - def stop_on_keyboard_stop(self):
1015 """action to perform to close nicely on a keyboard interupt""" 1016 pass # dummy function
1017
1018 - def exec_cmd(self, line, errorhandling=False, printcmd=True, 1019 precmd=False, postcmd=True, **opt):
1020 """for third party call, call the line with pre and postfix treatment 1021 without global error handling """ 1022 1023 if printcmd and not line.startswith('#'): 1024 logger.info(line) 1025 if self.child: 1026 current_interface = self.child 1027 else: 1028 current_interface = self 1029 1030 if precmd: 1031 line = current_interface.precmd(line) 1032 if errorhandling: 1033 stop = current_interface.onecmd(line, **opt) 1034 else: 1035 stop = Cmd.onecmd_orig(current_interface, line, **opt) 1036 if postcmd: 1037 stop = current_interface.postcmd(stop, line) 1038 return stop
1039
1040 - def run_cmd(self, line):
1041 """for third party call, call the line with pre and postfix treatment 1042 with global error handling""" 1043 1044 return self.exec_cmd(line, errorhandling=True, precmd=True)
1045
1046 - def emptyline(self):
1047 """If empty line, do nothing. Default is repeat previous command.""" 1048 pass
1049
1050 - def default(self, line, log=True):
1051 """Default action if line is not recognized""" 1052 1053 # Faulty command 1054 if log: 1055 logger.warning("Command \"%s\" not recognized, please try again" % \ 1056 line.split()[0]) 1057 if line.strip() in ['q', '.q', 'stop']: 1058 logger.info("If you want to quit mg5 please type \"exit\".") 1059 1060 if self.history and self.history[-1] == line: 1061 self.history.pop()
1062 1063 1064 1065 1066 1067 # Write the list of command line use in this session
1068 - def do_history(self, line):
1069 """write in a file the suite of command that was used""" 1070 1071 args = self.split_arg(line) 1072 # Check arguments validity 1073 self.check_history(args) 1074 1075 if len(args) == 0: 1076 logger.info('\n'.join(self.history)) 1077 return 1078 elif args[0] == 'clean': 1079 self.history = [] 1080 logger.info('History is cleaned') 1081 return 1082 elif args[0] == '.': 1083 output_file = os.path.join(self._export_dir, 'Cards', \ 1084 'proc_card_mg5.dat') 1085 output_file = open(output_file, 'w') 1086 else: 1087 output_file = open(args[0], 'w') 1088 1089 # Create the command file 1090 text = self.get_history_header() 1091 text += ('\n'.join(self.history) + '\n') 1092 1093 #write this information in a file 1094 output_file.write(text) 1095 output_file.close() 1096 1097 if self.log: 1098 logger.info("History written to " + output_file.name)
1099
1100 - def compile(self, *args, **opts):
1101 """ """ 1102 1103 return misc.compile(nb_core=self.options['nb_core'], *args, **opts)
1104
1105 - def avoid_history_duplicate(self, line, no_break=[]):
1106 """remove all line in history (but the last) starting with line. 1107 up to the point when a line didn't start by something in no_break. 1108 (reading in reverse order)""" 1109 1110 new_history = [] 1111 for i in range(1, len(self.history)+1): 1112 cur_line = self.history[-i] 1113 if i == 1: 1114 new_history.append(cur_line) 1115 elif not any((cur_line.startswith(text) for text in no_break)): 1116 to_add = self.history[:-i+1] 1117 to_add.reverse() 1118 new_history += to_add 1119 break 1120 elif cur_line.startswith(line): 1121 continue 1122 else: 1123 new_history.append(cur_line) 1124 1125 new_history.reverse() 1126 self.history[:] = new_history
1127 1128
1129 - def import_command_file(self, filepath):
1130 # remove this call from history 1131 if self.history: 1132 self.history.pop() 1133 1134 #avoid that command of other file interfere with this one. 1135 previous_store_line = self.get_stored_line() 1136 1137 # Read the lines of the file and execute them 1138 if isinstance(filepath, str): 1139 commandline = open(filepath).readlines() 1140 else: 1141 commandline = filepath 1142 oldinputfile = self.inputfile 1143 oldraw = self.use_rawinput 1144 self.inputfile = (l for l in commandline) # make a generator 1145 self.use_rawinput = False 1146 # Note using "for line in open(filepath)" is not safe since the file 1147 # filepath can be overwritten during the run (leading to weird results) 1148 # Note also that we need a generator and not a list. 1149 for line in self.inputfile: 1150 #remove pointless spaces and \n 1151 line = line.replace('\n', '').strip() 1152 # execute the line 1153 if line: 1154 self.exec_cmd(line, precmd=True) 1155 stored = self.get_stored_line() 1156 while stored: 1157 line = stored 1158 self.exec_cmd(line, precmd=True) 1159 stored = self.get_stored_line() 1160 1161 # If a child was open close it 1162 if self.child: 1163 self.child.exec_cmd('quit') 1164 self.inputfile = oldinputfile 1165 self.use_rawinput = oldraw 1166 1167 # restore original store line 1168 cmd = self 1169 while hasattr(cmd, 'mother') and cmd.mother: 1170 cmd = cmd.mother 1171 cmd.stored_line = previous_store_line 1172 return
1173
1174 - def get_history_header(self):
1175 """Default history header""" 1176 1177 return self.history_header
1178
1179 - def postloop(self):
1180 """ """ 1181 1182 args = self.split_arg(self.lastcmd) 1183 if args and args[0] in ['quit','exit']: 1184 if 'all' in args: 1185 return True 1186 if len(args) >1 and args[1].isdigit(): 1187 if args[1] not in ['0', '1']: 1188 return True 1189 return False
1190 1191 #=============================================================================== 1192 # Ask a question with a maximum amount of time to answer 1193 #=============================================================================== 1194 @staticmethod
1195 - def timed_input(question, default, timeout=None, noerror=True, fct=None, 1196 fct_timeout=None):
1197 """ a question with a maximal time to answer take default otherwise""" 1198 1199 def handle_alarm(signum, frame): 1200 raise TimeOutError
1201 1202 signal.signal(signal.SIGALRM, handle_alarm) 1203 1204 if fct is None: 1205 fct = raw_input 1206 1207 if timeout: 1208 signal.alarm(timeout) 1209 question += '[%ss to answer] ' % (timeout) 1210 try: 1211 result = fct(question) 1212 except TimeOutError: 1213 if noerror: 1214 logger.info('\nuse %s' % default) 1215 if fct_timeout: 1216 fct_timeout(True) 1217 return default 1218 else: 1219 signal.alarm(0) 1220 raise 1221 finally: 1222 signal.alarm(0) 1223 if fct_timeout: 1224 fct_timeout(False) 1225 return result
1226 1227 1228 1229 1230 1231 1232 # Quit
1233 - def do_quit(self, line):
1234 """Not in help: exit the mainloop() """ 1235 1236 if self.child: 1237 self.child.exec_cmd('quit ' + line, printcmd=False) 1238 return 1239 elif self.mother: 1240 self.mother.child = None 1241 if line == 'all': 1242 pass 1243 elif line: 1244 level = int(line) - 1 1245 if level: 1246 self.mother.lastcmd = 'quit %s' % level 1247 logger.info(' ') 1248 return True
1249 1250 # Aliases 1251 do_EOF = do_quit 1252 do_exit = do_quit 1253
1254 - def do_help(self, line):
1255 """Not in help: propose some usefull possible action """ 1256 1257 # if they are an argument use the default help 1258 if line: 1259 return cmd.Cmd.do_help(self, line) 1260 1261 1262 names = self.get_names() 1263 cmds = {} 1264 names.sort() 1265 # There can be duplicates if routines overridden 1266 prevname = '' 1267 for name in names: 1268 if name[:3] == 'do_': 1269 if name == prevname: 1270 continue 1271 prevname = name 1272 cmdname=name[3:] 1273 try: 1274 doc = getattr(self.cmd, name).__doc__ 1275 except Exception: 1276 doc = None 1277 if not doc: 1278 doc = getattr(self, name).__doc__ 1279 if not doc: 1280 tag = "Documented commands" 1281 elif ':' in doc: 1282 tag = doc.split(':',1)[0] 1283 else: 1284 tag = "Documented commands" 1285 if tag in cmds: 1286 cmds[tag].append(cmdname) 1287 else: 1288 cmds[tag] = [cmdname] 1289 1290 self.stdout.write("%s\n"%str(self.doc_leader)) 1291 for tag in self.helporder: 1292 if tag not in cmds: 1293 continue 1294 header = "%s (type help <topic>):" % tag 1295 self.print_topics(header, cmds[tag], 15,80) 1296 for name, item in cmds.items(): 1297 if name in self.helporder: 1298 continue 1299 if name == "Not in help": 1300 continue 1301 header = "%s (type help <topic>):" % name 1302 self.print_topics(header, item, 15,80) 1303 1304 1305 ## Add contextual help 1306 if len(self.history) == 0: 1307 last_action_2 = last_action = 'start' 1308 else: 1309 last_action_2 = last_action = 'none' 1310 1311 pos = 0 1312 authorize = self.next_possibility.keys() 1313 while last_action_2 not in authorize and last_action not in authorize: 1314 pos += 1 1315 if pos > len(self.history): 1316 last_action_2 = last_action = 'start' 1317 break 1318 1319 args = self.history[-1 * pos].split() 1320 last_action = args[0] 1321 if len(args)>1: 1322 last_action_2 = '%s %s' % (last_action, args[1]) 1323 else: 1324 last_action_2 = 'none' 1325 1326 logger.info('Contextual Help') 1327 logger.info('===============') 1328 if last_action_2 in authorize: 1329 options = self.next_possibility[last_action_2] 1330 elif last_action in authorize: 1331 options = self.next_possibility[last_action] 1332 else: 1333 return 1334 text = 'The following command(s) may be useful in order to continue.\n' 1335 for option in options: 1336 text+='\t %s \n' % option 1337 logger.info(text)
1338
1339 - def do_display(self, line, output=sys.stdout):
1340 """Advanced commands: basic display""" 1341 1342 args = self.split_arg(line) 1343 #check the validity of the arguments 1344 1345 if len(args) == 0: 1346 self.help_display() 1347 raise self.InvalidCmd, 'display require at least one argument' 1348 1349 if args[0] == "options": 1350 outstr = "Value of current Options:\n" 1351 for key, value in self.options.items(): 1352 outstr += '%25s \t:\t%s\n' %(key,value) 1353 output.write(outstr) 1354 1355 elif args[0] == "variable": 1356 outstr = "Value of Internal Variable:\n" 1357 try: 1358 var = eval(args[1]) 1359 except Exception: 1360 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1] 1361 else: 1362 outstr += 'GLOBAL:\n' 1363 outstr += misc.nice_representation(var, nb_space=4) 1364 1365 try: 1366 var = eval('self.%s' % args[1]) 1367 except Exception: 1368 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1] 1369 else: 1370 outstr += 'LOCAL:\n' 1371 outstr += misc.nice_representation(var, nb_space=4) 1372 split = args[1].split('.') 1373 for i, name in enumerate(split): 1374 try: 1375 __import__('.'.join(split[:i+1])) 1376 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1]))) 1377 except ImportError: 1378 try: 1379 var = eval(args[1]) 1380 except Exception, error: 1381 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1] 1382 break 1383 else: 1384 outstr += 'EXTERNAL:\n' 1385 outstr += misc.nice_representation(var, nb_space=4) 1386 else: 1387 var = eval(args[1]) 1388 outstr += 'EXTERNAL:\n' 1389 outstr += misc.nice_representation(var, nb_space=4) 1390 1391 pydoc.pager(outstr)
1392 1393
1394 - def do_save(self, line, check=True):
1395 """Save the configuration file""" 1396 1397 args = self.split_arg(line) 1398 # Check argument validity 1399 if check: 1400 Cmd.check_save(self, args) 1401 1402 # find base file for the configuration 1403 if'HOME' in os.environ and os.environ['HOME'] and \ 1404 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')): 1405 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt') 1406 if hasattr(self, 'me_dir'): 1407 basedir = self.me_dir 1408 elif not MADEVENT: 1409 basedir = MG5DIR 1410 else: 1411 basedir = os.getcwd() 1412 elif MADEVENT: 1413 # launch via ./bin/madevent 1414 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']: 1415 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)): 1416 base = pjoin(self.me_dir, 'Cards', config_file) 1417 basedir = self.me_dir 1418 else: 1419 if hasattr(self, 'me_dir'): 1420 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt') 1421 if len(args) == 0 and os.path.exists(base): 1422 self.write_configuration(base, base, self.me_dir) 1423 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt') 1424 basedir = MG5DIR 1425 1426 if len(args) == 0: 1427 args.append(base) 1428 self.write_configuration(args[0], base, basedir, self.options)
1429
1430 - def write_configuration(self, filepath, basefile, basedir, to_keep):
1431 """Write the configuration file""" 1432 # We use the default configuration file as a template. 1433 # to ensure that all configuration information are written we 1434 # keep track of all key that we need to write. 1435 1436 logger.info('save configuration file to %s' % filepath) 1437 to_write = to_keep.keys() 1438 text = "" 1439 # Use local configuration => Need to update the path 1440 for line in file(basefile): 1441 if '=' in line: 1442 data, value = line.split('=',1) 1443 else: 1444 text += line 1445 continue 1446 data = data.strip() 1447 if data.startswith('#'): 1448 key = data[1:].strip() 1449 else: 1450 key = data 1451 if '#' in value: 1452 value, comment = value.split('#',1) 1453 else: 1454 comment = '' 1455 if key in to_keep: 1456 value = str(to_keep[key]) 1457 else: 1458 text += line 1459 continue 1460 try: 1461 to_write.remove(key) 1462 except Exception: 1463 pass 1464 if '_path' in key: 1465 # special case need to update path 1466 # check if absolute path 1467 if not os.path.isabs(value): 1468 value = os.path.realpath(os.path.join(basedir, value)) 1469 text += '%s = %s # %s \n' % (key, value, comment) 1470 for key in to_write: 1471 if key in to_keep: 1472 text += '%s = %s \n' % (key, to_keep[key]) 1473 1474 if not MADEVENT: 1475 text += """\n# MG5 MAIN DIRECTORY\n""" 1476 text += "mg5_path = %s\n" % MG5DIR 1477 1478 writer = open(filepath,'w') 1479 writer.write(text) 1480 writer.close()
1481
1482 1483 1484 1485 -class CmdShell(Cmd):
1486 """CMD command with shell activate""" 1487 1488 # Access to shell
1489 - def do_shell(self, line):
1490 "Run a shell command" 1491 1492 if line.strip() is '': 1493 self.help_shell() 1494 else: 1495 logging.info("running shell command: " + line) 1496 subprocess.call(line, shell=True)
1497
1498 - def complete_shell(self, text, line, begidx, endidx):
1499 """ add path for shell """ 1500 1501 # Filename if directory is given 1502 # 1503 if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep: 1504 if not text: 1505 text = '' 1506 output = self.path_completion(text, 1507 base_dir=\ 1508 self.split_arg(line[0:begidx])[-1]) 1509 else: 1510 output = self.path_completion(text) 1511 return output
1512
1513 - def help_shell(self):
1514 """help for the shell""" 1515 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE') 1516 logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
1517
1518 1519 1520 1521 #=============================================================================== 1522 # Question with auto-completion 1523 #=============================================================================== 1524 -class SmartQuestion(BasicCmd):
1525 """ a class for answering a question with the path autocompletion""" 1526
1527 - def preloop(self):
1528 """Initializing before starting the main loop""" 1529 self.prompt = '>' 1530 self.value = None 1531 BasicCmd.preloop(self)
1532 1533
1534 - def __init__(self, question, allow_arg=[], default=None, 1535 mother_interface=None, *arg, **opt):
1536 self.question = question 1537 self.wrong_answer = 0 # forbids infinite loop 1538 self.allow_arg = [str(a) for a in allow_arg] 1539 self.history_header = '' 1540 self.default_value = str(default) 1541 self.mother_interface = mother_interface 1542 cmd.Cmd.__init__(self, *arg, **opt)
1543
1544 - def __call__(self, question, reprint_opt=True, **opts):
1545 1546 self.question = question 1547 for key,value in opts: 1548 setattr(self, key, value) 1549 if reprint_opt: 1550 print question 1551 return self.cmdloop()
1552 1553
1554 - def completenames(self, text, line, *ignored):
1555 prev_timer = signal.alarm(0) # avoid timer if any 1556 if prev_timer: 1557 nb_back = len(line) 1558 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1559 self.stdout.write(line) 1560 self.stdout.flush() 1561 try: 1562 out = {} 1563 out[' Options'] = Cmd.list_completion(text, self.allow_arg) 1564 out[' Recognized command'] = BasicCmd.completenames(self, text) 1565 1566 return self.deal_multiple_categories(out) 1567 except Exception, error: 1568 print error
1569
1570 - def get_names(self):
1571 # This method used to pull in base class attributes 1572 # at a time dir() didn't do it yet. 1573 return dir(self)
1574
1575 - def onecmd(self, line, **opt):
1576 """catch all error and stop properly command accordingly 1577 Interpret the argument as though it had been typed in response 1578 to the prompt. 1579 1580 The return value is a flag indicating whether interpretation of 1581 commands by the interpreter should stop. 1582 1583 This allow to pass extra argument for internal call. 1584 """ 1585 try: 1586 if '~/' in line and os.environ.has_key('HOME'): 1587 line = line.replace('~/', '%s/' % os.environ['HOME']) 1588 line = os.path.expandvars(line) 1589 cmd, arg, line = self.parseline(line) 1590 if not line: 1591 return self.emptyline() 1592 if cmd is None: 1593 return self.default(line) 1594 self.lastcmd = line 1595 if cmd == '': 1596 return self.default(line) 1597 else: 1598 try: 1599 func = getattr(self, 'do_' + cmd) 1600 except AttributeError: 1601 return self.default(line) 1602 return func(arg, **opt) 1603 except Exception as error: 1604 logger.warning(error)
1605
1606 - def reask(self, reprint_opt=True):
1607 pat = re.compile('\[(\d*)s to answer\]') 1608 prev_timer = signal.alarm(0) # avoid timer if any 1609 1610 if prev_timer: 1611 if pat.search(self.question): 1612 timeout = int(pat.search(self.question).groups()[0]) 1613 else: 1614 timeout=20 1615 print 1616 signal.alarm(timeout) 1617 if reprint_opt: 1618 if not prev_timer: 1619 self.question = pat.sub('',self.question) 1620 print self.question 1621 return False
1622
1623 - def default(self, line):
1624 """Default action if line is not recognized""" 1625 1626 if line.strip() == '' and self.default_value is not None: 1627 self.value = self.default_value 1628 else: 1629 self.value = line
1630
1631 - def emptyline(self):
1632 """If empty line, return default""" 1633 1634 if self.default_value is not None: 1635 self.value = self.default_value
1636 1637
1638 - def postcmd(self, stop, line):
1639 1640 try: 1641 if self.value in self.allow_arg: 1642 return True 1643 elif str(self.value) == 'EOF': 1644 self.value = self.default_value 1645 return True 1646 elif line and hasattr(self, 'do_%s' % line.split()[0]): 1647 return self.reask() 1648 elif self.value == 'repeat': 1649 return self.reask() 1650 elif len(self.allow_arg)==0: 1651 return True 1652 else: 1653 raise Exception 1654 except Exception,error: 1655 if self.wrong_answer < 100: 1656 self.wrong_answer += 1 1657 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \ 1658 % (self.value,','.join(self.allow_arg))) 1659 logger.warning('please retry') 1660 return False 1661 else: 1662 self.value = self.default_value 1663 return True
1664
1665 - def cmdloop(self, intro=None):
1666 cmd.Cmd.cmdloop(self, intro) 1667 return self.value
1668
1669 # a function helper 1670 -def smart_input(input_text, allow_arg=[], default=None):
1671 print input_text 1672 obj = SmartQuestion(allow_arg=allow_arg, default=default) 1673 return obj.cmdloop()
1674
1675 #=============================================================================== 1676 # Question in order to return a path with auto-completion 1677 #=============================================================================== 1678 -class OneLinePathCompletion(SmartQuestion):
1679 """ a class for answering a question with the path autocompletion""" 1680 1681 completion_prefix='' 1682
1683 - def completenames(self, text, line, begidx, endidx):
1684 prev_timer = signal.alarm(0) # avoid timer if any 1685 if prev_timer: 1686 nb_back = len(line) 1687 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1688 self.stdout.write(line) 1689 self.stdout.flush() 1690 1691 try: 1692 out = {} 1693 out[' Options'] = Cmd.list_completion(text, self.allow_arg) 1694 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False) 1695 out[' Recognized command'] = BasicCmd.completenames(self, text) 1696 1697 return self.deal_multiple_categories(out) 1698 except Exception, error: 1699 print error
1700
1701 - def precmd(self, *args):
1702 """ """ 1703 1704 signal.alarm(0) 1705 return SmartQuestion.precmd(self, *args)
1706
1707 - def completedefault(self,text, line, begidx, endidx):
1708 prev_timer = signal.alarm(0) # avoid timer if any 1709 if prev_timer: 1710 nb_back = len(line) 1711 self.stdout.write('\b'*nb_back + '[timer stopped]\n') 1712 self.stdout.write(line) 1713 self.stdout.flush() 1714 try: 1715 args = Cmd.split_arg(line[0:begidx]) 1716 except Exception, error: 1717 print error 1718 1719 # Directory continuation 1720 if args[-1].endswith(os.path.sep): 1721 1722 return Cmd.path_completion(text, 1723 os.path.join('.',*[a for a in args \ 1724 if a.endswith(os.path.sep)])) 1725 self.completenames(line+text)
1726 1727
1728 - def postcmd(self, stop, line):
1729 try: 1730 if self.value in self.allow_arg: 1731 return True 1732 elif self.value and os.path.isfile(self.value): 1733 return os.path.relpath(self.value) 1734 elif self.value and str(self.value) == 'EOF': 1735 self.value = self.default_value 1736 return True 1737 elif line and hasattr(self, 'do_%s' % line.split()[0]): 1738 # go to retry 1739 reprint_opt = True 1740 elif self.value == 'repeat': 1741 reprint_opt = True 1742 else: 1743 raise Exception 1744 except Exception, error: 1745 print """not valid argument. Valid argument are file path or value in (%s).""" \ 1746 % ','.join(self.allow_arg) 1747 print 'please retry' 1748 reprint_opt = False 1749 1750 return self.reask(reprint_opt)
1751
1752 1753 # a function helper 1754 -def raw_path_input(input_text, allow_arg=[], default=None):
1755 print input_text 1756 obj = OneLinePathCompletion(allow_arg=allow_arg, default=default ) 1757 return obj.cmdloop()
1758
1759 #=============================================================================== 1760 # 1761 #=============================================================================== 1762 -class CmdFile(file):
1763 """ a class for command input file -in order to debug cmd \n problem""" 1764
1765 - def __init__(self, name, opt='rU'):
1766 1767 file.__init__(self, name, opt) 1768 self.text = file.read(self) 1769 self.close() 1770 self.lines = self.text.split('\n')
1771
1772 - def readline(self, *arg, **opt):
1773 """readline method treating correctly a line whithout \n at the end 1774 (add it) 1775 """ 1776 if self.lines: 1777 line = self.lines.pop(0) 1778 else: 1779 return '' 1780 1781 if line.endswith('\n'): 1782 return line 1783 else: 1784 return line + '\n'
1785
1786 - def __next__(self):
1787 return self.lines.__next__()
1788
1789 - def __iter__(self):
1790 return self.lines.__iter__()
1791