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 not forceCategory and all(len(s) <= 1 for s in dico.values() ):
96 values = set((s[0] for s in dico.values() if len(s)==1))
97 if len(values) == 1:
98 return values
99
100
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 if not forceCategory and valid == 1:
119 out = out[1:]
120
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 allow_notification_center = True
467
469 """expected error for wrong command"""
470 pass
471
472 ConfigurationError = InvalidCmd
473
474 debug_output = 'debug'
475 error_debug = """Please report this bug to developers\n
476 More information is found in '%(debug)s'.\n
477 Please attach this file to your report."""
478 config_debug = error_debug
479
480 keyboard_stop_msg = """stopping all current operation
481 in order to quit the program please enter exit"""
482
483
485 """Init history and line continuation"""
486
487 self.log = True
488 self.history = []
489 self.save_line = ''
490 cmd.Cmd.__init__(self, *arg, **opt)
491 self.__initpos = os.path.abspath(os.getcwd())
492 self.child = None
493 self.mother = None
494 self.inputfile = None
495 self.haspiping = not sys.stdin.isatty()
496 self.stored_line = ''
497
498 if not hasattr(self, 'helporder'):
499 self.helporder = ['Documented commands']
500
501
503 """avoid to have html opening / notification"""
504 self.allow_notification_center = False
505 try:
506 self.options['automatic_html_opening'] = False
507 self.options['notification_center'] = False
508
509 except:
510 pass
511
512
514 """ A suite of additional function needed for in the cmd
515 this implement history, line breaking, comment treatment,...
516 """
517
518 if not line:
519 return line
520 line = line.lstrip()
521
522
523 if self.save_line:
524 line = self.save_line + line
525 self.save_line = ''
526
527
528 if line.endswith('\\'):
529 self.save_line = line[:-1]
530 return ''
531
532
533 if '#' in line:
534 line = line.split('#')[0]
535
536
537 if ';' in line:
538 lines = line.split(';')
539 for subline in lines:
540 if not (subline.startswith("history") or subline.startswith('help') \
541 or subline.startswith('#*')):
542 self.history.append(subline)
543 stop = self.onecmd(subline)
544 stop = self.postcmd(stop, subline)
545 return ''
546
547
548 self.history.append(line)
549 return line
550
551 - def postcmd(self,stop, line):
552 """ finishing a command
553 This looks if the command add a special post part."""
554
555 if line.strip():
556 try:
557 cmd, subline = line.split(None, 1)
558 except ValueError:
559 pass
560 else:
561 if hasattr(self,'post_%s' %cmd):
562 stop = getattr(self, 'post_%s' % cmd)(stop, subline)
563 return stop
564
566 """Define a sub cmd_interface"""
567
568
569 self.child = obj_instance
570 self.child.mother = self
571
572
573 self.child.allow_notification_center = self.allow_notification_center
574
575 if self.use_rawinput and interface:
576
577 obj_instance.cmdloop()
578 stop = obj_instance.postloop()
579 return stop
580 if self.inputfile:
581
582 obj_instance.inputfile = self.inputfile
583
584 obj_instance.haspiping = self.haspiping
585
586 if not interface:
587 return self.child
588
589
590
591
592 - def ask(self, question, default, choices=[], path_msg=None,
593 timeout = True, fct_timeout=None, ask_class=None, alias={},
594 first_cmd=None, **opt):
595 """ ask a question with some pre-define possibility
596 path info is
597 """
598
599 if path_msg:
600 path_msg = [path_msg]
601 else:
602 path_msg = []
603
604 if timeout:
605 try:
606 timeout = self.options['timeout']
607 except Exception:
608 pass
609
610
611 if choices + path_msg:
612 question += ' ['
613 question += "\033[%dm%s\033[0m, " % (4, default)
614 for data in choices[:9] + path_msg:
615 if default == data:
616 continue
617 else:
618 question += "%s, " % data
619
620 if len(choices) > 9:
621 question += '... , '
622 question = question[:-2]+']'
623 else:
624 question += "[\033[%dm%s\033[0m] " % (4, default)
625 if ask_class:
626 obj = ask_class
627 elif path_msg:
628 obj = OneLinePathCompletion
629 else:
630 obj = SmartQuestion
631
632 if alias:
633 choices += alias.keys()
634
635 question_instance = obj(question, allow_arg=choices, default=default,
636 mother_interface=self, **opt)
637
638 if first_cmd:
639 question_instance.onecmd(first_cmd)
640
641 if not self.haspiping:
642 if hasattr(obj, "haspiping"):
643 obj.haspiping = self.haspiping
644
645
646
647
648 answer = self.check_answer_in_input_file(question_instance, default, path_msg)
649 if answer is not None:
650 if answer in alias:
651 answer = alias[answer]
652 if ask_class:
653 answer = question_instance.default(answer)
654 return answer
655
656 question = question_instance.question
657 value = Cmd.timed_input(question, default, timeout=timeout,
658 fct=question_instance, fct_timeout=fct_timeout)
659
660
661
662 try:
663 if value in alias:
664 value = alias[value]
665 except TypeError:
666 pass
667 if value == default and ask_class:
668 value = question_instance.default(default)
669 return value
670
680
682 """check import command"""
683
684 if '-f' in args:
685 self.force = True
686 args.remove('-f')
687 if args[0] != 'command':
688 args.set(0, 'command')
689 if len(args) != 2:
690 raise self.InvalidCmd('import command requires one filepath argument')
691 if not os.path.exists(args[1]):
692 raise 'No such file or directory %s' % args[1]
693
694
745
747 """store a line of the input file which should be executed by the higher mother"""
748
749 if self.mother:
750 self.mother.store_line(line)
751 else:
752 self.stored_line = line
753
755 """return stored line and clean it"""
756 if self.mother:
757 value = self.mother.get_stored_line()
758 self.mother.stored_line = None
759 else:
760 value = self.stored_line
761 self.stored_line = None
762 return value
763
764
765
767 """ """
768
769 if self.child:
770 return self.child.nice_error_handling(error, line)
771
772 os.chdir(self.__initpos)
773
774 self.log = False
775 if os.path.exists(self.debug_output):
776 os.remove(self.debug_output)
777 try:
778 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output.replace(' ', '\ '))
779 except Exception, error:
780 logger.error(error)
781
782 debug_file = open(self.debug_output, 'a')
783 traceback.print_exc(file=debug_file)
784
785 if self.history and line == self.history[-1]:
786 error_text = 'Command \"%s\" interrupted with error:\n' % line
787 elif self.history:
788 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
789 error_text += '\"%s\" with error:\n' % self.history[-1]
790 else:
791 error_text = ''
792 error_text += '%s : %s\n' % (error.__class__.__name__,
793 str(error).replace('\n','\n\t'))
794 error_text += self.error_debug % {'debug':self.debug_output}
795 logger_stderr.critical(error_text)
796
797
798
799 try:
800 self.do_display('options', debug_file)
801 except Exception, error:
802 debug_file.write('Fail to write options with error %s' % error)
803
804
805 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']:
806 try:
807 ff = open(pjoin(self.me_dir, 'Cards', card))
808 debug_file.write(ff.read())
809 ff.close()
810 except Exception:
811 pass
812
813
814 if self.use_rawinput == False:
815 return True
816 return False
817
818
819
821 if self.child:
822 return self.child.nice_user_error(error, line)
823
824 os.chdir(self.__initpos)
825 if line == self.history[-1]:
826 error_text = 'Command \"%s\" interrupted with error:\n' % line
827 else:
828 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
829 error_text += '\"%s\" with error:\n' % self.history[-1]
830 error_text += '%s : %s' % (error.__class__.__name__,
831 str(error).replace('\n','\n\t'))
832 logger_stderr.error(error_text)
833
834 if self.use_rawinput == False:
835 return True
836
837 self.history.pop()
838 return False
839
841 if self.child:
842 return self.child.nice_user_error(error, line)
843
844 os.chdir(self.__initpos)
845 if not self.history or line == self.history[-1]:
846 error_text = 'Error detected in \"%s\"\n' % line
847 else:
848 error_text = 'Error detected in sub-command %s\n' % self.history[-1]
849 error_text += 'write debug file %s \n' % self.debug_output
850 self.log = False
851 cmd.Cmd.onecmd(self, 'history %s' % self.debug_output)
852 debug_file = open(self.debug_output, 'a')
853 traceback.print_exc(file=debug_file)
854 error_text += self.config_debug % {'debug' :self.debug_output}
855 error_text += '%s : %s' % (error.__class__.__name__,
856 str(error).replace('\n','\n\t'))
857 logger_stderr.error(error_text)
858
859
860 try:
861 self.do_display('options', debug_file)
862 except Exception, error:
863 debug_file.write('Fail to write options with error %s' % error)
864
865 if self.use_rawinput == False:
866 return True
867
868 if self.history:
869 self.history.pop()
870 return False
871
873 """Interpret the argument as though it had been typed in response
874 to the prompt.
875
876 The return value is a flag indicating whether interpretation of
877 commands by the interpreter should stop.
878
879 This allow to pass extra argument for internal call.
880 """
881 if '~/' in line and os.environ.has_key('HOME'):
882 line = line.replace('~/', '%s/' % os.environ['HOME'])
883 line = os.path.expandvars(line)
884 cmd, arg, line = self.parseline(line)
885 if not line:
886 return self.emptyline()
887 if cmd is None:
888 return self.default(line)
889 self.lastcmd = line
890 if cmd == '':
891 return self.default(line)
892 else:
893 try:
894 func = getattr(self, 'do_' + cmd)
895 except AttributeError:
896 return self.default(line)
897 return func(arg, **opt)
898
899
900 - def onecmd(self, line, **opt):
901 """catch all error and stop properly command accordingly"""
902
903 me_dir = ''
904 if hasattr(self, 'me_dir'):
905 me_dir = os.path.basename(me_dir) + ' '
906
907 try:
908 return self.onecmd_orig(line, **opt)
909 except self.InvalidCmd as error:
910 if __debug__:
911 self.nice_error_handling(error, line)
912 self.history.pop()
913 else:
914 self.nice_user_error(error, line)
915 if self.allow_notification_center:
916 misc.apple_notify('Run %sfailed' % me_dir,
917 'Invalid Command: %s' % error.__class__.__name__)
918
919 except self.ConfigurationError as error:
920 self.nice_config_error(error, line)
921 if self.allow_notification_center:
922 misc.apple_notify('Run %sfailed' % me_dir,
923 'Configuration error')
924 except Exception as error:
925 self.nice_error_handling(error, line)
926 if self.mother:
927 self.do_quit('')
928 if self.allow_notification_center:
929 misc.apple_notify('Run %sfailed' % me_dir,
930 'Exception: %s' % error.__class__.__name__)
931 except KeyboardInterrupt as error:
932 self.stop_on_keyboard_stop()
933 if __debug__:
934 self.nice_config_error(error, line)
935 logger.error(self.keyboard_stop_msg)
936
938 """action to perform to close nicely on a keyboard interupt"""
939 pass
940
941 - def exec_cmd(self, line, errorhandling=False, printcmd=True,
942 precmd=False, postcmd=True, **opt):
962
964 """for third party call, call the line with pre and postfix treatment
965 with global error handling"""
966
967 return self.exec_cmd(line, errorhandling=True, precmd=True)
968
970 """If empty line, do nothing. Default is repeat previous command."""
971 pass
972
973 - def default(self, line, log=True):
974 """Default action if line is not recognized"""
975
976
977 if log:
978 logger.warning("Command \"%s\" not recognized, please try again" % \
979 line.split()[0])
980 if line.strip() in ['q', '.q', 'stop']:
981 logger.info("If you want to quit mg5 please type \"exit\".")
982
983 if self.history and self.history[-1] == line:
984 self.history.pop()
985
986
987
988
989
990
991 - def do_history(self, line):
992 """write in a file the suite of command that was used"""
993
994 args = self.split_arg(line)
995
996 self.check_history(args)
997
998 if len(args) == 0:
999 logger.info('\n'.join(self.history))
1000 return
1001 elif args[0] == 'clean':
1002 self.history = []
1003 logger.info('History is cleaned')
1004 return
1005 elif args[0] == '.':
1006 output_file = os.path.join(self._export_dir, 'Cards', \
1007 'proc_card_mg5.dat')
1008 output_file = open(output_file, 'w')
1009 else:
1010 output_file = open(args[0], 'w')
1011
1012
1013 text = self.get_history_header()
1014 text += ('\n'.join(self.history) + '\n')
1015
1016
1017 output_file.write(text)
1018 output_file.close()
1019
1020 if self.log:
1021 logger.info("History written to " + output_file.name)
1022
1023 - def compile(self, *args, **opts):
1027
1028 - def avoid_history_duplicate(self, line, no_break=[]):
1029 """remove all line in history (but the last) starting with line.
1030 up to the point when a line didn't start by something in no_break.
1031 (reading in reverse order)"""
1032
1033 new_history = []
1034 for i in range(1, len(self.history)+1):
1035 cur_line = self.history[-i]
1036 if i == 1:
1037 new_history.append(cur_line)
1038 elif not any((cur_line.startswith(text) for text in no_break)):
1039 to_add = self.history[:-i+1]
1040 to_add.reverse()
1041 new_history += to_add
1042 break
1043 elif cur_line.startswith(line):
1044 continue
1045 else:
1046 new_history.append(cur_line)
1047
1048 new_history.reverse()
1049 self.history[:] = new_history
1050
1051
1053
1054 if self.history:
1055 self.history.pop()
1056
1057
1058 previous_store_line = self.get_stored_line()
1059
1060
1061 if isinstance(filepath, str):
1062 commandline = open(filepath).readlines()
1063 else:
1064 commandline = filepath
1065 oldinputfile = self.inputfile
1066 oldraw = self.use_rawinput
1067 self.inputfile = (l for l in commandline)
1068 self.use_rawinput = False
1069
1070
1071
1072 for line in self.inputfile:
1073
1074 line = line.replace('\n', '').strip()
1075
1076 if line:
1077 self.exec_cmd(line, precmd=True)
1078 stored = self.get_stored_line()
1079 while stored:
1080 line = stored
1081 self.exec_cmd(line, precmd=True)
1082 stored = self.get_stored_line()
1083
1084
1085 if self.child:
1086 self.child.exec_cmd('quit')
1087 self.inputfile = oldinputfile
1088 self.use_rawinput = oldraw
1089
1090
1091 cmd = self
1092 while hasattr(cmd, 'mother') and cmd.mother:
1093 cmd = cmd.mother
1094 cmd.stored_line = previous_store_line
1095 return
1096
1098 """Default history header"""
1099
1100 return self.history_header
1101
1102 - def postloop(self):
1103 """ """
1104
1105 args = self.split_arg(self.lastcmd)
1106 if args and args[0] in ['quit','exit']:
1107 if 'all' in args:
1108 return True
1109 if len(args) >1 and args[1].isdigit():
1110 if args[1] not in ['0', '1']:
1111 return True
1112 return False
1113
1114
1115
1116
1117 @staticmethod
1124
1125 signal.signal(signal.SIGALRM, handle_alarm)
1126
1127 if fct is None:
1128 fct = raw_input
1129
1130 if timeout:
1131 signal.alarm(timeout)
1132 question += '[%ss to answer] ' % (timeout)
1133 try:
1134 result = fct(question)
1135 except TimeOutError:
1136 if noerror:
1137 logger.info('\nuse %s' % default)
1138 if fct_timeout:
1139 fct_timeout(True)
1140 return default
1141 else:
1142 signal.alarm(0)
1143 raise
1144 finally:
1145 signal.alarm(0)
1146 if fct_timeout:
1147 fct_timeout(False)
1148 return result
1149
1150
1151
1152
1153
1154
1155
1157 """Not in help: exit the mainloop() """
1158
1159 if self.child:
1160 self.child.exec_cmd('quit ' + line, printcmd=False)
1161 return
1162 elif self.mother:
1163 self.mother.child = None
1164 if line == 'all':
1165 pass
1166 elif line:
1167 level = int(line) - 1
1168 if level:
1169 self.mother.lastcmd = 'quit %s' % level
1170 logger.info(' ')
1171 return True
1172
1173
1174 do_EOF = do_quit
1175 do_exit = do_quit
1176
1178 """Not in help: propose some usefull possible action """
1179
1180
1181 if line:
1182 return cmd.Cmd.do_help(self, line)
1183
1184
1185 names = self.get_names()
1186 cmds = {}
1187 names.sort()
1188
1189 prevname = ''
1190 for name in names:
1191 if name[:3] == 'do_':
1192 if name == prevname:
1193 continue
1194 prevname = name
1195 cmdname=name[3:]
1196 try:
1197 doc = getattr(self.cmd, name).__doc__
1198 except Exception:
1199 doc = None
1200 if not doc:
1201 doc = getattr(self, name).__doc__
1202 if not doc:
1203 tag = "Documented commands"
1204 elif ':' in doc:
1205 tag = doc.split(':',1)[0]
1206 else:
1207 tag = "Documented commands"
1208 if tag in cmds:
1209 cmds[tag].append(cmdname)
1210 else:
1211 cmds[tag] = [cmdname]
1212
1213 self.stdout.write("%s\n"%str(self.doc_leader))
1214 for tag in self.helporder:
1215 if tag not in cmds:
1216 continue
1217 header = "%s (type help <topic>):" % tag
1218 self.print_topics(header, cmds[tag], 15,80)
1219 for name, item in cmds.items():
1220 if name in self.helporder:
1221 continue
1222 if name == "Not in help":
1223 continue
1224 header = "%s (type help <topic>):" % name
1225 self.print_topics(header, item, 15,80)
1226
1227
1228
1229 if len(self.history) == 0:
1230 last_action_2 = last_action = 'start'
1231 else:
1232 last_action_2 = last_action = 'none'
1233
1234 pos = 0
1235 authorize = self.next_possibility.keys()
1236 while last_action_2 not in authorize and last_action not in authorize:
1237 pos += 1
1238 if pos > len(self.history):
1239 last_action_2 = last_action = 'start'
1240 break
1241
1242 args = self.history[-1 * pos].split()
1243 last_action = args[0]
1244 if len(args)>1:
1245 last_action_2 = '%s %s' % (last_action, args[1])
1246 else:
1247 last_action_2 = 'none'
1248
1249 logger.info('Contextual Help')
1250 logger.info('===============')
1251 if last_action_2 in authorize:
1252 options = self.next_possibility[last_action_2]
1253 elif last_action in authorize:
1254 options = self.next_possibility[last_action]
1255 else:
1256 return
1257 text = 'The following command(s) may be useful in order to continue.\n'
1258 for option in options:
1259 text+='\t %s \n' % option
1260 logger.info(text)
1261
1263 """Advanced commands: basic display"""
1264
1265 args = self.split_arg(line)
1266
1267
1268 if len(args) == 0:
1269 self.help_display()
1270 raise self.InvalidCmd, 'display require at least one argument'
1271
1272 if args[0] == "options":
1273 outstr = "Value of current Options:\n"
1274 for key, value in self.options.items():
1275 outstr += '%25s \t:\t%s\n' %(key,value)
1276 output.write(outstr)
1277
1278 elif args[0] == "variable":
1279 outstr = "Value of Internal Variable:\n"
1280 try:
1281 var = eval(args[1])
1282 except Exception:
1283 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
1284 else:
1285 outstr += 'GLOBAL:\n'
1286 outstr += misc.nice_representation(var, nb_space=4)
1287
1288 try:
1289 var = eval('self.%s' % args[1])
1290 except Exception:
1291 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
1292 else:
1293 outstr += 'LOCAL:\n'
1294 outstr += misc.nice_representation(var, nb_space=4)
1295 split = args[1].split('.')
1296 for i, name in enumerate(split):
1297 try:
1298 __import__('.'.join(split[:i+1]))
1299 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1])))
1300 except ImportError:
1301 try:
1302 var = eval(args[1])
1303 except Exception, error:
1304 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1]
1305 break
1306 else:
1307 outstr += 'EXTERNAL:\n'
1308 outstr += misc.nice_representation(var, nb_space=4)
1309 else:
1310 var = eval(args[1])
1311 outstr += 'EXTERNAL:\n'
1312 outstr += misc.nice_representation(var, nb_space=4)
1313
1314 pydoc.pager(outstr)
1315
1316
1317 - def do_save(self, line, check=True):
1318 """Save the configuration file"""
1319
1320 args = self.split_arg(line)
1321
1322 if check:
1323 Cmd.check_save(self, args)
1324
1325
1326 if'HOME' in os.environ and os.environ['HOME'] and \
1327 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
1328 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
1329 if hasattr(self, 'me_dir'):
1330 basedir = self.me_dir
1331 elif not MADEVENT:
1332 basedir = MG5DIR
1333 else:
1334 basedir = os.getcwd()
1335 elif MADEVENT:
1336
1337 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']:
1338 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)):
1339 base = pjoin(self.me_dir, 'Cards', config_file)
1340 basedir = self.me_dir
1341 else:
1342 if hasattr(self, 'me_dir'):
1343 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1344 if len(args) == 0 and os.path.exists(base):
1345 self.write_configuration(base, base, self.me_dir)
1346 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1347 basedir = MG5DIR
1348
1349 if len(args) == 0:
1350 args.append(base)
1351 self.write_configuration(args[0], base, basedir, self.options)
1352
1354 """Write the configuration file"""
1355
1356
1357
1358
1359 logger.info('save configuration file to %s' % filepath)
1360 to_write = to_keep.keys()
1361 text = ""
1362
1363 for line in file(basefile):
1364 if '=' in line:
1365 data, value = line.split('=',1)
1366 else:
1367 text += line
1368 continue
1369 data = data.strip()
1370 if data.startswith('#'):
1371 key = data[1:].strip()
1372 else:
1373 key = data
1374 if '#' in value:
1375 value, comment = value.split('#',1)
1376 else:
1377 comment = ''
1378 if key in to_keep:
1379 value = str(to_keep[key])
1380 else:
1381 text += line
1382 continue
1383 try:
1384 to_write.remove(key)
1385 except Exception:
1386 pass
1387 if '_path' in key:
1388
1389
1390 if not os.path.isabs(value):
1391 value = os.path.realpath(os.path.join(basedir, value))
1392 text += '%s = %s # %s \n' % (key, value, comment)
1393 for key in to_write:
1394 if key in to_keep:
1395 text += '%s = %s \n' % (key, to_keep[key])
1396
1397 if not MADEVENT:
1398 text += """\n# MG5 MAIN DIRECTORY\n"""
1399 text += "mg5_path = %s\n" % MG5DIR
1400
1401 writer = open(filepath,'w')
1402 writer.write(text)
1403 writer.close()
1404
1409 """CMD command with shell activate"""
1410
1411
1413 "Run a shell command"
1414
1415 if line.strip() is '':
1416 self.help_shell()
1417 else:
1418 logging.info("running shell command: " + line)
1419 subprocess.call(line, shell=True)
1420
1422 """ add path for shell """
1423
1424
1425
1426 if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep:
1427 if not text:
1428 text = ''
1429 output = self.path_completion(text,
1430 base_dir=\
1431 self.split_arg(line[0:begidx])[-1])
1432 else:
1433 output = self.path_completion(text)
1434 return output
1435
1437 """help for the shell"""
1438 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')
1439 logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
1440
1448 """ a class for answering a question with the path autocompletion"""
1449
1451 """Initializing before starting the main loop"""
1452 self.prompt = '>'
1453 self.value = None
1454 BasicCmd.preloop(self)
1455
1456
1457 - def __init__(self, question, allow_arg=[], default=None,
1458 mother_interface=None, *arg, **opt):
1459 self.question = question
1460 self.wrong_answer = 0
1461 self.allow_arg = [str(a) for a in allow_arg]
1462 self.history_header = ''
1463 self.default_value = str(default)
1464 self.mother_interface = mother_interface
1465 cmd.Cmd.__init__(self, *arg, **opt)
1466
1467 - def __call__(self, question, reprint_opt=True, **opts):
1468
1469 self.question = question
1470 for key,value in opts:
1471 setattr(self, key, value)
1472 if reprint_opt:
1473 print question
1474 return self.cmdloop()
1475
1476
1478 prev_timer = signal.alarm(0)
1479 if prev_timer:
1480 nb_back = len(line)
1481 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1482 self.stdout.write(line)
1483 self.stdout.flush()
1484 try:
1485 out = {}
1486 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
1487 out[' Recognized command'] = BasicCmd.completenames(self, text)
1488
1489 return self.deal_multiple_categories(out)
1490 except Exception, error:
1491 print error
1492
1494
1495
1496 return dir(self)
1497
1498 - def onecmd(self, line, **opt):
1499 """catch all error and stop properly command accordingly
1500 Interpret the argument as though it had been typed in response
1501 to the prompt.
1502
1503 The return value is a flag indicating whether interpretation of
1504 commands by the interpreter should stop.
1505
1506 This allow to pass extra argument for internal call.
1507 """
1508 try:
1509 if '~/' in line and os.environ.has_key('HOME'):
1510 line = line.replace('~/', '%s/' % os.environ['HOME'])
1511 line = os.path.expandvars(line)
1512 cmd, arg, line = self.parseline(line)
1513 if not line:
1514 return self.emptyline()
1515 if cmd is None:
1516 return self.default(line)
1517 self.lastcmd = line
1518 if cmd == '':
1519 return self.default(line)
1520 else:
1521 try:
1522 func = getattr(self, 'do_' + cmd)
1523 except AttributeError:
1524 return self.default(line)
1525 return func(arg, **opt)
1526 except Exception as error:
1527 logger.warning(error)
1528
1529 - def reask(self, reprint_opt=True):
1530 pat = re.compile('\[(\d*)s to answer\]')
1531 prev_timer = signal.alarm(0)
1532
1533 if prev_timer:
1534 if pat.search(self.question):
1535 timeout = int(pat.search(self.question).groups()[0])
1536 else:
1537 timeout=20
1538 print
1539 signal.alarm(timeout)
1540 if reprint_opt:
1541 if not prev_timer:
1542 self.question = pat.sub('',self.question)
1543 print self.question
1544 return False
1545
1547 """Default action if line is not recognized"""
1548
1549 if line.strip() == '' and self.default_value is not None:
1550 self.value = self.default_value
1551 else:
1552 self.value = line
1553
1555 """If empty line, return default"""
1556
1557 if self.default_value is not None:
1558 self.value = self.default_value
1559
1560
1561 - def postcmd(self, stop, line):
1562
1563 try:
1564 if self.value in self.allow_arg:
1565 return True
1566 elif str(self.value) == 'EOF':
1567 self.value = self.default_value
1568 return True
1569 elif line and hasattr(self, 'do_%s' % line.split()[0]):
1570 return self.reask()
1571 elif self.value == 'repeat':
1572 return self.reask()
1573 elif len(self.allow_arg)==0:
1574 return True
1575 else:
1576 raise Exception
1577 except Exception,error:
1578 if self.wrong_answer < 100:
1579 self.wrong_answer += 1
1580 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
1581 % (self.value,','.join(self.allow_arg)))
1582 logger.warning('please retry')
1583 return False
1584 else:
1585 self.value = self.default_value
1586 return True
1587
1589 cmd.Cmd.cmdloop(self, intro)
1590 return self.value
1591
1597
1602 """ a class for answering a question with the path autocompletion"""
1603
1604 completion_prefix=''
1605
1607 prev_timer = signal.alarm(0)
1608 if prev_timer:
1609 nb_back = len(line)
1610 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1611 self.stdout.write(line)
1612 self.stdout.flush()
1613
1614 try:
1615 out = {}
1616 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
1617 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
1618 out[' Recognized command'] = BasicCmd.completenames(self, text)
1619
1620 return self.deal_multiple_categories(out)
1621 except Exception, error:
1622 print error
1623
1629
1631 prev_timer = signal.alarm(0)
1632 if prev_timer:
1633 nb_back = len(line)
1634 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
1635 self.stdout.write(line)
1636 self.stdout.flush()
1637 try:
1638 args = Cmd.split_arg(line[0:begidx])
1639 except Exception, error:
1640 print error
1641
1642
1643 if args[-1].endswith(os.path.sep):
1644
1645 return Cmd.path_completion(text,
1646 os.path.join('.',*[a for a in args \
1647 if a.endswith(os.path.sep)]))
1648 self.completenames(line+text)
1649
1650
1651 - def postcmd(self, stop, line):
1652 try:
1653 if self.value in self.allow_arg:
1654 return True
1655 elif self.value and os.path.isfile(self.value):
1656 return os.path.relpath(self.value)
1657 elif self.value and str(self.value) == 'EOF':
1658 self.value = self.default_value
1659 return True
1660 elif line and hasattr(self, 'do_%s' % line.split()[0]):
1661
1662 reprint_opt = True
1663 elif self.value == 'repeat':
1664 reprint_opt = True
1665 else:
1666 raise Exception
1667 except Exception, error:
1668 print """not valid argument. Valid argument are file path or value in (%s).""" \
1669 % ','.join(self.allow_arg)
1670 print 'please retry'
1671 reprint_opt = False
1672
1673 return self.reask(reprint_opt)
1674
1681
1682
1683
1684
1685 -class CmdFile(file):
1686 """ a class for command input file -in order to debug cmd \n problem"""
1687
1694
1696 """readline method treating correctly a line whithout \n at the end
1697 (add it)
1698 """
1699 if self.lines:
1700 line = self.lines.pop(0)
1701 else:
1702 return ''
1703
1704 if line.endswith('\n'):
1705 return line
1706 else:
1707 return line + '\n'
1708
1711
1714