1
2
3
4
5
6
7
8
9
10
11
12
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')
36 logger_stderr = logging.getLogger('fatalerror')
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
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
77 """Simple extension for the readline"""
78
82
84 """convert the multiple category in a formatted list understand by our
85 specific readline parser"""
86
87 if 'libedit' in readline.__doc__:
88
89 out = []
90 for name, opt in dico.items():
91 out += opt
92 return out
93
94
95 if 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
101 out = []
102 valid=0
103
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
111 d = {}
112 for x in opt:
113 d[x] = 1
114 opt = list(d.keys())
115 opt.sort()
116 out += opt
117
118
119 if valid == 1:
120 out = out[1:]
121 return out
122
123 @debug()
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
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
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
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:
221 compfunc = self.completedefault
222 else:
223 compfunc = self.completenames
224
225
226 if line and begidx > 2 and line[begidx-2:begidx] == '\ ':
227 Ntext = line.split(os.path.sep)[-1]
228 self.completion_prefix = Ntext.rsplit('\ ', 1)[0] + '\ '
229 to_rm = len(self.completion_prefix) - 1
230 Nbegidx = len(line.rsplit(os.path.sep, 1)[0]) + 1
231 data = compfunc(Ntext.replace('\ ', ' '), line, Nbegidx, endidx)
232 self.completion_matches = [p[to_rm:] for p in data
233 if len(p)>to_rm]
234
235 elif line and line[begidx-1] == '-':
236 try:
237 Ntext = line.split()[-1]
238 self.completion_prefix = Ntext.rsplit('-',1)[0] +'-'
239 to_rm = len(self.completion_prefix)
240 Nbegidx = len(line.rsplit(None, 1)[0])
241 data = compfunc(Ntext, line, Nbegidx, endidx)
242 self.completion_matches = [p[to_rm:] for p in data
243 if len(p)>to_rm]
244 except Exception, error:
245 print error
246 else:
247 self.completion_prefix = ''
248 self.completion_matches = compfunc(text, line, begidx, endidx)
249
250 self.completion_matches = [ l if l[-1] in [' ','@','=',os.path.sep]
251 else ((l + ' ') if not l.endswith('\\$') else l[:-2])
252 for l in self.completion_matches if l]
253
254 try:
255 return self.completion_matches[state]
256 except IndexError, error:
257
258
259
260 return None
261
262 @staticmethod
264 """Split a line of arguments"""
265
266 split = line.split()
267 out=[]
268 tmp=''
269 for data in split:
270 if data[-1] == '\\':
271 tmp += data[:-1]+' '
272 elif tmp:
273 tmp += data
274 tmp = os.path.expanduser(os.path.expandvars(tmp))
275 out.append(tmp)
276 else:
277 out.append(data)
278 return out
279
280 @staticmethod
282 """Propose completions of text in list"""
283
284 if not text:
285 completions = list
286 else:
287 completions = [ f
288 for f in list
289 if f.startswith(text)
290 ]
291
292 return completions
293
294
295 @staticmethod
296 - def path_completion(text, base_dir = None, only_dirs = False,
297 relative=True):
298 """Propose completions of text to compose a valid path"""
299
300 if base_dir is None:
301 base_dir = os.getcwd()
302 base_dir = os.path.expanduser(os.path.expandvars(base_dir))
303
304 if text == '~':
305 text = '~/'
306 prefix, text = os.path.split(text)
307 prefix = os.path.expanduser(os.path.expandvars(prefix))
308 base_dir = os.path.join(base_dir, prefix)
309 if prefix:
310 prefix += os.path.sep
311
312 if only_dirs:
313 completion = [prefix + f
314 for f in os.listdir(base_dir)
315 if f.startswith(text) and \
316 os.path.isdir(os.path.join(base_dir, f)) and \
317 (not f.startswith('.') or text.startswith('.'))
318 ]
319 else:
320 completion = [ prefix + f
321 for f in os.listdir(base_dir)
322 if f.startswith(text) and \
323 os.path.isfile(os.path.join(base_dir, f)) and \
324 (not f.startswith('.') or text.startswith('.'))
325 ]
326
327 completion = completion + \
328 [prefix + f + os.path.sep
329 for f in os.listdir(base_dir)
330 if f.startswith(text) and \
331 os.path.isdir(os.path.join(base_dir, f)) and \
332 (not f.startswith('.') or text.startswith('.'))
333 ]
334
335 if relative:
336 completion += [prefix + f for f in ['.'+os.path.sep, '..'+os.path.sep] if \
337 f.startswith(text) and not prefix.startswith('.')]
338
339 completion = [a.replace(' ','\ ') for a in completion]
340 return completion
341
346 """Extension of the cmd object for only the check command"""
347
348 - def check_history(self, args):
349 """check the validity of line"""
350
351 if len(args) > 1:
352 self.help_history()
353 raise self.InvalidCmd('\"history\" command takes at most one argument')
354
355 if not len(args):
356 return
357
358 if args[0] =='.':
359 if not self._export_dir:
360 raise self.InvalidCmd("No default directory is defined for \'.\' option")
361 elif args[0] != 'clean':
362 dirpath = os.path.dirname(args[0])
363 if dirpath and not os.path.exists(dirpath) or \
364 os.path.isdir(args[0]):
365 raise self.InvalidCmd("invalid path %s " % dirpath)
366
368 """check that the line is compatible with save options"""
369
370 if len(args) > 2:
371 self.help_save()
372 raise self.InvalidCmd, 'too many arguments for save command.'
373
374 if len(args) == 2:
375 if args[0] != 'options':
376 self.help_save()
377 raise self.InvalidCmd, '\'%s\' is not recognized as first argument.' % \
378 args[0]
379 else:
380 args.pop(0)
381
383 """Extension of the cmd object for only the help command"""
384
386 logger.info("-- terminates the application",'$MG:color:BLUE')
387 logger.info("syntax: quit",'$MG:color:BLACK')
388
389 help_EOF = help_quit
390
391 - def help_history(self):
392 logger.info("-- interact with the command history.",'$MG:color:BLUE')
393 logger.info("syntax: history [FILEPATH|clean|.] ",'$MG:color:BLACK')
394 logger.info(" > If FILEPATH is \'.\' and \'output\' is done,")
395 logger.info(" Cards/proc_card_mg5.dat will be used.")
396 logger.info(" > If FILEPATH is omitted, the history will be output to stdout.")
397 logger.info(" \"clean\" will remove all entries from the history.")
398
400 logger.info("-- access to the in-line help",'$MG:color:BLUE')
401 logger.info("syntax: help",'$MG:color:BLACK')
402
404 """help text for save"""
405 logger.info("-- save options configuration to filepath.",'$MG:color:BLUE')
406 logger.info("syntax: save [options] [FILEPATH]",'$MG:color:BLACK')
407
409 """help for display command"""
410 logger.info("-- display a the status of various internal state variables",'$MG:color:BLUE')
411 logger.info("syntax: display " + "|".join(self._display_opts),'$MG:color:BLACK')
412
421
422 - def complete_history(self, text, line, begidx, endidx):
423 "Complete the history command"
424
425 args = self.split_arg(line[0:begidx])
426
427
428 if args[-1].endswith(os.path.sep):
429 return self.path_completion(text,
430 os.path.join('.',*[a for a in args \
431 if a.endswith(os.path.sep)]))
432
433 if len(args) == 1:
434 return self.path_completion(text)
435
437 "Complete the save command"
438
439 args = self.split_arg(line[0:begidx])
440
441
442 if len(args) == 1:
443 return self.list_completion(text, ['options'])
444
445
446 if args[-1].endswith(os.path.sep):
447 return self.path_completion(text,
448 pjoin('.',*[a for a in args if a.endswith(os.path.sep)]),
449 only_dirs = True)
450
451
452 if len(args) == 2:
453 return self.path_completion(text)
454
455 -class Cmd(CheckCmd, HelpCmd, CompleteCmd, BasicCmd):
456 """Extension of the cmd.Cmd command line.
457 This extensions supports line breaking, history, comments,
458 internal call to cmdline, path completion,...
459 this class should be MG5 independent"""
460
461
462 next_possibility = {}
463 history_header = ""
464
465 _display_opts = ['options','variable']
466
468 """expected error for wrong command"""
469 pass
470
471 ConfigurationError = InvalidCmd
472
473 debug_output = 'debug'
474 error_debug = """Please report this bug to developers\n
475 More information is found in '%(debug)s'.\n
476 Please attach this file to your report."""
477 config_debug = error_debug
478
479 keyboard_stop_msg = """stopping all current operation
480 in order to quit the program please enter exit"""
481
482
484 """Init history and line continuation"""
485
486 self.log = True
487 self.history = []
488 self.save_line = ''
489 cmd.Cmd.__init__(self, *arg, **opt)
490 self.__initpos = os.path.abspath(os.getcwd())
491 self.child = None
492 self.mother = None
493 self.inputfile = None
494 self.haspiping = not sys.stdin.isatty()
495 self.stored_line = ''
496
497 if not hasattr(self, 'helporder'):
498 self.helporder = ['Documented commands']
499
500
502 """ A suite of additional function needed for in the cmd
503 this implement history, line breaking, comment treatment,...
504 """
505
506 if not line:
507 return line
508 line = line.lstrip()
509
510
511 if self.save_line:
512 line = self.save_line + line
513 self.save_line = ''
514
515
516 if line.endswith('\\'):
517 self.save_line = line[:-1]
518 return ''
519
520
521 if '#' in line:
522 line = line.split('#')[0]
523
524
525 if ';' in line:
526 lines = line.split(';')
527 for subline in lines:
528 if not (subline.startswith("history") or subline.startswith('help') \
529 or subline.startswith('#*')):
530 self.history.append(subline)
531 stop = self.onecmd(subline)
532 stop = self.postcmd(stop, subline)
533 return ''
534
535
536 self.history.append(line)
537 return line
538
539 - def postcmd(self,stop, line):
540 """ finishing a command
541 This looks if the command add a special post part."""
542
543 if line.strip():
544 try:
545 cmd, subline = line.split(None, 1)
546 except ValueError:
547 pass
548 else:
549 if hasattr(self,'post_%s' %cmd):
550 stop = getattr(self, 'post_%s' % cmd)(stop, subline)
551 return stop
552
554 """Define a sub cmd_interface"""
555
556
557 self.child = obj_instance
558 self.child.mother = self
559
560 if self.use_rawinput and interface:
561
562 obj_instance.cmdloop()
563 stop = obj_instance.postloop()
564 return stop
565 if self.inputfile:
566
567 obj_instance.inputfile = self.inputfile
568
569 obj_instance.haspiping = self.haspiping
570
571 if not interface:
572 return self.child
573
574
575
576
577 - def ask(self, question, default, choices=[], path_msg=None,
578 timeout = True, fct_timeout=None, ask_class=None, alias={},
579 first_cmd=None, **opt):
580 """ ask a question with some pre-define possibility
581 path info is
582 """
583
584 if path_msg:
585 path_msg = [path_msg]
586 else:
587 path_msg = []
588
589 if timeout:
590 try:
591 timeout = self.options['timeout']
592 except Exception:
593 pass
594
595
596 if choices + path_msg:
597 question += ' ['
598 question += "\033[%dm%s\033[0m, " % (4, default)
599 for data in choices[:9] + path_msg:
600 if default == data:
601 continue
602 else:
603 question += "%s, " % data
604
605 if len(choices) > 9:
606 question += '... , '
607 question = question[:-2]+']'
608 else:
609 question += "[\033[%dm%s\033[0m] " % (4, default)
610 if ask_class:
611 obj = ask_class
612 elif path_msg:
613 obj = OneLinePathCompletion
614 else:
615 obj = SmartQuestion
616
617 if alias:
618 choices += alias.keys()
619
620 question_instance = obj(question, allow_arg=choices, default=default,
621 mother_interface=self, **opt)
622
623 if first_cmd:
624 question_instance.onecmd(first_cmd)
625
626 if not self.haspiping:
627 if hasattr(obj, "haspiping"):
628 obj.haspiping = self.haspiping
629
630
631
632
633 answer = self.check_answer_in_input_file(question_instance, default, path_msg)
634 if answer is not None:
635 if answer in alias:
636 answer = alias[answer]
637 if ask_class:
638 answer = question_instance.default(answer)
639 return answer
640
641 question = question_instance.question
642 value = Cmd.timed_input(question, default, timeout=timeout,
643 fct=question_instance, fct_timeout=fct_timeout)
644
645
646
647 try:
648 if value in alias:
649 value = alias[value]
650 except TypeError:
651 pass
652 if value == default and ask_class:
653 value = question_instance.default(default)
654 return value
655
665
667 """check import command"""
668
669 if '-f' in args:
670 self.force = True
671 args.remove('-f')
672 if args[0] != 'command':
673 args.set(0, 'command')
674 if len(args) != 2:
675 raise self.InvalidCmd('import command requires one filepath argument')
676 if not os.path.exists(args[1]):
677 raise 'No such file or directory %s' % args[1]
678
679
730
732 """store a line of the input file which should be executed by the higher mother"""
733
734 if self.mother:
735 self.mother.store_line(line)
736 else:
737 self.stored_line = line
738
740 """return stored line and clean it"""
741 if self.mother:
742 value = self.mother.get_stored_line()
743 self.mother.stored_line = None
744 else:
745 value = self.stored_line
746 self.stored_line = None
747 return value
748
749
750
752 """ """
753
754 if self.child:
755 return self.child.nice_error_handling(error, line)
756
757 os.chdir(self.__initpos)
758
759 self.log = False
760 if os.path.exists(self.debug_output):
761 os.remove(self.debug_output)
762 try:
763 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output.replace(' ', '\ '))
764 except Exception, error:
765 logger.error(error)
766
767 debug_file = open(self.debug_output, 'a')
768 traceback.print_exc(file=debug_file)
769
770 if self.history and line == self.history[-1]:
771 error_text = 'Command \"%s\" interrupted with error:\n' % line
772 elif self.history:
773 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
774 error_text += '\"%s\" with error:\n' % self.history[-1]
775 else:
776 error_text = ''
777 error_text += '%s : %s\n' % (error.__class__.__name__,
778 str(error).replace('\n','\n\t'))
779 error_text += self.error_debug % {'debug':self.debug_output}
780 logger_stderr.critical(error_text)
781
782
783
784 try:
785 self.do_display('options', debug_file)
786 except Exception, error:
787 debug_file.write('Fail to write options with error %s' % error)
788
789
790 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']:
791 try:
792 ff = open(pjoin(self.me_dir, 'Cards', card))
793 debug_file.write(ff.read())
794 ff.close()
795 except Exception:
796 pass
797
798
799 if self.use_rawinput == False:
800 return True
801 return False
802
803
804
806 if self.child:
807 return self.child.nice_user_error(error, line)
808
809 os.chdir(self.__initpos)
810 if line == self.history[-1]:
811 error_text = 'Command \"%s\" interrupted with error:\n' % line
812 else:
813 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
814 error_text += '\"%s\" with error:\n' % self.history[-1]
815 error_text += '%s : %s' % (error.__class__.__name__,
816 str(error).replace('\n','\n\t'))
817 logger_stderr.error(error_text)
818
819 if self.use_rawinput == False:
820 return True
821
822 self.history.pop()
823 return False
824
826 if self.child:
827 return self.child.nice_user_error(error, line)
828
829 os.chdir(self.__initpos)
830 if not self.history or line == self.history[-1]:
831 error_text = 'Error detected in \"%s\"\n' % line
832 else:
833 error_text = 'Error detected in sub-command %s\n' % self.history[-1]
834 error_text += 'write debug file %s \n' % self.debug_output
835 self.log = False
836 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output)
837 debug_file = open(self.debug_output, 'a')
838 traceback.print_exc(file=debug_file)
839 error_text += self.config_debug % {'debug' :self.debug_output}
840 error_text += '%s : %s' % (error.__class__.__name__,
841 str(error).replace('\n','\n\t'))
842 logger_stderr.error(error_text)
843
844
845 try:
846 self.do_display('options', debug_file)
847 except Exception, error:
848 debug_file.write('Fail to write options with error %s' % error)
849
850 if self.use_rawinput == False:
851 return True
852
853 if self.history:
854 self.history.pop()
855 return False
856
858 """Interpret the argument as though it had been typed in response
859 to the prompt.
860
861 The return value is a flag indicating whether interpretation of
862 commands by the interpreter should stop.
863
864 This allow to pass extra argument for internal call.
865 """
866 if '~/' in line and os.environ.has_key('HOME'):
867 line = line.replace('~/', '%s/' % os.environ['HOME'])
868 line = os.path.expandvars(line)
869 cmd, arg, line = self.parseline(line)
870 if not line:
871 return self.emptyline()
872 if cmd is None:
873 return self.default(line)
874 self.lastcmd = line
875 if cmd == '':
876 return self.default(line)
877 else:
878 try:
879 func = getattr(self, 'do_' + cmd)
880 except AttributeError:
881 return self.default(line)
882 return func(arg, **opt)
883
884
885 - def onecmd(self, line, **opt):
907
909 """action to perform to close nicely on a keyboard interupt"""
910 pass
911
912 - def exec_cmd(self, line, errorhandling=False, printcmd=True,
913 precmd=False, postcmd=True, **opt):
933
935 """for third party call, call the line with pre and postfix treatment
936 with global error handling"""
937
938 return self.exec_cmd(line, errorhandling=True, precmd=True)
939
941 """If empty line, do nothing. Default is repeat previous command."""
942 pass
943
944 - def default(self, line, log=True):
945 """Default action if line is not recognized"""
946
947
948 if log:
949 logger.warning("Command \"%s\" not recognized, please try again" % \
950 line.split()[0])
951 if line.strip() in ['q', '.q', 'stop']:
952 logger.info("If you want to quit mg5 please type \"exit\".")
953
954 if self.history and self.history[-1] == line:
955 self.history.pop()
956
957
958
959
960
961
962 - def do_history(self, line):
963 """write in a file the suite of command that was used"""
964
965 args = self.split_arg(line)
966
967 self.check_history(args)
968
969 if len(args) == 0:
970 logger.info('\n'.join(self.history))
971 return
972 elif args[0] == 'clean':
973 self.history = []
974 logger.info('History is cleaned')
975 return
976 elif args[0] == '.':
977 output_file = os.path.join(self._export_dir, 'Cards', \
978 'proc_card_mg5.dat')
979 output_file = open(output_file, 'w')
980 else:
981 output_file = open(args[0], 'w')
982
983
984 text = self.get_history_header()
985 text += ('\n'.join(self.history) + '\n')
986
987
988 output_file.write(text)
989 output_file.close()
990
991 if self.log:
992 logger.info("History written to " + output_file.name)
993
998
999 - def avoid_history_duplicate(self, line, no_break=[]):
1000 """remove all line in history (but the last) starting with line.
1001 up to the point when a line didn't start by something in no_break.
1002 (reading in reverse order)"""
1003
1004 new_history = []
1005 for i in range(1, len(self.history)+1):
1006 cur_line = self.history[-i]
1007 if i == 1:
1008 new_history.append(cur_line)
1009 elif not any((cur_line.startswith(text) for text in no_break)):
1010 to_add = self.history[:-i+1]
1011 to_add.reverse()
1012 new_history += to_add
1013 break
1014 elif cur_line.startswith(line):
1015 continue
1016 else:
1017 new_history.append(cur_line)
1018
1019 new_history.reverse()
1020 self.history[:] = new_history
1021
1022
1024
1025 if self.history:
1026 self.history.pop()
1027
1028
1029 previous_store_line = self.get_stored_line()
1030
1031
1032 if isinstance(filepath, str):
1033 commandline = open(filepath).readlines()
1034 else:
1035 commandline = filepath
1036 oldinputfile = self.inputfile
1037 oldraw = self.use_rawinput
1038 self.inputfile = (l for l in commandline)
1039 self.use_rawinput = False
1040
1041
1042
1043 for line in self.inputfile:
1044
1045 line = line.replace('\n', '').strip()
1046
1047 if line:
1048 self.exec_cmd(line, precmd=True)
1049 stored = self.get_stored_line()
1050 while stored:
1051 line = stored
1052 self.exec_cmd(line, precmd=True)
1053 stored = self.get_stored_line()
1054
1055
1056 if self.child:
1057 self.child.exec_cmd('quit')
1058 self.inputfile = oldinputfile
1059 self.use_rawinput = oldraw
1060
1061
1062 cmd = self
1063 while hasattr(cmd, 'mother') and cmd.mother:
1064 cmd = cmd.mother
1065 cmd.stored_line = previous_store_line
1066 return
1067
1069 """Default history header"""
1070
1071 return self.history_header
1072
1073 - def postloop(self):
1074 """ """
1075
1076 args = self.split_arg(self.lastcmd)
1077 if args and args[0] in ['quit','exit']:
1078 if 'all' in args:
1079 return True
1080 if len(args) >1 and args[1].isdigit():
1081 if args[1] not in ['0', '1']:
1082 return True
1083 return False
1084
1085
1086
1087
1088 @staticmethod
1095
1096 signal.signal(signal.SIGALRM, handle_alarm)
1097
1098 if fct is None:
1099 fct = raw_input
1100
1101 if timeout:
1102 signal.alarm(timeout)
1103 question += '[%ss to answer] ' % (timeout)
1104 try:
1105 result = fct(question)
1106 except TimeOutError:
1107 if noerror:
1108 logger.info('\nuse %s' % default)
1109 if fct_timeout:
1110 fct_timeout(True)
1111 return default
1112 else:
1113 signal.alarm(0)
1114 raise
1115 finally:
1116 signal.alarm(0)
1117 if fct_timeout:
1118 fct_timeout(False)
1119 return result
1120
1121
1122
1123
1124
1125
1126
1128 """Not in help: exit the mainloop() """
1129
1130 if self.child:
1131 self.child.exec_cmd('quit ' + line, printcmd=False)
1132 return
1133 elif self.mother:
1134 self.mother.child = None
1135 if line == 'all':
1136 pass
1137 elif line:
1138 level = int(line) - 1
1139 if level:
1140 self.mother.lastcmd = 'quit %s' % level
1141 logger.info(' ')
1142 return True
1143
1144
1145 do_EOF = do_quit
1146 do_exit = do_quit
1147
1149 """Not in help: propose some usefull possible action """
1150
1151
1152 if line:
1153 return cmd.Cmd.do_help(self, line)
1154
1155
1156 names = self.get_names()
1157 cmds = {}
1158 names.sort()
1159
1160 prevname = ''
1161 for name in names:
1162 if name[:3] == 'do_':
1163 if name == prevname:
1164 continue
1165 prevname = name
1166 cmdname=name[3:]
1167 try:
1168 doc = getattr(self.cmd, name).__doc__
1169 except Exception:
1170 doc = None
1171 if not doc:
1172 doc = getattr(self, name).__doc__
1173 if not doc:
1174 tag = "Documented commands"
1175 elif ':' in doc:
1176 tag = doc.split(':',1)[0]
1177 else:
1178 tag = "Documented commands"
1179 if tag in cmds:
1180 cmds[tag].append(cmdname)
1181 else:
1182 cmds[tag] = [cmdname]
1183
1184 self.stdout.write("%s\n"%str(self.doc_leader))
1185 for tag in self.helporder:
1186 if tag not in cmds:
1187 continue
1188 header = "%s (type help <topic>):" % tag
1189 self.print_topics(header, cmds[tag], 15,80)
1190 for name, item in cmds.items():
1191 if name in self.helporder:
1192 continue
1193 if name == "Not in help":
1194 continue
1195 header = "%s (type help <topic>):" % name
1196 self.print_topics(header, item, 15,80)
1197
1198
1199
1200 if len(self.history) == 0:
1201 last_action_2 = last_action = 'start'
1202 else:
1203 last_action_2 = last_action = 'none'
1204
1205 pos = 0
1206 authorize = self.next_possibility.keys()
1207 while last_action_2 not in authorize and last_action not in authorize:
1208 pos += 1
1209 if pos > len(self.history):
1210 last_action_2 = last_action = 'start'
1211 break
1212
1213 args = self.history[-1 * pos].split()
1214 last_action = args[0]
1215 if len(args)>1:
1216 last_action_2 = '%s %s' % (last_action, args[1])
1217 else:
1218 last_action_2 = 'none'
1219
1220 logger.info('Contextual Help')
1221 logger.info('===============')
1222 if last_action_2 in authorize:
1223 options = self.next_possibility[last_action_2]
1224 elif last_action in authorize:
1225 options = self.next_possibility[last_action]
1226 else:
1227 return
1228 text = 'The following command(s) may be useful in order to continue.\n'
1229 for option in options:
1230 text+='\t %s \n' % option
1231 logger.info(text)
1232
1234 """Advanced commands: basic display"""
1235
1236 args = self.split_arg(line)
1237
1238
1239 if len(args) == 0:
1240 self.help_display()
1241 raise self.InvalidCmd, 'display require at least one argument'
1242
1243 if args[0] == "options":
1244 outstr = "Value of current Options:\n"
1245 for key, value in self.options.items():
1246 outstr += '%25s \t:\t%s\n' %(key,value)
1247 output.write(outstr)
1248
1249 elif args[0] == "variable":
1250 outstr = "Value of Internal Variable:\n"
1251 try:
1252 var = eval(args[1])
1253 except Exception:
1254 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
1255 else:
1256 outstr += 'GLOBAL:\n'
1257 outstr += misc.nice_representation(var, nb_space=4)
1258
1259 try:
1260 var = eval('self.%s' % args[1])
1261 except Exception:
1262 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
1263 else:
1264 outstr += 'LOCAL:\n'
1265 outstr += misc.nice_representation(var, nb_space=4)
1266 split = args[1].split('.')
1267 for i, name in enumerate(split):
1268 try:
1269 __import__('.'.join(split[:i+1]))
1270 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1])))
1271 except ImportError:
1272 try:
1273 var = eval(args[1])
1274 except Exception, error:
1275 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1]
1276 break
1277 else:
1278 outstr += 'EXTERNAL:\n'
1279 outstr += misc.nice_representation(var, nb_space=4)
1280 else:
1281 var = eval(args[1])
1282 outstr += 'EXTERNAL:\n'
1283 outstr += misc.nice_representation(var, nb_space=4)
1284
1285 pydoc.pager(outstr)
1286
1287
1288 - def do_save(self, line, check=True):
1289 """Save the configuration file"""
1290
1291 args = self.split_arg(line)
1292
1293 if check:
1294 Cmd.check_save(self, args)
1295
1296
1297 if'HOME' in os.environ and os.environ['HOME'] and \
1298 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
1299 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
1300 if hasattr(self, 'me_dir'):
1301 basedir = self.me_dir
1302 elif not MADEVENT:
1303 basedir = MG5DIR
1304 else:
1305 basedir = os.getcwd()
1306 elif MADEVENT:
1307
1308 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']:
1309 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)):
1310 base = pjoin(self.me_dir, 'Cards', config_file)
1311 basedir = self.me_dir
1312 else:
1313 if hasattr(self, 'me_dir'):
1314 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1315 if len(args) == 0 and os.path.exists(base):
1316 self.write_configuration(base, base, self.me_dir)
1317 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1318 basedir = MG5DIR
1319
1320 if len(args) == 0:
1321 args.append(base)
1322 self.write_configuration(args[0], base, basedir, self.options)
1323
1325 """Write the configuration file"""
1326
1327
1328
1329
1330 logger.info('save configuration file to %s' % filepath)
1331 to_write = to_keep.keys()
1332 text = ""
1333
1334 for line in file(basefile):
1335 if '=' in line:
1336 data, value = line.split('=',1)
1337 else:
1338 text += line
1339 continue
1340 data = data.strip()
1341 if data.startswith('#'):
1342 key = data[1:].strip()
1343 else:
1344 key = data
1345 if '#' in value:
1346 value, comment = value.split('#',1)
1347 else:
1348 comment = ''
1349 if key in to_keep:
1350 value = str(to_keep[key])
1351 else:
1352 text += line
1353 continue
1354 try:
1355 to_write.remove(key)
1356 except Exception:
1357 pass
1358 if '_path' in key:
1359
1360
1361 if not os.path.isabs(value):
1362 value = os.path.realpath(os.path.join(basedir, value))
1363 text += '%s = %s # %s \n' % (key, value, comment)
1364 for key in to_write:
1365 if key in to_keep:
1366 text += '%s = %s \n' % (key, to_keep[key])
1367
1368 if not MADEVENT:
1369 text += """\n# MG5 MAIN DIRECTORY\n"""
1370 text += "mg5_path = %s\n" % MG5DIR
1371
1372 writer = open(filepath,'w')
1373 writer.write(text)
1374 writer.close()
1375
1380 """CMD command with shell activate"""
1381
1382
1384 "Run a shell command"
1385
1386 if line.strip() is '':
1387 self.help_shell()
1388 else:
1389 logging.info("running shell command: " + line)
1390 subprocess.call(line, shell=True)
1391
1393 """ add path for shell """
1394
1395
1396
1397 if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep:
1398 if not text:
1399 text = ''
1400 output = self.path_completion(text,
1401 base_dir=\
1402 self.split_arg(line[0:begidx])[-1])
1403 else:
1404 output = self.path_completion(text)
1405 return output
1406
1408 """help for the shell"""
1409 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')
1410 logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
1411
1419 """ a class for answering a question with the path autocompletion"""
1420
1422 """Initializing before starting the main loop"""
1423 self.prompt = '>'
1424 self.value = None
1425 BasicCmd.preloop(self)
1426
1427
1428 - def __init__(self, question, allow_arg=[], default=None,
1429 mother_interface=None, *arg, **opt):
1430 self.question = question
1431 self.wrong_answer = 0
1432 self.allow_arg = [str(a) for a in allow_arg]
1433 self.history_header = ''
1434 self.default_value = str(default)
1435 self.mother_interface = mother_interface
1436 cmd.Cmd.__init__(self, *arg, **opt)
1437
1438 - def __call__(self, question, reprint_opt=True, **opts):
1439
1440 self.question = question
1441 for key,value in opts:
1442 setattr(self, key, value)
1443 if reprint_opt:
1444 print question
1445 return self.cmdloop()
1446
1447
1449 prev_timer = signal.alarm(0)
1450 if prev_timer:
1451 nb_back = len(line)
1452 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1453 self.stdout.write(line)
1454 self.stdout.flush()
1455 try:
1456 out = {}
1457 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
1458 out[' Recognized command'] = BasicCmd.completenames(self, text)
1459
1460 return self.deal_multiple_categories(out)
1461 except Exception, error:
1462 print error
1463
1465
1466
1467 return dir(self)
1468
1469 - def onecmd(self, line, **opt):
1470 """catch all error and stop properly command accordingly
1471 Interpret the argument as though it had been typed in response
1472 to the prompt.
1473
1474 The return value is a flag indicating whether interpretation of
1475 commands by the interpreter should stop.
1476
1477 This allow to pass extra argument for internal call.
1478 """
1479 try:
1480 if '~/' in line and os.environ.has_key('HOME'):
1481 line = line.replace('~/', '%s/' % os.environ['HOME'])
1482 line = os.path.expandvars(line)
1483 cmd, arg, line = self.parseline(line)
1484 if not line:
1485 return self.emptyline()
1486 if cmd is None:
1487 return self.default(line)
1488 self.lastcmd = line
1489 if cmd == '':
1490 return self.default(line)
1491 else:
1492 try:
1493 func = getattr(self, 'do_' + cmd)
1494 except AttributeError:
1495 return self.default(line)
1496 return func(arg, **opt)
1497 except Exception as error:
1498 logger.warning(error)
1499
1500 - def reask(self, reprint_opt=True):
1501 pat = re.compile('\[(\d*)s to answer\]')
1502 prev_timer = signal.alarm(0)
1503
1504 if prev_timer:
1505 if pat.search(self.question):
1506 timeout = int(pat.search(self.question).groups()[0])
1507 else:
1508 timeout=20
1509 print
1510 signal.alarm(timeout)
1511 if reprint_opt:
1512 if not prev_timer:
1513 self.question = pat.sub('',self.question)
1514 print self.question
1515 return False
1516
1518 """Default action if line is not recognized"""
1519
1520 if line.strip() == '' and self.default_value is not None:
1521 self.value = self.default_value
1522 else:
1523 self.value = line
1524
1526 """If empty line, return default"""
1527
1528 if self.default_value is not None:
1529 self.value = self.default_value
1530
1531
1532 - def postcmd(self, stop, line):
1533
1534 try:
1535 if self.value in self.allow_arg:
1536 return True
1537 elif str(self.value) == 'EOF':
1538 self.value = self.default_value
1539 return True
1540 elif line and hasattr(self, 'do_%s' % line.split()[0]):
1541 return self.reask()
1542 elif self.value == 'repeat':
1543 return self.reask()
1544 elif len(self.allow_arg)==0:
1545 return True
1546 else:
1547 raise Exception
1548 except Exception,error:
1549 if self.wrong_answer < 100:
1550 self.wrong_answer += 1
1551 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
1552 % (self.value,','.join(self.allow_arg)))
1553 logger.warning('please retry')
1554 return False
1555 else:
1556 self.value = self.default_value
1557 return True
1558
1560 cmd.Cmd.cmdloop(self, intro)
1561 return self.value
1562
1568
1573 """ a class for answering a question with the path autocompletion"""
1574
1575 completion_prefix=''
1576
1578 prev_timer = signal.alarm(0)
1579 if prev_timer:
1580 nb_back = len(line)
1581 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1582 self.stdout.write(line)
1583 self.stdout.flush()
1584
1585 try:
1586 out = {}
1587 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
1588 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
1589 out[' Recognized command'] = BasicCmd.completenames(self, text)
1590
1591 return self.deal_multiple_categories(out)
1592 except Exception, error:
1593 print error
1594
1600
1602 prev_timer = signal.alarm(0)
1603 if prev_timer:
1604 nb_back = len(line)
1605 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1606 self.stdout.write(line)
1607 self.stdout.flush()
1608 try:
1609 args = Cmd.split_arg(line[0:begidx])
1610 except Exception, error:
1611 print error
1612
1613
1614 if args[-1].endswith(os.path.sep):
1615
1616 return Cmd.path_completion(text,
1617 os.path.join('.',*[a for a in args \
1618 if a.endswith(os.path.sep)]))
1619 self.completenames(line+text)
1620
1621
1622 - def postcmd(self, stop, line):
1623 try:
1624 if self.value in self.allow_arg:
1625 return True
1626 elif self.value and os.path.isfile(self.value):
1627 return os.path.relpath(self.value)
1628 elif self.value and str(self.value) == 'EOF':
1629 self.value = self.default_value
1630 return True
1631 elif line and hasattr(self, 'do_%s' % line.split()[0]):
1632
1633 reprint_opt = True
1634 elif self.value == 'repeat':
1635 reprint_opt = True
1636 else:
1637 raise Exception
1638 except Exception, error:
1639 print """not valid argument. Valid argument are file path or value in (%s).""" \
1640 % ','.join(self.allow_arg)
1641 print 'please retry'
1642 reprint_opt = False
1643
1644 return self.reask(reprint_opt)
1645
1652
1653
1654
1655
1656 -class CmdFile(file):
1657 """ a class for command input file -in order to debug cmd \n problem"""
1658
1665
1667 """readline method treating correctly a line whithout \n at the end
1668 (add it)
1669 """
1670 if self.lines:
1671 line = self.lines.pop(0)
1672 else:
1673 return ''
1674
1675 if line.endswith('\n'):
1676 return line
1677 else:
1678 return line + '\n'
1679
1682
1685