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={},**opt):
579 """ ask a question with some pre-define possibility
580 path info is
581 """
582 if path_msg:
583 path_msg = [path_msg]
584 else:
585 path_msg = []
586
587 if timeout:
588 try:
589 timeout = self.options['timeout']
590 except Exception:
591 pass
592
593
594 if choices + path_msg:
595 question += ' ['
596 question += "\033[%dm%s\033[0m, " % (4, default)
597 for data in choices[:9] + path_msg:
598 if default == data:
599 continue
600 else:
601 question += "%s, " % data
602
603 if len(choices) > 9:
604 question += '... , '
605 question = question[:-2]+']'
606 else:
607 question += "[\033[%dm%s\033[0m] " % (4, default)
608 if ask_class:
609 obj = ask_class
610 elif path_msg:
611 obj = OneLinePathCompletion
612 else:
613 obj = SmartQuestion
614
615 if alias:
616 choices += alias.keys()
617
618 question_instance = obj(question, allow_arg=choices, default=default,
619 mother_interface=self, **opt)
620 if not self.haspiping:
621 if hasattr(obj, "haspiping"):
622 obj.haspiping = self.haspiping
623
624
625 answer = self.check_answer_in_input_file(question_instance, default, path_msg)
626 if answer is not None:
627 if answer in alias:
628 answer = alias[answer]
629 if ask_class:
630 answer = question_instance.default(answer)
631 return answer
632
633 question = question_instance.question
634 value = Cmd.timed_input(question, default, timeout=timeout,
635 fct=question_instance, fct_timeout=fct_timeout)
636
637 try:
638 if value in alias:
639 value = alias[value]
640 except TypeError:
641 pass
642 if value == default and ask_class:
643 value = question_instance.default(default)
644 return value
645
655
657 """check import command"""
658
659 if '-f' in args:
660 self.force = True
661 args.remove('-f')
662 if args[0] != 'command':
663 args.set(0, 'command')
664 if len(args) != 2:
665 raise self.InvalidCmd('import command requires one filepath argument')
666 if not os.path.exists(args[1]):
667 raise 'No such file or directory %s' % args[1]
668
669
720
722 """store a line of the input file which should be executed by the higher mother"""
723
724 if self.mother:
725 self.mother.store_line(line)
726 else:
727 self.stored_line = line
728
730 """return stored line and clean it"""
731 if self.mother:
732 value = self.mother.get_stored_line()
733 self.mother.stored_line = None
734 else:
735 value = self.stored_line
736 self.stored_line = None
737 return value
738
739
740
742 """ """
743
744 if self.child:
745 return self.child.nice_error_handling(error, line)
746
747 os.chdir(self.__initpos)
748
749 self.log = False
750 if os.path.exists(self.debug_output):
751 os.remove(self.debug_output)
752 try:
753 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output.replace(' ', '\ '))
754 except Exception, error:
755 logger.error(error)
756
757 debug_file = open(self.debug_output, 'a')
758 traceback.print_exc(file=debug_file)
759
760 if self.history and line == self.history[-1]:
761 error_text = 'Command \"%s\" interrupted with error:\n' % line
762 elif self.history:
763 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
764 error_text += '\"%s\" with error:\n' % self.history[-1]
765 else:
766 error_text = ''
767 error_text += '%s : %s\n' % (error.__class__.__name__,
768 str(error).replace('\n','\n\t'))
769 error_text += self.error_debug % {'debug':self.debug_output}
770 logger_stderr.critical(error_text)
771
772
773
774 try:
775 self.do_display('options', debug_file)
776 except Exception, error:
777 debug_file.write('Fail to write options with error %s' % error)
778
779
780 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']:
781 try:
782 ff = open(pjoin(self.me_dir, 'Cards', card))
783 debug_file.write(ff.read())
784 ff.close()
785 except Exception:
786 pass
787
788
789 if self.use_rawinput == False:
790 return True
791 return False
792
793
794
796 if self.child:
797 return self.child.nice_user_error(error, line)
798
799 os.chdir(self.__initpos)
800 if line == self.history[-1]:
801 error_text = 'Command \"%s\" interrupted with error:\n' % line
802 else:
803 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
804 error_text += '\"%s\" with error:\n' % self.history[-1]
805 error_text += '%s : %s' % (error.__class__.__name__,
806 str(error).replace('\n','\n\t'))
807 logger_stderr.error(error_text)
808
809 if self.use_rawinput == False:
810 return True
811
812 self.history.pop()
813 return False
814
816 if self.child:
817 return self.child.nice_user_error(error, line)
818
819 os.chdir(self.__initpos)
820 if not self.history or line == self.history[-1]:
821 error_text = 'Error detected in \"%s\"\n' % line
822 else:
823 error_text = 'Error detected in sub-command %s\n' % self.history[-1]
824 error_text += 'write debug file %s \n' % self.debug_output
825 self.log = False
826 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output)
827 debug_file = open(self.debug_output, 'a')
828 traceback.print_exc(file=debug_file)
829 error_text += self.config_debug % {'debug' :self.debug_output}
830 error_text += '%s : %s' % (error.__class__.__name__,
831 str(error).replace('\n','\n\t'))
832 logger_stderr.error(error_text)
833
834
835 try:
836 self.do_display('options', debug_file)
837 except Exception, error:
838 debug_file.write('Fail to write options with error %s' % error)
839
840 if self.use_rawinput == False:
841 return True
842
843 if self.history:
844 self.history.pop()
845 return False
846
848 """Interpret the argument as though it had been typed in response
849 to the prompt.
850
851 The return value is a flag indicating whether interpretation of
852 commands by the interpreter should stop.
853
854 This allow to pass extra argument for internal call.
855 """
856 if '~/' in line and os.environ.has_key('HOME'):
857 line = line.replace('~/', '%s/' % os.environ['HOME'])
858 line = os.path.expandvars(line)
859 cmd, arg, line = self.parseline(line)
860 if not line:
861 return self.emptyline()
862 if cmd is None:
863 return self.default(line)
864 self.lastcmd = line
865 if cmd == '':
866 return self.default(line)
867 else:
868 try:
869 func = getattr(self, 'do_' + cmd)
870 except AttributeError:
871 return self.default(line)
872 return func(arg, **opt)
873
874
875 - def onecmd(self, line, **opt):
897
899 """action to perform to close nicely on a keyboard interupt"""
900 pass
901
902 - def exec_cmd(self, line, errorhandling=False, printcmd=True,
903 precmd=False, postcmd=True, **opt):
923
925 """for third party call, call the line with pre and postfix treatment
926 with global error handling"""
927
928 return self.exec_cmd(line, errorhandling=True, precmd=True)
929
931 """If empty line, do nothing. Default is repeat previous command."""
932 pass
933
934 - def default(self, line, log=True):
935 """Default action if line is not recognized"""
936
937
938 if log:
939 logger.warning("Command \"%s\" not recognized, please try again" % \
940 line.split()[0])
941 if line.strip() in ['q', '.q', 'stop']:
942 logger.info("If you want to quit mg5 please type \"exit\".")
943
944 if self.history and self.history[-1] == line:
945 self.history.pop()
946
947
948
949
950
951
952 - def do_history(self, line):
953 """write in a file the suite of command that was used"""
954
955 args = self.split_arg(line)
956
957 self.check_history(args)
958
959 if len(args) == 0:
960 logger.info('\n'.join(self.history))
961 return
962 elif args[0] == 'clean':
963 self.history = []
964 logger.info('History is cleaned')
965 return
966 elif args[0] == '.':
967 output_file = os.path.join(self._export_dir, 'Cards', \
968 'proc_card_mg5.dat')
969 output_file = open(output_file, 'w')
970 else:
971 output_file = open(args[0], 'w')
972
973
974 text = self.get_history_header()
975 text += ('\n'.join(self.history) + '\n')
976
977
978 output_file.write(text)
979 output_file.close()
980
981 if self.log:
982 logger.info("History written to " + output_file.name)
983
988
989 - def avoid_history_duplicate(self, line, no_break=[]):
990 """remove all line in history (but the last) starting with line.
991 up to the point when a line didn't start by something in no_break.
992 (reading in reverse order)"""
993
994 new_history = []
995 for i in range(1, len(self.history)+1):
996 cur_line = self.history[-i]
997 if i == 1:
998 new_history.append(cur_line)
999 elif not any((cur_line.startswith(text) for text in no_break)):
1000 to_add = self.history[:-i+1]
1001 to_add.reverse()
1002 new_history += to_add
1003 break
1004 elif cur_line.startswith(line):
1005 continue
1006 else:
1007 new_history.append(cur_line)
1008
1009 new_history.reverse()
1010 self.history[:] = new_history
1011
1012
1014
1015 if self.history:
1016 self.history.pop()
1017
1018
1019 previous_store_line = self.get_stored_line()
1020
1021
1022 if isinstance(filepath, str):
1023 commandline = open(filepath).readlines()
1024 else:
1025 commandline = filepath
1026 oldinputfile = self.inputfile
1027 oldraw = self.use_rawinput
1028 self.inputfile = (l for l in commandline)
1029 self.use_rawinput = False
1030
1031
1032
1033 for line in self.inputfile:
1034
1035 line = line.replace('\n', '').strip()
1036
1037 if line:
1038 self.exec_cmd(line, precmd=True)
1039 stored = self.get_stored_line()
1040 while stored:
1041 line = stored
1042 self.exec_cmd(line, precmd=True)
1043 stored = self.get_stored_line()
1044
1045
1046 if self.child:
1047 self.child.exec_cmd('quit')
1048 self.inputfile = oldinputfile
1049 self.use_rawinput = oldraw
1050
1051
1052 cmd = self
1053 while hasattr(cmd, 'mother') and cmd.mother:
1054 cmd = cmd.mother
1055 cmd.stored_line = previous_store_line
1056 return
1057
1059 """Default history header"""
1060
1061 return self.history_header
1062
1063 - def postloop(self):
1064 """ """
1065
1066 args = self.split_arg(self.lastcmd)
1067 if args and args[0] in ['quit','exit']:
1068 if 'all' in args:
1069 return True
1070 if len(args) >1 and args[1].isdigit():
1071 if args[1] not in ['0', '1']:
1072 return True
1073 return False
1074
1075
1076
1077
1078 @staticmethod
1085
1086 signal.signal(signal.SIGALRM, handle_alarm)
1087
1088 if fct is None:
1089 fct = raw_input
1090
1091 if timeout:
1092 signal.alarm(timeout)
1093 question += '[%ss to answer] ' % (timeout)
1094 try:
1095 result = fct(question)
1096 except TimeOutError:
1097 if noerror:
1098 logger.info('\nuse %s' % default)
1099 if fct_timeout:
1100 fct_timeout(True)
1101 return default
1102 else:
1103 signal.alarm(0)
1104 raise
1105 finally:
1106 signal.alarm(0)
1107 if fct_timeout:
1108 fct_timeout(False)
1109 return result
1110
1111
1112
1113
1114
1115
1116
1118 """Not in help: exit the mainloop() """
1119
1120 if self.child:
1121 self.child.exec_cmd('quit ' + line, printcmd=False)
1122 return
1123 elif self.mother:
1124 self.mother.child = None
1125 if line == 'all':
1126 pass
1127 elif line:
1128 level = int(line) - 1
1129 if level:
1130 self.mother.lastcmd = 'quit %s' % level
1131 logger.info(' ')
1132 return True
1133
1134
1135 do_EOF = do_quit
1136 do_exit = do_quit
1137
1139 """Not in help: propose some usefull possible action """
1140
1141
1142 if line:
1143 return cmd.Cmd.do_help(self, line)
1144
1145
1146 names = self.get_names()
1147 cmds = {}
1148 names.sort()
1149
1150 prevname = ''
1151 for name in names:
1152 if name[:3] == 'do_':
1153 if name == prevname:
1154 continue
1155 prevname = name
1156 cmdname=name[3:]
1157 try:
1158 doc = getattr(self.cmd, name).__doc__
1159 except Exception:
1160 doc = None
1161 if not doc:
1162 doc = getattr(self, name).__doc__
1163 if not doc:
1164 tag = "Documented commands"
1165 elif ':' in doc:
1166 tag = doc.split(':',1)[0]
1167 else:
1168 tag = "Documented commands"
1169 if tag in cmds:
1170 cmds[tag].append(cmdname)
1171 else:
1172 cmds[tag] = [cmdname]
1173
1174 self.stdout.write("%s\n"%str(self.doc_leader))
1175 for tag in self.helporder:
1176 if tag not in cmds:
1177 continue
1178 header = "%s (type help <topic>):" % tag
1179 self.print_topics(header, cmds[tag], 15,80)
1180 for name, item in cmds.items():
1181 if name in self.helporder:
1182 continue
1183 if name == "Not in help":
1184 continue
1185 header = "%s (type help <topic>):" % name
1186 self.print_topics(header, item, 15,80)
1187
1188
1189
1190 if len(self.history) == 0:
1191 last_action_2 = last_action = 'start'
1192 else:
1193 last_action_2 = last_action = 'none'
1194
1195 pos = 0
1196 authorize = self.next_possibility.keys()
1197 while last_action_2 not in authorize and last_action not in authorize:
1198 pos += 1
1199 if pos > len(self.history):
1200 last_action_2 = last_action = 'start'
1201 break
1202
1203 args = self.history[-1 * pos].split()
1204 last_action = args[0]
1205 if len(args)>1:
1206 last_action_2 = '%s %s' % (last_action, args[1])
1207 else:
1208 last_action_2 = 'none'
1209
1210 logger.info('Contextual Help')
1211 logger.info('===============')
1212 if last_action_2 in authorize:
1213 options = self.next_possibility[last_action_2]
1214 elif last_action in authorize:
1215 options = self.next_possibility[last_action]
1216 else:
1217 return
1218 text = 'The following command(s) may be useful in order to continue.\n'
1219 for option in options:
1220 text+='\t %s \n' % option
1221 logger.info(text)
1222
1224 """Advanced commands: basic display"""
1225
1226 args = self.split_arg(line)
1227
1228
1229 if len(args) == 0:
1230 self.help_display()
1231 raise self.InvalidCmd, 'display require at least one argument'
1232
1233 if args[0] == "options":
1234 outstr = "Value of current Options:\n"
1235 for key, value in self.options.items():
1236 outstr += '%25s \t:\t%s\n' %(key,value)
1237 output.write(outstr)
1238
1239 elif args[0] == "variable":
1240 outstr = "Value of Internal Variable:\n"
1241 try:
1242 var = eval(args[1])
1243 except Exception:
1244 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
1245 else:
1246 outstr += 'GLOBAL:\n'
1247 outstr += misc.nice_representation(var, nb_space=4)
1248
1249 try:
1250 var = eval('self.%s' % args[1])
1251 except Exception:
1252 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
1253 else:
1254 outstr += 'LOCAL:\n'
1255 outstr += misc.nice_representation(var, nb_space=4)
1256 split = args[1].split('.')
1257 for i, name in enumerate(split):
1258 try:
1259 __import__('.'.join(split[:i+1]))
1260 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1])))
1261 except ImportError:
1262 try:
1263 var = eval(args[1])
1264 except Exception, error:
1265 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1]
1266 break
1267 else:
1268 outstr += 'EXTERNAL:\n'
1269 outstr += misc.nice_representation(var, nb_space=4)
1270 else:
1271 var = eval(args[1])
1272 outstr += 'EXTERNAL:\n'
1273 outstr += misc.nice_representation(var, nb_space=4)
1274
1275 pydoc.pager(outstr)
1276
1277
1278 - def do_save(self, line, check=True):
1279 """Save the configuration file"""
1280
1281 args = self.split_arg(line)
1282
1283 if check:
1284 Cmd.check_save(self, args)
1285
1286
1287 if'HOME' in os.environ and os.environ['HOME'] and \
1288 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
1289 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
1290 if hasattr(self, 'me_dir'):
1291 basedir = self.me_dir
1292 elif not MADEVENT:
1293 basedir = MG5DIR
1294 else:
1295 basedir = os.getcwd()
1296 elif MADEVENT:
1297
1298 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']:
1299 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)):
1300 base = pjoin(self.me_dir, 'Cards', config_file)
1301 basedir = self.me_dir
1302 else:
1303 if hasattr(self, 'me_dir'):
1304 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1305 if len(args) == 0 and os.path.exists(base):
1306 self.write_configuration(base, base, self.me_dir)
1307 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1308 basedir = MG5DIR
1309
1310 if len(args) == 0:
1311 args.append(base)
1312 self.write_configuration(args[0], base, basedir, self.options)
1313
1315 """Write the configuration file"""
1316
1317
1318
1319
1320 logger.info('save configuration file to %s' % filepath)
1321 to_write = to_keep.keys()
1322 text = ""
1323
1324 for line in file(basefile):
1325 if '=' in line:
1326 data, value = line.split('=',1)
1327 else:
1328 text += line
1329 continue
1330 data = data.strip()
1331 if data.startswith('#'):
1332 key = data[1:].strip()
1333 else:
1334 key = data
1335 if '#' in value:
1336 value, comment = value.split('#',1)
1337 else:
1338 comment = ''
1339 if key in to_keep:
1340 value = str(to_keep[key])
1341 else:
1342 text += line
1343 continue
1344 try:
1345 to_write.remove(key)
1346 except Exception:
1347 pass
1348 if '_path' in key:
1349
1350
1351 if not os.path.isabs(value):
1352 value = os.path.realpath(os.path.join(basedir, value))
1353 text += '%s = %s # %s \n' % (key, value, comment)
1354 for key in to_write:
1355 if key in to_keep:
1356 text += '%s = %s \n' % (key, to_keep[key])
1357
1358 if not MADEVENT:
1359 text += """\n# MG5 MAIN DIRECTORY\n"""
1360 text += "mg5_path = %s\n" % MG5DIR
1361
1362 writer = open(filepath,'w')
1363 writer.write(text)
1364 writer.close()
1365
1370 """CMD command with shell activate"""
1371
1372
1374 "Run a shell command"
1375
1376 if line.strip() is '':
1377 self.help_shell()
1378 else:
1379 logging.info("running shell command: " + line)
1380 subprocess.call(line, shell=True)
1381
1383 """ add path for shell """
1384
1385
1386
1387 if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep:
1388 if not text:
1389 text = ''
1390 output = self.path_completion(text,
1391 base_dir=\
1392 self.split_arg(line[0:begidx])[-1])
1393 else:
1394 output = self.path_completion(text)
1395 return output
1396
1398 """help for the shell"""
1399 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')
1400 logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
1401
1409 """ a class for answering a question with the path autocompletion"""
1410
1412 """Initializing before starting the main loop"""
1413 self.prompt = '>'
1414 self.value = None
1415 BasicCmd.preloop(self)
1416
1417
1418 - def __init__(self, question, allow_arg=[], default=None,
1419 mother_interface=None, *arg, **opt):
1420 self.question = question
1421 self.wrong_answer = 0
1422 self.allow_arg = [str(a) for a in allow_arg]
1423 self.history_header = ''
1424 self.default_value = str(default)
1425 self.mother_interface = mother_interface
1426 cmd.Cmd.__init__(self, *arg, **opt)
1427
1428 - def __call__(self, question, reprint_opt=True, **opts):
1429
1430 self.question = question
1431 for key,value in opts:
1432 setattr(self, key, value)
1433 if reprint_opt:
1434 print question
1435 return self.cmdloop()
1436
1437
1439 prev_timer = signal.alarm(0)
1440 if prev_timer:
1441 nb_back = len(line)
1442 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1443 self.stdout.write(line)
1444 self.stdout.flush()
1445 try:
1446 out = {}
1447 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
1448 out[' Recognized command'] = BasicCmd.completenames(self, text)
1449
1450 return self.deal_multiple_categories(out)
1451 except Exception, error:
1452 print error
1453
1455
1456
1457 return dir(self)
1458
1459 - def onecmd(self, line, **opt):
1460 """catch all error and stop properly command accordingly
1461 Interpret the argument as though it had been typed in response
1462 to the prompt.
1463
1464 The return value is a flag indicating whether interpretation of
1465 commands by the interpreter should stop.
1466
1467 This allow to pass extra argument for internal call.
1468 """
1469 try:
1470 if '~/' in line and os.environ.has_key('HOME'):
1471 line = line.replace('~/', '%s/' % os.environ['HOME'])
1472 line = os.path.expandvars(line)
1473 cmd, arg, line = self.parseline(line)
1474 if not line:
1475 return self.emptyline()
1476 if cmd is None:
1477 return self.default(line)
1478 self.lastcmd = line
1479 if cmd == '':
1480 return self.default(line)
1481 else:
1482 try:
1483 func = getattr(self, 'do_' + cmd)
1484 except AttributeError:
1485 return self.default(line)
1486 return func(arg, **opt)
1487 except Exception as error:
1488 logger.warning(error)
1489
1490 - def reask(self, reprint_opt=True):
1491 pat = re.compile('\[(\d*)s to answer\]')
1492 prev_timer = signal.alarm(0)
1493
1494 if prev_timer:
1495 if pat.search(self.question):
1496 timeout = int(pat.search(self.question).groups()[0])
1497 else:
1498 timeout=20
1499 print
1500 signal.alarm(timeout)
1501 if reprint_opt:
1502 if not prev_timer:
1503 self.question = pat.sub('',self.question)
1504 print self.question
1505 return False
1506
1508 """Default action if line is not recognized"""
1509
1510 if line.strip() == '' and self.default_value is not None:
1511 self.value = self.default_value
1512 else:
1513 self.value = line
1514
1516 """If empty line, return default"""
1517
1518 if self.default_value is not None:
1519 self.value = self.default_value
1520
1521
1522 - def postcmd(self, stop, line):
1523
1524 try:
1525 if self.value in self.allow_arg:
1526 return True
1527 elif str(self.value) == 'EOF':
1528 self.value = self.default_value
1529 return True
1530 elif line and hasattr(self, 'do_%s' % line.split()[0]):
1531 return self.reask()
1532 elif self.value == 'repeat':
1533 return self.reask()
1534 elif len(self.allow_arg)==0:
1535 return True
1536 else:
1537 raise Exception
1538 except Exception,error:
1539 if self.wrong_answer < 100:
1540 self.wrong_answer += 1
1541 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
1542 % (self.value,','.join(self.allow_arg)))
1543 logger.warning('please retry')
1544 return False
1545 else:
1546 self.value = self.default_value
1547 return True
1548
1550 cmd.Cmd.cmdloop(self, intro)
1551 return self.value
1552
1558
1563 """ a class for answering a question with the path autocompletion"""
1564
1565 completion_prefix=''
1566
1568 prev_timer = signal.alarm(0)
1569 if prev_timer:
1570 nb_back = len(line)
1571 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1572 self.stdout.write(line)
1573 self.stdout.flush()
1574
1575 try:
1576 out = {}
1577 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
1578 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
1579 out[' Recognized command'] = BasicCmd.completenames(self, text)
1580
1581 return self.deal_multiple_categories(out)
1582 except Exception, error:
1583 print error
1584
1590
1592 prev_timer = signal.alarm(0)
1593 if prev_timer:
1594 nb_back = len(line)
1595 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1596 self.stdout.write(line)
1597 self.stdout.flush()
1598 try:
1599 args = Cmd.split_arg(line[0:begidx])
1600 except Exception, error:
1601 print error
1602
1603
1604 if args[-1].endswith(os.path.sep):
1605
1606 return Cmd.path_completion(text,
1607 os.path.join('.',*[a for a in args \
1608 if a.endswith(os.path.sep)]))
1609 self.completenames(line+text)
1610
1611
1612 - def postcmd(self, stop, line):
1613 try:
1614 if self.value in self.allow_arg:
1615 return True
1616 elif self.value and os.path.isfile(self.value):
1617 return os.path.relpath(self.value)
1618 elif self.value and str(self.value) == 'EOF':
1619 self.value = self.default_value
1620 return True
1621 elif line and hasattr(self, 'do_%s' % line.split()[0]):
1622
1623 reprint_opt = True
1624 elif self.value == 'repeat':
1625 reprint_opt = True
1626 else:
1627 raise Exception
1628 except Exception, error:
1629 print """not valid argument. Valid argument are file path or value in (%s).""" \
1630 % ','.join(self.allow_arg)
1631 print 'please retry'
1632 reprint_opt = False
1633
1634 return self.reask(reprint_opt)
1635
1642
1643
1644
1645
1646 -class CmdFile(file):
1647 """ a class for command input file -in order to debug cmd \n problem"""
1648
1655
1657 """readline method treating correctly a line whithout \n at the end
1658 (add it)
1659 """
1660 if self.lines:
1661 line = self.lines.pop(0)
1662 else:
1663 return ''
1664
1665 if line.endswith('\n'):
1666 return line
1667 else:
1668 return line + '\n'
1669
1672
1675