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 if isinstance(filepath, str):
1020 commandline = open(filepath).readlines()
1021 else:
1022 commandline = filepath
1023 oldinputfile = self.inputfile
1024 oldraw = self.use_rawinput
1025 self.inputfile = (l for l in commandline)
1026 self.use_rawinput = False
1027
1028
1029
1030 for line in self.inputfile:
1031
1032 line = line.replace('\n', '').strip()
1033
1034 if line:
1035 self.exec_cmd(line, precmd=True)
1036 stored = self.get_stored_line()
1037 while stored:
1038 line = stored
1039 self.exec_cmd(line, precmd=True)
1040 stored = self.get_stored_line()
1041
1042
1043 if self.child:
1044 self.child.exec_cmd('quit')
1045 self.inputfile = oldinputfile
1046 self.use_rawinput = oldraw
1047 return
1048
1050 """Default history header"""
1051
1052 return self.history_header
1053
1054 - def postloop(self):
1055 """ """
1056
1057 args = self.split_arg(self.lastcmd)
1058 if args and args[0] in ['quit','exit']:
1059 if 'all' in args:
1060 return True
1061 if len(args) >1 and args[1].isdigit():
1062 if args[1] not in ['0', '1']:
1063 return True
1064 return False
1065
1066
1067
1068
1069 @staticmethod
1076
1077 signal.signal(signal.SIGALRM, handle_alarm)
1078
1079 if fct is None:
1080 fct = raw_input
1081
1082 if timeout:
1083 signal.alarm(timeout)
1084 question += '[%ss to answer] ' % (timeout)
1085 try:
1086 result = fct(question)
1087 except TimeOutError:
1088 if noerror:
1089 logger.info('\nuse %s' % default)
1090 if fct_timeout:
1091 fct_timeout(True)
1092 return default
1093 else:
1094 signal.alarm(0)
1095 raise
1096 finally:
1097 signal.alarm(0)
1098 if fct_timeout:
1099 fct_timeout(False)
1100 return result
1101
1102
1103
1104
1105
1106
1107
1109 """Not in help: exit the mainloop() """
1110
1111 if self.child:
1112 self.child.exec_cmd('quit ' + line, printcmd=False)
1113 return
1114 elif self.mother:
1115 self.mother.child = None
1116 if line == 'all':
1117 pass
1118 elif line:
1119 level = int(line) - 1
1120 if level:
1121 self.mother.lastcmd = 'quit %s' % level
1122 logger.info(' ')
1123 return True
1124
1125
1126 do_EOF = do_quit
1127 do_exit = do_quit
1128
1130 """Not in help: propose some usefull possible action """
1131
1132
1133 if line:
1134 return cmd.Cmd.do_help(self, line)
1135
1136
1137 names = self.get_names()
1138 cmds = {}
1139 names.sort()
1140
1141 prevname = ''
1142 for name in names:
1143 if name[:3] == 'do_':
1144 if name == prevname:
1145 continue
1146 prevname = name
1147 cmdname=name[3:]
1148 try:
1149 doc = getattr(self.cmd, name).__doc__
1150 except Exception:
1151 doc = None
1152 if not doc:
1153 doc = getattr(self, name).__doc__
1154 if not doc:
1155 tag = "Documented commands"
1156 elif ':' in doc:
1157 tag = doc.split(':',1)[0]
1158 else:
1159 tag = "Documented commands"
1160 if tag in cmds:
1161 cmds[tag].append(cmdname)
1162 else:
1163 cmds[tag] = [cmdname]
1164
1165 self.stdout.write("%s\n"%str(self.doc_leader))
1166 for tag in self.helporder:
1167 if tag not in cmds:
1168 continue
1169 header = "%s (type help <topic>):" % tag
1170 self.print_topics(header, cmds[tag], 15,80)
1171 for name, item in cmds.items():
1172 if name in self.helporder:
1173 continue
1174 if name == "Not in help":
1175 continue
1176 header = "%s (type help <topic>):" % name
1177 self.print_topics(header, item, 15,80)
1178
1179
1180
1181 if len(self.history) == 0:
1182 last_action_2 = last_action = 'start'
1183 else:
1184 last_action_2 = last_action = 'none'
1185
1186 pos = 0
1187 authorize = self.next_possibility.keys()
1188 while last_action_2 not in authorize and last_action not in authorize:
1189 pos += 1
1190 if pos > len(self.history):
1191 last_action_2 = last_action = 'start'
1192 break
1193
1194 args = self.history[-1 * pos].split()
1195 last_action = args[0]
1196 if len(args)>1:
1197 last_action_2 = '%s %s' % (last_action, args[1])
1198 else:
1199 last_action_2 = 'none'
1200
1201 logger.info('Contextual Help')
1202 logger.info('===============')
1203 if last_action_2 in authorize:
1204 options = self.next_possibility[last_action_2]
1205 elif last_action in authorize:
1206 options = self.next_possibility[last_action]
1207 else:
1208 return
1209 text = 'The following command(s) may be useful in order to continue.\n'
1210 for option in options:
1211 text+='\t %s \n' % option
1212 logger.info(text)
1213
1215 """Advanced commands: basic display"""
1216
1217 args = self.split_arg(line)
1218
1219
1220 if len(args) == 0:
1221 self.help_display()
1222 raise self.InvalidCmd, 'display require at least one argument'
1223
1224 if args[0] == "options":
1225 outstr = "Value of current Options:\n"
1226 for key, value in self.options.items():
1227 outstr += '%25s \t:\t%s\n' %(key,value)
1228 output.write(outstr)
1229
1230 elif args[0] == "variable":
1231 outstr = "Value of Internal Variable:\n"
1232 try:
1233 var = eval(args[1])
1234 except Exception:
1235 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
1236 else:
1237 outstr += 'GLOBAL:\n'
1238 outstr += misc.nice_representation(var, nb_space=4)
1239
1240 try:
1241 var = eval('self.%s' % args[1])
1242 except Exception:
1243 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
1244 else:
1245 outstr += 'LOCAL:\n'
1246 outstr += misc.nice_representation(var, nb_space=4)
1247 split = args[1].split('.')
1248 for i, name in enumerate(split):
1249 try:
1250 __import__('.'.join(split[:i+1]))
1251 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1])))
1252 except ImportError:
1253 try:
1254 var = eval(args[1])
1255 except Exception, error:
1256 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1]
1257 break
1258 else:
1259 outstr += 'EXTERNAL:\n'
1260 outstr += misc.nice_representation(var, nb_space=4)
1261 else:
1262 var = eval(args[1])
1263 outstr += 'EXTERNAL:\n'
1264 outstr += misc.nice_representation(var, nb_space=4)
1265
1266 pydoc.pager(outstr)
1267
1268
1269 - def do_save(self, line, check=True):
1270 """Save the configuration file"""
1271
1272 args = self.split_arg(line)
1273
1274 if check:
1275 Cmd.check_save(self, args)
1276
1277
1278 if'HOME' in os.environ and os.environ['HOME'] and \
1279 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
1280 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
1281 if hasattr(self, 'me_dir'):
1282 basedir = self.me_dir
1283 elif not MADEVENT:
1284 basedir = MG5DIR
1285 else:
1286 basedir = os.getcwd()
1287 elif MADEVENT:
1288
1289 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']:
1290 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)):
1291 base = pjoin(self.me_dir, 'Cards', config_file)
1292 basedir = self.me_dir
1293 else:
1294 if hasattr(self, 'me_dir'):
1295 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1296 if len(args) == 0 and os.path.exists(base):
1297 self.write_configuration(base, base, self.me_dir)
1298 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1299 basedir = MG5DIR
1300
1301 if len(args) == 0:
1302 args.append(base)
1303 self.write_configuration(args[0], base, basedir, self.options)
1304
1306 """Write the configuration file"""
1307
1308
1309
1310
1311 logger.info('save configuration file to %s' % filepath)
1312 to_write = to_keep.keys()
1313 text = ""
1314
1315 for line in file(basefile):
1316 if '=' in line:
1317 data, value = line.split('=',1)
1318 else:
1319 text += line
1320 continue
1321 data = data.strip()
1322 if data.startswith('#'):
1323 key = data[1:].strip()
1324 else:
1325 key = data
1326 if '#' in value:
1327 value, comment = value.split('#',1)
1328 else:
1329 comment = ''
1330 if key in to_keep:
1331 value = str(to_keep[key])
1332 else:
1333 text += line
1334 continue
1335 try:
1336 to_write.remove(key)
1337 except Exception:
1338 pass
1339 if '_path' in key:
1340
1341
1342 if not os.path.isabs(value):
1343 value = os.path.realpath(os.path.join(basedir, value))
1344 text += '%s = %s # %s \n' % (key, value, comment)
1345 for key in to_write:
1346 if key in to_keep:
1347 text += '%s = %s \n' % (key, to_keep[key])
1348
1349 if not MADEVENT:
1350 text += """\n# MG5 MAIN DIRECTORY\n"""
1351 text += "mg5_path = %s\n" % MG5DIR
1352
1353 writer = open(filepath,'w')
1354 writer.write(text)
1355 writer.close()
1356
1361 """CMD command with shell activate"""
1362
1363
1365 "Run a shell command"
1366
1367 if line.strip() is '':
1368 self.help_shell()
1369 else:
1370 logging.info("running shell command: " + line)
1371 subprocess.call(line, shell=True)
1372
1374 """ add path for shell """
1375
1376
1377
1378 if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep:
1379 if not text:
1380 text = ''
1381 output = self.path_completion(text,
1382 base_dir=\
1383 self.split_arg(line[0:begidx])[-1])
1384 else:
1385 output = self.path_completion(text)
1386 return output
1387
1389 """help for the shell"""
1390 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')
1391 logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
1392
1400 """ a class for answering a question with the path autocompletion"""
1401
1403 """Initializing before starting the main loop"""
1404 self.prompt = '>'
1405 self.value = None
1406 BasicCmd.preloop(self)
1407
1408
1409 - def __init__(self, question, allow_arg=[], default=None,
1410 mother_interface=None, *arg, **opt):
1411 self.question = question
1412 self.wrong_answer = 0
1413 self.allow_arg = [str(a) for a in allow_arg]
1414 self.history_header = ''
1415 self.default_value = str(default)
1416 self.mother_interface = mother_interface
1417 cmd.Cmd.__init__(self, *arg, **opt)
1418
1419 - def __call__(self, question, reprint_opt=True, **opts):
1420
1421 self.question = question
1422 for key,value in opts:
1423 setattr(self, key, value)
1424 if reprint_opt:
1425 print question
1426 return self.cmdloop()
1427
1428
1430 prev_timer = signal.alarm(0)
1431 if prev_timer:
1432 nb_back = len(line)
1433 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1434 self.stdout.write(line)
1435 self.stdout.flush()
1436 try:
1437 out = {}
1438 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
1439 out[' Recognized command'] = BasicCmd.completenames(self, text)
1440
1441 return self.deal_multiple_categories(out)
1442 except Exception, error:
1443 print error
1444
1446
1447
1448 return dir(self)
1449
1450 - def onecmd(self, line, **opt):
1451 """catch all error and stop properly command accordingly
1452 Interpret the argument as though it had been typed in response
1453 to the prompt.
1454
1455 The return value is a flag indicating whether interpretation of
1456 commands by the interpreter should stop.
1457
1458 This allow to pass extra argument for internal call.
1459 """
1460 try:
1461 if '~/' in line and os.environ.has_key('HOME'):
1462 line = line.replace('~/', '%s/' % os.environ['HOME'])
1463 line = os.path.expandvars(line)
1464 cmd, arg, line = self.parseline(line)
1465 if not line:
1466 return self.emptyline()
1467 if cmd is None:
1468 return self.default(line)
1469 self.lastcmd = line
1470 if cmd == '':
1471 return self.default(line)
1472 else:
1473 try:
1474 func = getattr(self, 'do_' + cmd)
1475 except AttributeError:
1476 return self.default(line)
1477 return func(arg, **opt)
1478 except Exception as error:
1479 logger.warning(error)
1480
1481 - def reask(self, reprint_opt=True):
1482 pat = re.compile('\[(\d*)s to answer\]')
1483 prev_timer = signal.alarm(0)
1484
1485 if prev_timer:
1486 if pat.search(self.question):
1487 timeout = int(pat.search(self.question).groups()[0])
1488 else:
1489 timeout=20
1490 print
1491 signal.alarm(timeout)
1492 if reprint_opt:
1493 if not prev_timer:
1494 self.question = pat.sub('',self.question)
1495 print self.question
1496 return False
1497
1499 """Default action if line is not recognized"""
1500
1501 if line.strip() == '' and self.default_value is not None:
1502 self.value = self.default_value
1503 else:
1504 self.value = line
1505
1507 """If empty line, return default"""
1508
1509 if self.default_value is not None:
1510 self.value = self.default_value
1511
1512
1513 - def postcmd(self, stop, line):
1514
1515 try:
1516 if self.value in self.allow_arg:
1517 return True
1518 elif str(self.value) == 'EOF':
1519 self.value = self.default_value
1520 return True
1521 elif line and hasattr(self, 'do_%s' % line.split()[0]):
1522 return self.reask()
1523 elif self.value == 'repeat':
1524 return self.reask()
1525 elif len(self.allow_arg)==0:
1526 return True
1527 else:
1528 raise Exception
1529 except Exception,error:
1530 if self.wrong_answer < 100:
1531 self.wrong_answer += 1
1532 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
1533 % (self.value,','.join(self.allow_arg)))
1534 logger.warning('please retry')
1535 return False
1536 else:
1537 self.value = self.default_value
1538 return True
1539
1541 cmd.Cmd.cmdloop(self, intro)
1542 return self.value
1543
1549
1554 """ a class for answering a question with the path autocompletion"""
1555
1556 completion_prefix=''
1557
1559 prev_timer = signal.alarm(0)
1560 if prev_timer:
1561 nb_back = len(line)
1562 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1563 self.stdout.write(line)
1564 self.stdout.flush()
1565
1566 try:
1567 out = {}
1568 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
1569 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
1570 out[' Recognized command'] = BasicCmd.completenames(self, text)
1571
1572 return self.deal_multiple_categories(out)
1573 except Exception, error:
1574 print error
1575
1581
1583 prev_timer = signal.alarm(0)
1584 if prev_timer:
1585 nb_back = len(line)
1586 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1587 self.stdout.write(line)
1588 self.stdout.flush()
1589 try:
1590 args = Cmd.split_arg(line[0:begidx])
1591 except Exception, error:
1592 print error
1593
1594
1595 if args[-1].endswith(os.path.sep):
1596
1597 return Cmd.path_completion(text,
1598 os.path.join('.',*[a for a in args \
1599 if a.endswith(os.path.sep)]))
1600 self.completenames(line+text)
1601
1602
1603 - def postcmd(self, stop, line):
1604 try:
1605 if self.value in self.allow_arg:
1606 return True
1607 elif self.value and os.path.isfile(self.value):
1608 return os.path.relpath(self.value)
1609 elif self.value and str(self.value) == 'EOF':
1610 self.value = self.default_value
1611 return True
1612 elif line and hasattr(self, 'do_%s' % line.split()[0]):
1613
1614 reprint_opt = True
1615 elif self.value == 'repeat':
1616 reprint_opt = True
1617 else:
1618 raise Exception
1619 except Exception, error:
1620 print """not valid argument. Valid argument are file path or value in (%s).""" \
1621 % ','.join(self.allow_arg)
1622 print 'please retry'
1623 reprint_opt = False
1624
1625 return self.reask(reprint_opt)
1626
1633
1634
1635
1636
1637 -class CmdFile(file):
1638 """ a class for command input file -in order to debug cmd \n problem"""
1639
1646
1648 """readline method treating correctly a line whithout \n at the end
1649 (add it)
1650 """
1651 if self.lines:
1652 line = self.lines.pop(0)
1653 else:
1654 return ''
1655
1656 if line.endswith('\n'):
1657 return line
1658 else:
1659 return line + '\n'
1660
1663
1666