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 logging
19 import math
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 logger_tuto = logging.getLogger('tutorial')
38 logger_plugin = logging.getLogger('tutorial_plugin')
39
40 try:
41 import madgraph.various.misc as misc
42 from madgraph import MG5DIR, MadGraph5Error
43 MADEVENT = False
44 except ImportError, error:
45 try:
46 import internal.misc as misc
47 except:
48 raise error
49
50 MADEVENT = True
51
52
53 pjoin = os.path.join
56 """Class for run-time error"""
57
58 -def debug(debug_only=True):
59
60 def deco_debug(f):
61
62 if debug_only and not __debug__:
63 return f
64
65 def deco_f(*args, **opt):
66 try:
67 return f(*args, **opt)
68 except Exception, error:
69 logger.error(error)
70 logger.error(traceback.print_exc(file=sys.stdout))
71 return
72 return deco_f
73 return deco_debug
74
75 import string
76
77
78 __all__ = ["Cmd"]
79 PROMPT = '(Cmd) '
80 IDENTCHARS = string.ascii_letters + string.digits + '_'
82 """A simple framework for writing line-oriented command interpreters.
83
84 These are often useful for test harnesses, administrative tools, and
85 prototypes that will later be wrapped in a more sophisticated interface.
86
87 A Cmd instance or subclass instance is a line-oriented interpreter
88 framework. There is no good reason to instantiate Cmd itself; rather,
89 it's useful as a superclass of an interpreter class you define yourself
90 in order to inherit Cmd's methods and encapsulate action methods.
91
92 """
93 prompt = PROMPT
94 identchars = IDENTCHARS
95 ruler = '='
96 lastcmd = ''
97 intro = None
98 doc_leader = ""
99 doc_header = "Documented commands (type help <topic>):"
100 misc_header = "Miscellaneous help topics:"
101 undoc_header = "Undocumented commands:"
102 nohelp = "*** No help on %s"
103 use_rawinput = 1
104
105 - def __init__(self, completekey='tab', stdin=None, stdout=None,**opt):
106 """Instantiate a line-oriented interpreter framework.
107
108 The optional argument 'completekey' is the readline name of a
109 completion key; it defaults to the Tab key. If completekey is
110 not None and the readline module is available, command completion
111 is done automatically. The optional arguments stdin and stdout
112 specify alternate input and output file objects; if not specified,
113 sys.stdin and sys.stdout are used.
114
115 """
116 import sys
117 if stdin is not None:
118 self.stdin = stdin
119 else:
120 self.stdin = sys.stdin
121 if stdout is not None:
122 self.stdout = stdout
123 else:
124 self.stdout = sys.stdout
125 self.cmdqueue = []
126 self.completekey = completekey
127 self.cmd_options = opt
128
130 """Repeatedly issue a prompt, accept input, parse an initial prefix
131 off the received input, and dispatch to action methods, passing them
132 the remainder of the line as argument.
133
134 """
135
136 self.preloop()
137 if self.use_rawinput and self.completekey:
138 try:
139 import readline
140 self.old_completer = readline.get_completer()
141 readline.set_completer(self.complete)
142 readline.parse_and_bind(self.completekey+": complete")
143 except ImportError:
144 pass
145 try:
146 if intro is not None:
147 self.intro = intro
148 if self.intro:
149 self.stdout.write(str(self.intro)+"\n")
150 stop = None
151 while not stop:
152 if self.cmdqueue:
153 line = self.cmdqueue.pop(0)
154 else:
155 if self.use_rawinput:
156 try:
157 line = raw_input(self.prompt)
158 except EOFError:
159 line = 'EOF'
160 else:
161 self.stdout.write(self.prompt)
162 self.stdout.flush()
163 line = self.stdin.readline()
164 if not len(line):
165 line = 'EOF'
166 else:
167 line = line.rstrip('\r\n')
168 line = self.precmd(line)
169 stop = self.onecmd(line)
170 stop = self.postcmd(stop, line)
171 self.postloop()
172 finally:
173 if self.use_rawinput and self.completekey:
174 try:
175 import readline
176 readline.set_completer(self.old_completer)
177 except ImportError:
178 pass
179
180
182 """Hook method executed just before the command line is
183 interpreted, but after the input prompt is generated and issued.
184
185 """
186 return line
187
188 - def postcmd(self, stop, line):
189 """Hook method executed just after a command dispatch is finished."""
190 return stop
191
193 """Hook method executed once when the cmdloop() method is called."""
194 pass
195
196 - def postloop(self):
197 """Hook method executed once when the cmdloop() method is about to
198 return.
199
200 """
201 pass
202
204 """Parse the line into a command name and a string containing
205 the arguments. Returns a tuple containing (command, args, line).
206 'command' and 'args' may be None if the line couldn't be parsed.
207 """
208 line = line.strip()
209 if not line:
210 return None, None, line
211 elif line[0] == '?':
212 line = 'help ' + line[1:]
213 elif line[0] == '!':
214 if hasattr(self, 'do_shell'):
215 line = 'shell ' + line[1:]
216 else:
217 return None, None, line
218 i, n = 0, len(line)
219 while i < n and line[i] in self.identchars: i = i+1
220 cmd, arg = line[:i], line[i:].strip()
221 return cmd, arg, line
222
224 """Interpret the argument as though it had been typed in response
225 to the prompt.
226
227 This may be overridden, but should not normally need to be;
228 see the precmd() and postcmd() methods for useful execution hooks.
229 The return value is a flag indicating whether interpretation of
230 commands by the interpreter should stop.
231
232 """
233 cmd, arg, line = self.parseline(line)
234 if not line:
235 return self.emptyline()
236 if cmd is None:
237 return self.default(line)
238 self.lastcmd = line
239 if cmd == '':
240 return self.default(line)
241 else:
242 try:
243 func = getattr(self, 'do_' + cmd)
244 except AttributeError:
245 return self.default(line)
246 return func(arg)
247
249 """Called when an empty line is entered in response to the prompt.
250
251 If this method is not overridden, it repeats the last nonempty
252 command entered.
253
254 """
255 if self.lastcmd:
256 return self.onecmd(self.lastcmd)
257
259 """Called on an input line when the command prefix is not recognized.
260
261 If this method is not overridden, it prints an error message and
262 returns.
263
264 """
265 self.stdout.write('*** Unknown syntax: %s\n'%line)
266
268 """Method called to complete an input line when no command-specific
269 complete_*() method is available.
270
271 By default, it returns an empty list.
272
273 """
274 return []
275
277 dotext = 'do_'+text
278
279 done = set()
280
281 return [a[3:] for a in self.get_names()
282 if a.startswith(dotext) and a not in done and not done.add(a)]
283
285 """Return the next possible completion for 'text'.
286
287 If a command has not been entered, then complete against command list.
288 Otherwise try to call complete_<command> to get list of completions.
289 """
290 if state == 0:
291 import readline
292 origline = readline.get_line_buffer()
293 line = origline.lstrip()
294 stripped = len(origline) - len(line)
295 begidx = readline.get_begidx() - stripped
296 endidx = readline.get_endidx() - stripped
297 if begidx>0:
298 cmd, args, foo = self.parseline(line)
299 if cmd == '':
300 compfunc = self.completedefault
301 else:
302 try:
303 compfunc = getattr(self, 'complete_' + cmd)
304 except AttributeError:
305 compfunc = self.completedefault
306 else:
307 compfunc = self.completenames
308 self.completion_matches = compfunc(text, line, begidx, endidx)
309 try:
310 return self.completion_matches[state]
311 except IndexError:
312 return None
313
315
316
317 names = []
318 classes = [self.__class__]
319 while classes:
320 aclass = classes.pop(0)
321 if aclass.__bases__:
322 classes = classes + list(aclass.__bases__)
323 names = names + dir(aclass)
324 return names
325
328
330 if arg:
331
332 try:
333 func = getattr(self, 'help_' + arg)
334 except AttributeError:
335 try:
336 doc=getattr(self, 'do_' + arg).__doc__
337 if doc:
338 self.stdout.write("%s\n"%str(doc))
339 return
340 except AttributeError:
341 pass
342 self.stdout.write("%s\n"%str(self.nohelp % (arg,)))
343 return
344 func()
345 else:
346 names = self.get_names()
347 cmds_doc = []
348 cmds_undoc = []
349 help = {}
350 for name in names:
351 if name[:5] == 'help_':
352 help[name[5:]]=1
353 names.sort()
354
355 prevname = ''
356 for name in names:
357 if name[:3] == 'do_':
358 if name == prevname:
359 continue
360 prevname = name
361 cmd=name[3:]
362 if cmd in help:
363 cmds_doc.append(cmd)
364 del help[cmd]
365 elif getattr(self, name).__doc__:
366 cmds_doc.append(cmd)
367 else:
368 cmds_undoc.append(cmd)
369 self.stdout.write("%s\n"%str(self.doc_leader))
370 self.print_topics(self.doc_header, cmds_doc, 15,80)
371 self.print_topics(self.misc_header, help.keys(),15,80)
372 self.print_topics(self.undoc_header, cmds_undoc, 15,80)
373
381
383 """Display a list of strings as a compact set of columns.
384
385 Each column is only as wide as necessary.
386 Columns are separated by two spaces (one was not legible enough).
387 """
388 if not list:
389 self.stdout.write("<empty>\n")
390 return
391 nonstrings = [i for i in range(len(list))
392 if not isinstance(list[i], str)]
393 if nonstrings:
394 raise TypeError, ("list[i] not a string for i in %s" %
395 ", ".join(map(str, nonstrings)))
396 size = len(list)
397 if size == 1:
398 self.stdout.write('%s\n'%str(list[0]))
399 return
400
401 for nrows in range(1, len(list)):
402 ncols = (size+nrows-1) // nrows
403 colwidths = []
404 totwidth = -2
405 for col in range(ncols):
406 colwidth = 0
407 for row in range(nrows):
408 i = row + nrows*col
409 if i >= size:
410 break
411 x = list[i]
412 colwidth = max(colwidth, len(x))
413 colwidths.append(colwidth)
414 totwidth += colwidth + 2
415 if totwidth > displaywidth:
416 break
417 if totwidth <= displaywidth:
418 break
419 else:
420 nrows = len(list)
421 ncols = 1
422 colwidths = [0]
423 for row in range(nrows):
424 texts = []
425 for col in range(ncols):
426 i = row + nrows*col
427 if i >= size:
428 x = ""
429 else:
430 x = list[i]
431 texts.append(x)
432 while texts and not texts[-1]:
433 del texts[-1]
434 for col in range(len(texts)):
435 texts[col] = texts[col].ljust(colwidths[col])
436 self.stdout.write("%s\n"%str(" ".join(texts)))
437
438
439
440
441
442
443
444 -class BasicCmd(OriginalCmd):
445 """Simple extension for the readline"""
446
448 """ This has been refactorized here so that it can be called when another
449 program called by MG5 (such as MadAnalysis5) changes this attribute of readline"""
450 if readline:
451 if not 'libedit' in readline.__doc__:
452 readline.set_completion_display_matches_hook(self.print_suggestions)
453 else:
454 readline.set_completion_display_matches_hook()
455
459
461 """convert the multiple category in a formatted list understand by our
462 specific readline parser"""
463
464 if not formatting:
465 return dico
466
467 if 'libedit' in readline.__doc__:
468
469 out = []
470 for name, opt in dico.items():
471 out += opt
472 return list(set(out))
473
474
475 if not forceCategory and all(len(s) <= 1 for s in dico.values() ):
476 values = set((s[0] for s in dico.values() if len(s)==1))
477 if len(values) == 1:
478 return values
479
480
481 out = []
482 valid=0
483
484 for name, opt in dico.items():
485 if not opt:
486 continue
487 name = name.replace(' ', '_')
488 valid += 1
489 out.append(opt[0].rstrip()+'@@'+name+'@@')
490
491 d = {}
492 for x in opt:
493 d[x] = 1
494 opt = list(d.keys())
495 opt.sort()
496 out += opt
497
498 if not forceCategory and valid == 1:
499 out = out[1:]
500
501 return out
502
503 @debug()
505 """print auto-completions by category"""
506 if not hasattr(self, 'completion_prefix'):
507 self.completion_prefix = ''
508 longest_match_length += len(self.completion_prefix)
509 try:
510 if len(matches) == 1:
511 self.stdout.write(matches[0]+' ')
512 return
513 self.stdout.write('\n')
514 l2 = [a[-2:] for a in matches]
515 if '@@' in l2:
516 nb_column = self.getTerminalSize()//(longest_match_length+1)
517 pos=0
518 for val in self.completion_matches:
519 if val.endswith('@@'):
520 category = val.rsplit('@@',2)[1]
521 category = category.replace('_',' ')
522 self.stdout.write('\n %s:\n%s\n' % (category, '=' * (len(category)+2)))
523 start = 0
524 pos = 0
525 continue
526 elif pos and pos % nb_column ==0:
527 self.stdout.write('\n')
528 self.stdout.write(self.completion_prefix + val + \
529 ' ' * (longest_match_length +1 -len(val)))
530 pos +=1
531 self.stdout.write('\n')
532 else:
533
534 nb_column = self.getTerminalSize()//(longest_match_length+1)
535 for i,val in enumerate(matches):
536 if i and i%nb_column ==0:
537 self.stdout.write('\n')
538 self.stdout.write(self.completion_prefix + val + \
539 ' ' * (longest_match_length +1 -len(val)))
540 self.stdout.write('\n')
541
542 self.stdout.write(self.prompt+readline.get_line_buffer())
543 self.stdout.flush()
544 except Exception, error:
545 if __debug__:
546 logger.error(error)
547
549 def ioctl_GWINSZ(fd):
550 try:
551 import fcntl, termios, struct
552 cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
553 '1234'))
554 except Exception:
555 return None
556 return cr
557 cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
558 if not cr:
559 try:
560 fd = os.open(os.ctermid(), os.O_RDONLY)
561 cr = ioctl_GWINSZ(fd)
562 os.close(fd)
563 except Exception:
564 pass
565 if not cr:
566 try:
567 cr = (os.environ['LINES'], os.environ['COLUMNS'])
568 except Exception:
569 cr = (25, 80)
570 return int(cr[1])
571
573 """Return the next possible completion for 'text'.
574 If a command has not been entered, then complete against command list.
575 Otherwise try to call complete_<command> to get list of completions.
576 """
577 if state == 0:
578 import readline
579 origline = readline.get_line_buffer()
580 line = origline.lstrip()
581 stripped = len(origline) - len(line)
582 begidx = readline.get_begidx() - stripped
583 endidx = readline.get_endidx() - stripped
584
585 if ';' in line:
586 begin, line = line.rsplit(';',1)
587 begidx = begidx - len(begin) - 1
588 endidx = endidx - len(begin) - 1
589 if line[:begidx] == ' ' * begidx:
590 begidx=0
591
592 if begidx>0:
593 cmd, args, foo = self.parseline(line)
594 if cmd == '':
595 compfunc = self.completedefault
596 else:
597 try:
598 compfunc = getattr(self, 'complete_' + cmd)
599 except AttributeError, error:
600 compfunc = self.completedefault
601 except Exception, error:
602 misc.sprint(error)
603 else:
604 compfunc = self.completenames
605
606
607 if line and begidx > 2 and line[begidx-2:begidx] == '\ ':
608 Ntext = line.split(os.path.sep)[-1]
609 self.completion_prefix = Ntext.rsplit('\ ', 1)[0] + '\ '
610 to_rm = len(self.completion_prefix) - 1
611 Nbegidx = len(line.rsplit(os.path.sep, 1)[0]) + 1
612 data = compfunc(Ntext.replace('\ ', ' '), line, Nbegidx, endidx)
613 self.completion_matches = [p[to_rm:] for p in data
614 if len(p)>to_rm]
615
616 elif line and line[begidx-1] in ['-',"=",':']:
617 try:
618 sep = line[begidx-1]
619 Ntext = line.split()[-1]
620 self.completion_prefix = Ntext.rsplit(sep,1)[0] + sep
621 to_rm = len(self.completion_prefix)
622 Nbegidx = len(line.rsplit(None, 1)[0])
623 data = compfunc(Ntext, line, Nbegidx, endidx)
624 self.completion_matches = [p[to_rm:] for p in data
625 if len(p)>to_rm]
626 except Exception, error:
627 print error
628 else:
629 self.completion_prefix = ''
630 self.completion_matches = compfunc(text, line, begidx, endidx)
631
632 self.completion_matches = [ l if l[-1] in [' ','@','=',os.path.sep]
633 else ((l + ' ') if not l.endswith('\\$') else l[:-2])
634 for l in self.completion_matches if l]
635
636 try:
637 return self.completion_matches[state]
638 except IndexError, error:
639
640
641
642 return None
643
644 @staticmethod
646 """Split a line of arguments"""
647
648 split = line.split()
649 out=[]
650 tmp=''
651 for data in split:
652 if data[-1] == '\\':
653 tmp += data[:-1]+' '
654 elif tmp:
655 tmp += data
656 tmp = os.path.expanduser(os.path.expandvars(tmp))
657 out.append(tmp)
658
659
660 tmp = ''
661 else:
662 out.append(data)
663 return out
664
665 @staticmethod
667 """Propose completions of text in list"""
668
669 if not text:
670 completions = list
671 else:
672 completions = [ f
673 for f in list
674 if f.startswith(text)
675 ]
676
677 return completions
678
679
680 @staticmethod
681 - def path_completion(text, base_dir = None, only_dirs = False,
682 relative=True):
683 """Propose completions of text to compose a valid path"""
684
685 if base_dir is None:
686 base_dir = os.getcwd()
687 base_dir = os.path.expanduser(os.path.expandvars(base_dir))
688
689 if text == '~':
690 text = '~/'
691 prefix, text = os.path.split(text)
692 prefix = os.path.expanduser(os.path.expandvars(prefix))
693 base_dir = os.path.join(base_dir, prefix)
694 if prefix:
695 prefix += os.path.sep
696
697 if only_dirs:
698 completion = [prefix + f + os.path.sep
699 for f in os.listdir(base_dir)
700 if f.startswith(text) and \
701 os.path.isdir(os.path.join(base_dir, f)) and \
702 (not f.startswith('.') or text.startswith('.'))
703 ]
704 else:
705 completion = [ prefix + f
706 for f in os.listdir(base_dir)
707 if f.startswith(text) and \
708 os.path.isfile(os.path.join(base_dir, f)) and \
709 (not f.startswith('.') or text.startswith('.'))
710 ]
711
712 completion = completion + \
713 [prefix + f + os.path.sep
714 for f in os.listdir(base_dir)
715 if f.startswith(text) and \
716 os.path.isdir(os.path.join(base_dir, f)) and \
717 (not f.startswith('.') or text.startswith('.'))
718 ]
719
720 if relative:
721 completion += [prefix + f for f in ['.'+os.path.sep, '..'+os.path.sep] if \
722 f.startswith(text) and not prefix.startswith('.')]
723
724 completion = [a.replace(' ','\ ') for a in completion]
725 return completion
726
731 """Extension of the cmd object for only the check command"""
732
733 - def check_history(self, args):
734 """check the validity of line"""
735
736 if len(args) > 1:
737 self.help_history()
738 raise self.InvalidCmd('\"history\" command takes at most one argument')
739
740 if not len(args):
741 return
742
743 if args[0] =='.':
744 if not self._export_dir:
745 raise self.InvalidCmd("No default directory is defined for \'.\' option")
746 elif args[0] != 'clean':
747 dirpath = os.path.dirname(args[0])
748 if dirpath and not os.path.exists(dirpath) or \
749 os.path.isdir(args[0]):
750 raise self.InvalidCmd("invalid path %s " % dirpath)
751
753 """check that the line is compatible with save options"""
754
755 if len(args) > 2:
756 self.help_save()
757 raise self.InvalidCmd, 'too many arguments for save command.'
758
759 if len(args) == 2:
760 if args[0] != 'options':
761 self.help_save()
762 raise self.InvalidCmd, '\'%s\' is not recognized as first argument.' % \
763 args[0]
764 else:
765 args.pop(0)
766
768 """Extension of the cmd object for only the help command"""
769
771 logger.info("-- terminates the application",'$MG:color:BLUE')
772 logger.info("syntax: quit",'$MG:BOLD')
773
774 help_EOF = help_quit
775
776 - def help_history(self):
777 logger.info("-- interact with the command history.",'$MG:color:BLUE')
778 logger.info("syntax: history [FILEPATH|clean|.] ",'$MG:BOLD')
779 logger.info(" > If FILEPATH is \'.\' and \'output\' is done,")
780 logger.info(" Cards/proc_card_mg5.dat will be used.")
781 logger.info(" > If FILEPATH is omitted, the history will be output to stdout.")
782 logger.info(" \"clean\" will remove all entries from the history.")
783
785 logger.info("-- access to the in-line help",'$MG:color:BLUE')
786 logger.info("syntax: help",'$MG:BOLD')
787
789 """help text for save"""
790 logger.info("-- save options configuration to filepath.",'$MG:color:BLUE')
791 logger.info("syntax: save [options] [FILEPATH]",'$MG:BOLD')
792
794 """help for display command"""
795 logger.info("-- display a the status of various internal state variables",'$MG:color:BLUE')
796 logger.info("syntax: display " + "|".join(self._display_opts),'$MG:BOLD')
797
806
807 - def complete_history(self, text, line, begidx, endidx):
808 "Complete the history command"
809
810 args = self.split_arg(line[0:begidx])
811
812
813 if args[-1].endswith(os.path.sep):
814 return self.path_completion(text,
815 os.path.join('.',*[a for a in args \
816 if a.endswith(os.path.sep)]))
817
818 if len(args) == 1:
819 return self.path_completion(text)
820
839
840 -class Cmd(CheckCmd, HelpCmd, CompleteCmd, BasicCmd):
841 """Extension of the cmd.Cmd command line.
842 This extensions supports line breaking, history, comments,
843 internal call to cmdline, path completion,...
844 this class should be MG5 independent"""
845
846
847 next_possibility = {}
848 history_header = ""
849
850 _display_opts = ['options','variable']
851 allow_notification_center = True
852
854 """expected error for wrong command"""
855 pass
856
857 ConfigurationError = InvalidCmd
858
859 debug_output = 'debug'
860 error_debug = """Please report this bug to developers\n
861 More information is found in '%(debug)s'.\n
862 Please attach this file to your report."""
863 config_debug = error_debug
864
865 keyboard_stop_msg = """stopping all current operation
866 in order to quit the program please enter exit"""
867
868 if MADEVENT:
869 plugin_path = []
870 else:
871 plugin_path = [pjoin(MG5DIR, 'PLUGIN')]
872 if 'PYTHONPATH' in os.environ:
873 for PluginCandidate in os.environ['PYTHONPATH'].split(':'):
874 try:
875 dirlist = os.listdir(PluginCandidate)
876 except OSError:
877 continue
878 for onedir in dirlist:
879 if onedir == 'MG5aMC_PLUGIN':
880 plugin_path.append(pjoin(PluginCandidate, 'MG5aMC_PLUGIN'))
881 break
882 else:
883 continue
884 break
885
887 """Init history and line continuation"""
888
889 self.log = True
890 self.history = []
891 self.save_line = ''
892 super(Cmd, self).__init__(*arg, **opt)
893 self.__initpos = os.path.abspath(os.getcwd())
894 self.child = None
895 self.mother = None
896 self.inputfile = None
897 self.haspiping = not sys.stdin.isatty()
898 self.stored_line = ''
899
900 if not hasattr(self, 'helporder'):
901 self.helporder = ['Documented commands']
902
904 """Hook method executed once when the cmdloop() method is called."""
905 if self.completekey:
906 try:
907 import readline
908 self.old_completer = readline.get_completer()
909 readline.set_completer(self.complete)
910 readline.parse_and_bind(self.completekey+": complete")
911 except ImportError:
912 readline = None
913 pass
914 if readline and not 'libedit' in readline.__doc__:
915 readline.set_completion_display_matches_hook(self.print_suggestions)
916
917
919
920 self.preloop()
921 if intro is not None:
922 self.intro = intro
923 if self.intro:
924 print self.intro
925 stop = None
926 while not stop:
927 if self.cmdqueue:
928 line = self.cmdqueue[0]
929 del self.cmdqueue[0]
930 else:
931 if self.use_rawinput:
932 try:
933 line = raw_input(self.prompt)
934 except EOFError:
935 line = 'EOF'
936 else:
937 sys.stdout.write(self.prompt)
938 sys.stdout.flush()
939 line = sys.stdin.readline()
940 if not len(line):
941 line = 'EOF'
942 else:
943 line = line[:-1]
944 try:
945 line = self.precmd(line)
946 stop = self.onecmd(line)
947 except BaseException, error:
948 self.error_handling(error, line)
949 if isinstance(error, KeyboardInterrupt):
950 stop = True
951 finally:
952 stop = self.postcmd(stop, line)
953 self.postloop()
954
956 """avoid to have html opening / notification"""
957 self.allow_notification_center = False
958 try:
959 self.options['automatic_html_opening'] = False
960 self.options['notification_center'] = False
961
962 except:
963 pass
964
965
967 """ A suite of additional function needed for in the cmd
968 this implement history, line breaking, comment treatment,...
969 """
970
971 if not line:
972 return line
973
974
975 if self.save_line:
976 line = self.save_line + line
977 self.save_line = ''
978
979 line = line.lstrip()
980
981 if line.endswith('\\'):
982 self.save_line = line[:-1]
983 return ''
984
985
986 if '#' in line:
987 line = line.split('#')[0]
988
989
990 if ';' in line:
991 lines = line.split(';')
992 for subline in lines:
993 if not (subline.startswith("history") or subline.startswith('help') \
994 or subline.startswith('#*')):
995 self.history.append(subline)
996 stop = self.onecmd_orig(subline)
997 stop = self.postcmd(stop, subline)
998 return ''
999
1000
1001 self.history.append(line)
1002 return line
1003
1004 - def postcmd(self,stop, line):
1005 """ finishing a command
1006 This looks if the command add a special post part."""
1007
1008 if line.strip():
1009 try:
1010 cmd, subline = line.split(None, 1)
1011 except ValueError:
1012 pass
1013 else:
1014 if hasattr(self,'post_%s' %cmd):
1015 stop = getattr(self, 'post_%s' % cmd)(stop, subline)
1016 return stop
1017
1042
1043
1044
1045
1046 - def ask(self, question, default, choices=[], path_msg=None,
1047 timeout = True, fct_timeout=None, ask_class=None, alias={},
1048 first_cmd=None, text_format='4', force=False,
1049 return_instance=False, **opt):
1050 """ ask a question with some pre-define possibility
1051 path info is
1052 """
1053
1054 if path_msg:
1055 path_msg = [path_msg]
1056 else:
1057 path_msg = []
1058
1059 if timeout is True:
1060 try:
1061 timeout = self.options['timeout']
1062 except Exception:
1063 pass
1064
1065
1066 if choices + path_msg:
1067 question += ' ['
1068 question += "\033[%sm%s\033[0m, " % (text_format, default)
1069 for data in choices[:9] + path_msg:
1070 if default == data:
1071 continue
1072 else:
1073 question += "%s, " % data
1074
1075 if len(choices) > 9:
1076 question += '... , '
1077 question = question[:-2]+']'
1078 else:
1079 question += "[\033[%sm%s\033[0m] " % (text_format, default)
1080 if ask_class:
1081 obj = ask_class
1082 elif path_msg:
1083 obj = OneLinePathCompletion
1084 else:
1085 obj = SmartQuestion
1086
1087 if alias:
1088 choices += alias.keys()
1089
1090 question_instance = obj(question, allow_arg=choices, default=default,
1091 mother_interface=self, **opt)
1092
1093 if first_cmd:
1094 if isinstance(first_cmd, str):
1095 question_instance.onecmd(first_cmd)
1096 else:
1097 for line in first_cmd:
1098 question_instance.onecmd(line)
1099 if not self.haspiping:
1100 if hasattr(obj, "haspiping"):
1101 obj.haspiping = self.haspiping
1102
1103 if force:
1104 answer = default
1105 else:
1106 answer = self.check_answer_in_input_file(question_instance, default, path_msg)
1107 if answer is not None:
1108 if answer in alias:
1109 answer = alias[answer]
1110 if ask_class:
1111 line=answer
1112 answer = question_instance.default(line)
1113 question_instance.postcmd(answer, line)
1114 if not return_instance:
1115 return question_instance.answer
1116 else:
1117 return question_instance.answer , question_instance
1118 if hasattr(question_instance, 'check_answer_consistency'):
1119 question_instance.check_answer_consistency()
1120 if not return_instance:
1121 return answer
1122 else:
1123 return answer, question_instance
1124
1125 question = question_instance.question
1126 if not force:
1127 value = Cmd.timed_input(question, default, timeout=timeout,
1128 fct=question_instance, fct_timeout=fct_timeout)
1129 else:
1130 value = default
1131
1132 try:
1133 if value in alias:
1134 value = alias[value]
1135 except TypeError:
1136 pass
1137
1138 if value == default and ask_class:
1139 value = question_instance.default(default)
1140 if hasattr(question_instance, 'answer'):
1141 value = question_instance.answer
1142
1143
1144 if not return_instance:
1145 return value
1146 else:
1147 return value, question_instance
1148
1158
1159
1161 """check import command"""
1162
1163 if '-f' in args:
1164 self.force = True
1165 args.remove('-f')
1166 if args[0] != 'command':
1167 args.set(0, 'command')
1168 if len(args) != 2:
1169 raise self.InvalidCmd('import command requires one filepath argument')
1170 if not os.path.exists(args[1]):
1171 raise 'No such file or directory %s' % args[1]
1172
1173
1257
1259 """store a line of the input file which should be executed by the higher mother"""
1260
1261 if self.mother:
1262 self.mother.store_line(line)
1263 else:
1264 self.stored_line = line
1265
1267 """return stored line and clean it"""
1268 if self.mother:
1269 value = self.mother.get_stored_line()
1270 self.mother.stored_line = None
1271 else:
1272 value = self.stored_line
1273 self.stored_line = None
1274 return value
1275
1276
1277
1279 """ """
1280
1281 if self.child:
1282 return self.child.nice_error_handling(error, line)
1283
1284 os.chdir(self.__initpos)
1285
1286 self.log = False
1287 if os.path.exists(self.debug_output):
1288 os.remove(self.debug_output)
1289 try:
1290 super(Cmd,self).onecmd('history %s' % self.debug_output.replace(' ', '\ '))
1291 except Exception, error:
1292 logger.error(error)
1293
1294 debug_file = open(self.debug_output, 'a')
1295 traceback.print_exc(file=debug_file)
1296 if hasattr(error, 'filename'):
1297 debug_file.write("Related File: %s\n" % error.filename)
1298
1299 if self.history and line == self.history[-1]:
1300 error_text = 'Command \"%s\" interrupted with error:\n' % line
1301 elif self.history:
1302 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
1303 error_text += '\"%s\" with error:\n' % self.history[-1]
1304 else:
1305 error_text = ''
1306 error_text += '%s : %s\n' % (error.__class__.__name__,
1307 str(error).replace('\n','\n\t'))
1308 error_text += self.error_debug % {'debug':self.debug_output}
1309 logger_stderr.critical(error_text)
1310
1311
1312
1313 try:
1314 self.do_display('options', debug_file)
1315 except Exception, error:
1316 debug_file.write('Fail to write options with error %s' % error)
1317
1318
1319 for card in ['proc_card_mg5.dat','param_card.dat', 'run_card.dat']:
1320 try:
1321 ff = open(pjoin(self.me_dir, 'Cards', card))
1322 debug_file.write(ff.read())
1323 ff.close()
1324 except Exception:
1325 pass
1326
1327
1328 if hasattr(self, 'options') and 'crash_on_error' in self.options and \
1329 self.options['crash_on_error']:
1330 logger.info('stop computation due to crash_on_error=True')
1331 sys.exit(str(error))
1332
1333
1334 if self.use_rawinput == False or self.inputfile:
1335 return True
1336 elif self.mother:
1337 if self.mother.use_rawinput is False:
1338 return True
1339
1340 elif self.mother.mother:
1341 if self.mother.mother.use_rawinput is False:
1342 return True
1343
1344 return False
1345
1346
1347
1349 if self.child:
1350 return self.child.nice_user_error(error, line)
1351
1352 os.chdir(self.__initpos)
1353 if not self.history or line == self.history[-1]:
1354 error_text = 'Command \"%s\" interrupted with error:\n' % line
1355 else:
1356 error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
1357 error_text += '\"%s\" with error:\n' % self.history[-1]
1358 error_text += '%s : %s' % (error.__class__.__name__,
1359 str(error).replace('\n','\n\t'))
1360 logger_stderr.error(error_text)
1361
1362 if hasattr(self, 'options') and 'crash_on_error' in self.options and \
1363 self.options['crash_on_error']:
1364 logger.info('stop computation due to crash_on_error=True')
1365 sys.exit(str(error))
1366
1367
1368 if self.use_rawinput == False or self.inputfile:
1369 return True
1370 elif self.mother:
1371 if self.mother.use_rawinput is False:
1372 return True
1373 elif self.mother.mother:
1374 if self.mother.mother.use_rawinput is False:
1375 return True
1376
1377
1378 self.history.pop()
1379 return False
1380
1382 if self.child:
1383 return self.child.nice_user_error(error, line)
1384
1385 os.chdir(self.__initpos)
1386 if not self.history or line == self.history[-1]:
1387 error_text = 'Error detected in \"%s\"\n' % line
1388 else:
1389 error_text = 'Error detected in sub-command %s\n' % self.history[-1]
1390 error_text += 'write debug file %s \n' % self.debug_output
1391 self.log = False
1392 super(Cmd,self).onecmd('history %s' % self.debug_output)
1393 debug_file = open(self.debug_output, 'a')
1394 traceback.print_exc(file=debug_file)
1395 error_text += self.config_debug % {'debug' :self.debug_output}
1396 error_text += '%s : %s' % (error.__class__.__name__,
1397 str(error).replace('\n','\n\t'))
1398 logger_stderr.error(error_text)
1399
1400
1401 try:
1402 self.do_display('options', debug_file)
1403 except Exception, error:
1404 debug_file.write('Fail to write options with error %s' % error)
1405 if hasattr(self, 'options') and 'crash_on_error' in self.options and \
1406 self.options['crash_on_error']:
1407 logger.info('stop computation due to crash_on_error=True')
1408 sys.exit(str(error))
1409
1410
1411 if self.use_rawinput == False or self.inputfile:
1412 return True
1413 elif self.mother:
1414 if self.mother.use_rawinput is False:
1415 return True
1416 elif self.mother.mother:
1417 if self.mother.mother.use_rawinput is False:
1418 return True
1419
1420
1421 if self.history:
1422 self.history.pop()
1423 return False
1424
1426 """Interpret the argument as though it had been typed in response
1427 to the prompt.
1428
1429 The return value is a flag indicating whether interpretation of
1430 commands by the interpreter should stop.
1431
1432 This allow to pass extra argument for internal call.
1433 """
1434 if '~/' in line and os.environ.has_key('HOME'):
1435 line = line.replace('~/', '%s/' % os.environ['HOME'])
1436 if '#' in line:
1437 line = line.split('#')[0]
1438
1439 line = os.path.expandvars(line)
1440 cmd, arg, line = self.parseline(line)
1441 if not line:
1442 return self.emptyline()
1443 if cmd is None:
1444 return self.default(line)
1445 self.lastcmd = line
1446 if cmd == '':
1447 return self.default(line)
1448 else:
1449 try:
1450 func = getattr(self, 'do_' + cmd)
1451 except AttributeError:
1452 return self.default(line)
1453 return func(arg, **opt)
1454
1497
1498
1499
1500 - def onecmd(self, line, **opt):
1501 """catch all error and stop properly command accordingly"""
1502
1503 try:
1504 return self.onecmd_orig(line, **opt)
1505 except BaseException, error:
1506 self.error_handling(error, line)
1507
1508
1510 """action to perform to close nicely on a keyboard interupt"""
1511 pass
1512
1513 - def exec_cmd(self, line, errorhandling=False, printcmd=True,
1514 precmd=False, postcmd=True,
1515 child=True, **opt):
1535
1537 """for third party call, call the line with pre and postfix treatment
1538 with global error handling"""
1539
1540 return self.exec_cmd(line, errorhandling=True, precmd=True)
1541
1543 """If empty line, do nothing. Default is repeat previous command."""
1544 pass
1545
1546 - def default(self, line, log=True):
1547 """Default action if line is not recognized"""
1548
1549
1550 if log:
1551 logger.warning("Command \"%s\" not recognized, please try again" % \
1552 line.split()[0])
1553 if line.strip() in ['q', '.q', 'stop']:
1554 logger.info("If you want to quit mg5 please type \"exit\".")
1555
1556 if self.history and self.history[-1] == line:
1557 self.history.pop()
1558
1559
1560 - def do_history(self, line):
1561 """write in a file the suite of command that was used"""
1562
1563 args = self.split_arg(line)
1564
1565 self.check_history(args)
1566
1567 if len(args) == 0:
1568 logger.info('\n'.join(self.history))
1569 return
1570 elif args[0] == 'clean':
1571 self.history = []
1572 logger.info('History is cleaned')
1573 return
1574 elif args[0] == '.':
1575 output_file = os.path.join(self._export_dir, 'Cards', \
1576 'proc_card_mg5.dat')
1577 output_file = open(output_file, 'w')
1578 else:
1579 output_file = open(args[0], 'w')
1580
1581
1582 text = self.get_history_header()
1583 text += ('\n'.join(self.history) + '\n')
1584
1585
1586 output_file.write(text)
1587 output_file.close()
1588
1589 if self.log:
1590 logger.info("History written to " + output_file.name)
1591
1592 - def compile(self, *args, **opts):
1596
1597 - def avoid_history_duplicate(self, line, no_break=[]):
1598 """remove all line in history (but the last) starting with line.
1599 up to the point when a line didn't start by something in no_break.
1600 (reading in reverse order)"""
1601
1602 new_history = []
1603 for i in range(1, len(self.history)+1):
1604 cur_line = self.history[-i]
1605 if i == 1:
1606 new_history.append(cur_line)
1607 elif not any((cur_line.startswith(text) for text in no_break)):
1608 to_add = self.history[:-i+1]
1609 to_add.reverse()
1610 new_history += to_add
1611 break
1612 elif cur_line.startswith(line):
1613 continue
1614 else:
1615 new_history.append(cur_line)
1616
1617 new_history.reverse()
1618 self.history[:] = new_history
1619
1620
1622
1623 if self.history:
1624 self.history.pop()
1625
1626
1627 previous_store_line = self.get_stored_line()
1628
1629
1630 if isinstance(filepath, str):
1631 commandline = open(filepath).readlines()
1632 else:
1633 commandline = filepath
1634 oldinputfile = self.inputfile
1635 oldraw = self.use_rawinput
1636 self.inputfile = (l for l in commandline)
1637 self.use_rawinput = False
1638
1639
1640
1641 for line in self.inputfile:
1642
1643 line = line.replace('\n', '').strip()
1644
1645 if line:
1646 self.exec_cmd(line, precmd=True)
1647 stored = self.get_stored_line()
1648 while stored:
1649 line = stored
1650 self.exec_cmd(line, precmd=True)
1651 stored = self.get_stored_line()
1652
1653
1654 if self.child:
1655 self.child.exec_cmd('quit')
1656 self.inputfile = oldinputfile
1657 self.use_rawinput = oldraw
1658
1659
1660 cmd = self
1661 while hasattr(cmd, 'mother') and cmd.mother:
1662 cmd = cmd.mother
1663 cmd.stored_line = previous_store_line
1664 return
1665
1667 """Default history header"""
1668
1669 return self.history_header
1670
1671 - def postloop(self):
1672 """ """
1673
1674 if self.use_rawinput and self.completekey:
1675 try:
1676 import readline
1677 readline.set_completer(self.old_completer)
1678 del self.old_completer
1679 except ImportError:
1680 pass
1681 except AttributeError:
1682 pass
1683
1684 args = self.split_arg(self.lastcmd)
1685 if args and args[0] in ['quit','exit']:
1686 if 'all' in args:
1687 return True
1688 if len(args) >1 and args[1].isdigit():
1689 if args[1] not in ['0', '1']:
1690 return True
1691
1692 return False
1693
1694
1695
1696
1697 @staticmethod
1704
1705 signal.signal(signal.SIGALRM, handle_alarm)
1706
1707 if fct is None:
1708 fct = raw_input
1709
1710 if timeout:
1711 signal.alarm(timeout)
1712 question += '[%ss to answer] ' % (timeout)
1713 try:
1714 result = fct(question)
1715 except TimeOutError:
1716 if noerror:
1717 logger.info('\nuse %s' % default)
1718 if fct_timeout:
1719 fct_timeout(True)
1720 return default
1721 else:
1722 signal.alarm(0)
1723 raise
1724 finally:
1725 signal.alarm(0)
1726 if fct_timeout:
1727 fct_timeout(False)
1728 return result
1729
1730
1731
1732
1733
1734
1735
1737 """Not in help: exit the mainloop() """
1738
1739 if self.child:
1740 self.child.exec_cmd('quit ' + line, printcmd=False)
1741 return
1742 elif self.mother:
1743 self.mother.child = None
1744 if line == 'all':
1745 self.mother.do_quit('all')
1746 pass
1747 elif line:
1748 level = int(line) - 1
1749 if level:
1750 self.mother.lastcmd = 'quit %s' % level
1751 elif self.inputfile:
1752 for line in self.inputfile:
1753 logger.warning('command not executed: %s' % line.replace('\n',''))
1754
1755 return True
1756
1757
1758 do_EOF = do_quit
1759 do_exit = do_quit
1760
1762 """Not in help: propose some usefull possible action """
1763
1764
1765 if line:
1766 return super(Cmd, self).do_help(line)
1767
1768
1769 names = self.get_names()
1770 cmds = {}
1771 names.sort()
1772
1773 prevname = ''
1774 for name in names:
1775 if name[:3] == 'do_':
1776 if name == prevname:
1777 continue
1778 prevname = name
1779 cmdname=name[3:]
1780 try:
1781 doc = getattr(self.cmd, name).__doc__
1782 except Exception:
1783 doc = None
1784 if not doc:
1785 doc = getattr(self, name).__doc__
1786 if not doc:
1787 tag = "Documented commands"
1788 elif ':' in doc:
1789 tag = doc.split(':',1)[0]
1790 else:
1791 tag = "Documented commands"
1792 if tag in cmds:
1793 cmds[tag].append(cmdname)
1794 else:
1795 cmds[tag] = [cmdname]
1796
1797 self.stdout.write("%s\n"%str(self.doc_leader))
1798 for tag in self.helporder:
1799 if tag not in cmds:
1800 continue
1801 header = "%s (type help <topic>):" % tag
1802 self.print_topics(header, cmds[tag], 15,80)
1803 for name, item in cmds.items():
1804 if name in self.helporder:
1805 continue
1806 if name == "Not in help":
1807 continue
1808 header = "%s (type help <topic>):" % name
1809 self.print_topics(header, item, 15,80)
1810
1811
1812
1813 if len(self.history) == 0:
1814 last_action_2 = last_action = 'start'
1815 else:
1816 last_action_2 = last_action = 'none'
1817
1818 pos = 0
1819 authorize = self.next_possibility.keys()
1820 while last_action_2 not in authorize and last_action not in authorize:
1821 pos += 1
1822 if pos > len(self.history):
1823 last_action_2 = last_action = 'start'
1824 break
1825
1826 args = self.history[-1 * pos].split()
1827 last_action = args[0]
1828 if len(args)>1:
1829 last_action_2 = '%s %s' % (last_action, args[1])
1830 else:
1831 last_action_2 = 'none'
1832
1833 logger.info('Contextual Help')
1834 logger.info('===============')
1835 if last_action_2 in authorize:
1836 options = self.next_possibility[last_action_2]
1837 elif last_action in authorize:
1838 options = self.next_possibility[last_action]
1839 else:
1840 return
1841 text = 'The following command(s) may be useful in order to continue.\n'
1842 for option in options:
1843 text+='\t %s \n' % option
1844 logger.info(text)
1845
1847 """Advanced commands: basic display"""
1848
1849 args = self.split_arg(line)
1850
1851
1852 if len(args) == 0:
1853 self.help_display()
1854 raise self.InvalidCmd, 'display require at least one argument'
1855
1856 if args[0] == "options":
1857 outstr = "Value of current Options:\n"
1858 for key, value in self.options.items():
1859 outstr += '%25s \t:\t%s\n' %(key,value)
1860 output.write(outstr)
1861
1862 elif args[0] == "variable":
1863 outstr = "Value of Internal Variable:\n"
1864 try:
1865 var = eval(args[1])
1866 except Exception:
1867 outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
1868 else:
1869 outstr += 'GLOBAL:\n'
1870 outstr += misc.nice_representation(var, nb_space=4)
1871
1872 try:
1873 var = eval('self.%s' % args[1])
1874 except Exception:
1875 outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
1876 else:
1877 outstr += 'LOCAL:\n'
1878 outstr += misc.nice_representation(var, nb_space=4)
1879 split = args[1].split('.')
1880 for i, name in enumerate(split):
1881 try:
1882 __import__('.'.join(split[:i+1]))
1883 exec('%s=sys.modules[\'%s\']' % (split[i], '.'.join(split[:i+1])))
1884 except ImportError:
1885 try:
1886 var = eval(args[1])
1887 except Exception, error:
1888 outstr += 'EXTERNAL:\nVariable %s is not a external variable\n' % args[1]
1889 break
1890 else:
1891 outstr += 'EXTERNAL:\n'
1892 outstr += misc.nice_representation(var, nb_space=4)
1893 else:
1894 var = eval(args[1])
1895 outstr += 'EXTERNAL:\n'
1896 outstr += misc.nice_representation(var, nb_space=4)
1897
1898 pydoc.pager(outstr)
1899
1900
1901 - def do_save(self, line, check=True):
1902 """Save the configuration file"""
1903
1904 args = self.split_arg(line)
1905
1906 if check:
1907 Cmd.check_save(self, args)
1908
1909
1910 if 'HOME' in os.environ and os.environ['HOME'] and \
1911 os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
1912 base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
1913 if hasattr(self, 'me_dir'):
1914 basedir = self.me_dir
1915 elif not MADEVENT:
1916 basedir = MG5DIR
1917 else:
1918 basedir = os.getcwd()
1919 elif MADEVENT:
1920
1921 for config_file in ['me5_configuration.txt', 'amcatnlo_configuration.txt']:
1922 if os.path.exists(pjoin(self.me_dir, 'Cards', config_file)):
1923 base = pjoin(self.me_dir, 'Cards', config_file)
1924 basedir = self.me_dir
1925 else:
1926 if hasattr(self, 'me_dir'):
1927 base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
1928 if len(args) == 0 and os.path.exists(base):
1929 self.write_configuration(base, base, self.me_dir)
1930 base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
1931 basedir = MG5DIR
1932
1933 if len(args) == 0:
1934 args.append(base)
1935 self.write_configuration(args[0], base, basedir, self.options)
1936
1938 """Write the configuration file"""
1939
1940
1941
1942
1943 logger.info('save configuration file to %s' % filepath)
1944 to_write = to_keep.keys()
1945 text = ""
1946 has_mg5_path = False
1947
1948 for line in file(basefile):
1949 if '=' in line:
1950 data, value = line.split('=',1)
1951 else:
1952 text += line
1953 continue
1954 data = data.strip()
1955 if data.startswith('#'):
1956 key = data[1:].strip()
1957 else:
1958 key = data
1959 if '#' in value:
1960 value, comment = value.split('#',1)
1961 else:
1962 comment = ''
1963 if key in to_keep:
1964 value = str(to_keep[key])
1965 else:
1966 text += line
1967 continue
1968 if key == 'mg5_path':
1969 has_mg5_path = True
1970 try:
1971 to_write.remove(key)
1972 except Exception:
1973 pass
1974 if '_path' in key:
1975
1976
1977 if not os.path.isabs(value):
1978 value = os.path.realpath(os.path.join(basedir, value))
1979 text += '%s = %s # %s \n' % (key, value, comment)
1980 for key in to_write:
1981 if key in to_keep:
1982 text += '%s = %s \n' % (key, to_keep[key])
1983
1984 if not MADEVENT and not has_mg5_path:
1985 text += """\n# MG5 MAIN DIRECTORY\n"""
1986 text += "mg5_path = %s\n" % MG5DIR
1987
1988 writer = open(filepath,'w')
1989 writer.write(text)
1990 writer.close()
1991
1996 """CMD command with shell activate"""
1997
1998
2000 "Run a shell command"
2001
2002 if line.strip() is '':
2003 self.help_shell()
2004 else:
2005 logging.info("running shell command: " + line)
2006 subprocess.call(line, shell=True)
2007
2022
2024 """help for the shell"""
2025 logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')
2026 logger.info("syntax: shell CMD (or ! CMD)",'$MG:BOLD')
2027
2031
2035 """ a class for answering a question with the path autocompletion"""
2036
2037 allowpath = False
2039 """Initializing before starting the main loop"""
2040 self.prompt = '>'
2041 self.value = None
2042 BasicCmd.preloop(self)
2043
2044 @property
2047
2048 - def __init__(self, question, allow_arg=[], default=None,
2049 mother_interface=None, *arg, **opt):
2050
2051 self.question = question
2052 self.wrong_answer = 0
2053 self.allow_arg = [str(a) for a in allow_arg]
2054 self.history_header = ''
2055 self.default_value = str(default)
2056 self.mother_interface = mother_interface
2057
2058 if 'case' in opt:
2059 self.casesensitive = opt['case']
2060 del opt['case']
2061 elif 'casesensitive' in opt:
2062 self.casesensitive = opt['casesensitive']
2063 del opt['casesensitive']
2064 else:
2065 self.casesensistive = True
2066 super(SmartQuestion, self).__init__(*arg, **opt)
2067
2068 - def __call__(self, question, reprint_opt=True, **opts):
2069
2070 self.question = question
2071 for key,value in opts:
2072 setattr(self, key, value)
2073 if reprint_opt:
2074 print question
2075 logger_tuto.info("Need help here? type 'help'", '$MG:BOLD')
2076 logger_plugin.info("Need help here? type 'help'" , '$MG:BOLD')
2077 return self.cmdloop()
2078
2079
2081 prev_timer = signal.alarm(0)
2082 if prev_timer:
2083 nb_back = len(line)
2084 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2085 self.stdout.write(line)
2086 self.stdout.flush()
2087 try:
2088 out = {}
2089 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2090 out[' Recognized command'] = super(SmartQuestion, self).completenames(text,line, *ignored)
2091
2092 return self.deal_multiple_categories(out)
2093 except Exception, error:
2094 print error
2095
2096 completedefault = completenames
2097
2099
2100
2101 return dir(self)
2102
2103 - def onecmd(self, line, **opt):
2104 """catch all error and stop properly command accordingly
2105 Interpret the argument as though it had been typed in response
2106 to the prompt.
2107
2108 The return value is a flag indicating whether interpretation of
2109 commands by the interpreter should stop.
2110
2111 This allow to pass extra argument for internal call.
2112 """
2113 try:
2114 if '~/' in line and os.environ.has_key('HOME'):
2115 line = line.replace('~/', '%s/' % os.environ['HOME'])
2116 line = os.path.expandvars(line)
2117 cmd, arg, line = self.parseline(line)
2118 if not line:
2119 return self.emptyline()
2120 if cmd is None:
2121 return self.default(line)
2122 self.lastcmd = line
2123 if cmd == '':
2124 return self.default(line)
2125 else:
2126 try:
2127 func = getattr(self, 'do_' + cmd)
2128 except AttributeError:
2129 return self.default(line)
2130 return func(arg, **opt)
2131 except Exception as error:
2132 logger.warning(error)
2133 if __debug__:
2134 raise
2135
2136 - def reask(self, reprint_opt=True):
2137 pat = re.compile('\[(\d*)s to answer\]')
2138 prev_timer = signal.alarm(0)
2139
2140 if prev_timer:
2141 if pat.search(self.question):
2142 timeout = int(pat.search(self.question).groups()[0])
2143 signal.alarm(timeout)
2144 if reprint_opt:
2145 if not prev_timer:
2146 self.question = pat.sub('',self.question)
2147 print self.question.encode('utf8')
2148
2149 if self.mother_interface:
2150 answer = self.mother_interface.check_answer_in_input_file(self, 'EOF',
2151 path=self.allowpath)
2152 if answer:
2153 stop = self.default(answer)
2154 self.postcmd(stop, answer)
2155 return False
2156
2157 return False
2158
2160
2161 text=line
2162 out ={}
2163 out['Options'] = Cmd.list_completion(text, self.allow_arg)
2164 out['command'] = BasicCmd.completenames(self, text)
2165
2166 if not text:
2167 if out['Options']:
2168 logger.info( "Here is the list of all valid options:", '$MG:BOLD')
2169 logger.info( " "+ "\n ".join(out['Options']))
2170 if out['command']:
2171 logger.info( "Here is the list of command available:", '$MG:BOLD')
2172 logger.info( " "+ "\n ".join(out['command']))
2173 else:
2174 if out['Options']:
2175 logger.info( "Here is the list of all valid options starting with \'%s\'" % text, '$MG:BOLD')
2176 logger.info( " "+ "\n ".join(out['Options']))
2177 if out['command']:
2178 logger.info( "Here is the list of command available starting with \'%s\':" % text, '$MG:BOLD')
2179 logger.info( " "+ "\n ".join(out['command']))
2180 elif not out['Options']:
2181 logger.info( "No possibility starting with \'%s\'" % text, '$MG:BOLD')
2182 logger.info( "You can type help XXX, to see all command starting with XXX", '$MG:BOLD')
2186
2188 """Default action if line is not recognized"""
2189
2190 if line.strip() == '' and self.default_value is not None:
2191 self.value = self.default_value
2192 else:
2193 self.value = line
2194
2196 """If empty line, return default"""
2197
2198 if self.default_value is not None:
2199 self.value = self.default_value
2200
2201
2202 - def postcmd(self, stop, line):
2203
2204 try:
2205 if self.value in self.allow_arg:
2206 return True
2207 elif str(self.value) == 'EOF':
2208 self.value = self.default_value
2209 return True
2210 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2211 return self.reask()
2212 elif self.value in ['repeat', 'reask']:
2213 return self.reask()
2214 elif len(self.allow_arg)==0:
2215 return True
2216 elif ' ' in line.strip() and '=' in self.value:
2217 line,n = re.subn(r'\s*=\s*', '=', line)
2218 if n:
2219 self.default(line)
2220 return self.postcmd(stop, line)
2221 if not self.casesensitive:
2222 for ans in self.allow_arg:
2223 if ans.lower() == self.value.lower():
2224 self.value = ans
2225 return True
2226 break
2227 else:
2228 raise Exception
2229
2230
2231 else:
2232 raise Exception
2233 except Exception,error:
2234 if self.wrong_answer < 100:
2235 self.wrong_answer += 1
2236 logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
2237 % (self.value,','.join(self.allow_arg)))
2238 logger.warning('please retry')
2239 return False
2240 else:
2241 self.value = self.default_value
2242 return True
2243
2247
2253
2258 """ a class for answering a question with the path autocompletion"""
2259
2260 completion_prefix=''
2261 allowpath=True
2262
2263 - def completenames(self, text, line, begidx, endidx, formatting=True):
2264 prev_timer = signal.alarm(0)
2265 if prev_timer:
2266 nb_back = len(line)
2267 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2268 self.stdout.write(line)
2269 self.stdout.flush()
2270
2271 try:
2272 out = {}
2273 out[' Options'] = Cmd.list_completion(text, self.allow_arg)
2274 out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
2275 out[' Recognized command'] = BasicCmd.completenames(self, text, line, begidx, endidx)
2276
2277 return self.deal_multiple_categories(out, formatting)
2278 except Exception, error:
2279 print error
2280
2286
2288 prev_timer = signal.alarm(0)
2289 if prev_timer:
2290 nb_back = len(line)
2291 self.stdout.write('\b'*nb_back + '[timer stopped]\n')
2292 self.stdout.write(line)
2293 self.stdout.flush()
2294 try:
2295 args = Cmd.split_arg(line[0:begidx])
2296 except Exception, error:
2297 print error
2298
2299
2300 if args[-1].endswith(os.path.sep):
2301
2302 return Cmd.path_completion(text,
2303 os.path.join('.',*[a for a in args \
2304 if a.endswith(os.path.sep)]),
2305 begidx, endidx)
2306 return self.completenames(text, line, begidx, endidx)
2307
2308
2309 - def postcmd(self, stop, line):
2310 try:
2311 if self.value in self.allow_arg:
2312 return True
2313 elif self.value and os.path.isfile(self.value):
2314 return os.path.relpath(self.value)
2315 elif self.value and str(self.value) == 'EOF':
2316 self.value = self.default_value
2317 return True
2318 elif line and hasattr(self, 'do_%s' % line.split()[0]):
2319
2320 reprint_opt = True
2321 elif self.value == 'repeat':
2322 reprint_opt = True
2323 else:
2324 raise Exception
2325 except Exception, error:
2326 print """not valid argument. Valid argument are file path or value in (%s).""" \
2327 % ','.join(self.allow_arg)
2328 print 'please retry'
2329 reprint_opt = False
2330
2331 if line != 'EOF':
2332 return self.reask(reprint_opt)
2333
2340
2344 """A class for asking a question on which program to run.
2345 This is the abstract class
2346
2347 Behavior for each switch can be customize via:
2348 set_default_XXXX() -> set default value
2349 This is super-seeded by self.default_switch if that attribute is defined (and has a key for XXXX)
2350 get_allowed_XXXX() -> return list of possible value
2351 check_value_XXXX(value) -> return True/False if the user can set such value
2352 switch_off_XXXXX() -> set it off (called for special mode)
2353 color_for_XXXX(value) -> return the representation on the screen for value
2354 get_cardcmd_for_XXXX(value)> return the command to run to customize the cards to
2355 match the status
2356 print_options_XXXX() -> return the text to disply below "other options"
2357 default is other possible value (ordered correctly)
2358
2359 consistency_XX_YY(val_XX, val_YY)
2360 -> XX is the new key set by the user to a new value val_XX
2361 -> YY is another key set by the user.
2362 -> return value should be None or "replace_YY"
2363
2364 consistency_XX(val_XX):
2365 check the consistency of the other switch given the new status of this one.
2366 return a dict {key:replaced_value} or {} if nothing to do
2367
2368 user typing "NAME" will result to a call to self.ans_NAME(None)
2369 user typing "NAME=XX" will result to a call to self.ans_NAME('XX')
2370
2371 Note on case sensitivity:
2372 -------------------------
2373 the XXX is displayed with the case in self.to_control
2374 but ALL functions should use the lower case version.
2375 for key associated to get_allowed_keys(),
2376 if (user) value not in that list.
2377 -> try to find the first entry matching up to the case
2378 for ans_XXX, set the value to lower case, but if case_XXX is set to True
2379 """
2380
2381 case_sensitive = False
2382 quit_on = ['0','done', 'EOF','','auto']
2383
2384 - def __init__(self, to_control, motherinstance, *args, **opts):
2385 """to_control is a list of ('KEY': 'Choose the shower/hadronization program')
2386 """
2387
2388 self.to_control = to_control
2389 if 'hide_line' in opts:
2390 self.hide_line = opts['hide_line']
2391 else:
2392 self.hide_line = []
2393
2394 self.mother_interface = motherinstance
2395 self.inconsistent_keys = {}
2396
2397
2398 self.inconsistent_details = {}
2399 self.last_changed = []
2400
2401
2402 self.switch = {}
2403 for key, _ in to_control:
2404 self.switch[key.lower()] = 'temporary'
2405
2406 self.set_default_switch()
2407 question = self.create_question()
2408
2409
2410 allowed_args = [ `i`+';' for i in range(1, 1+len(self.to_control))]
2411 for key in self.switch:
2412 allowed_args += ['%s=%s;' % (key,s) for s in self.get_allowed(key)]
2413
2414 allowed_args += [key[4:]+';' for key in dir(self) if key.startswith('ans_')]
2415 if 'allow_arg' in opts:
2416 allowed_args += opts['allow_arg']
2417 del opts['allow_arg']
2418
2419 allowed_args +=["0", "done"]
2420 SmartQuestion.__init__(self, question, allowed_args, *args, **opts)
2421 self.options = self.mother_interface.options
2422
2449
2450
2451
2452
2453
2455
2456 for key,_ in self.to_control:
2457 key = key.lower()
2458 if hasattr(self, 'default_switch') and key in self.default_switch:
2459 self.switch[key] = self.default_switch[key]
2460 continue
2461 if hasattr(self, 'set_default_%s' % key):
2462 getattr(self, 'set_default_%s' % key)()
2463 else:
2464 self.default_switch_for(key)
2465
2467 """use this if they are no dedicated function for such key"""
2468
2469 if hasattr(self, 'get_allowed_%s' % key):
2470 return getattr(self, 'get_allowed_%s' % key)()[0]
2471 else:
2472 self.switch[key] = 'OFF'
2473
2475 """set all valid parameter to OFF --call before special keyword--
2476 """
2477
2478 for key in self.switch:
2479 if hasattr(self, 'switch_off_%s' % key):
2480 getattr(self, 'switch_off_%s' % key)()
2481 elif self.check_value(key, self.switch[key]):
2482 self.switch[key] = 'OFF'
2483 self.inconsistent_details = {}
2484 self.inconsistent_keys = {}
2485
2486
2488 """return True/False if the value is a correct value to be set by the USER.
2489 other value than those can be set by the system --like-- Not available.
2490 This does not check the full consistency of the switch
2491 """
2492
2493 if hasattr(self, 'check_value_%s' % key):
2494 return getattr(self, 'check_value_%s' % key)(value)
2495 elif value in self.get_allowed(key):
2496 return True
2497 else:
2498 return False
2499
2500
2502 """ return the list of command that need to be run to have a consistent
2503 set of cards with the switch value choosen """
2504
2505 switch = self.answer
2506 cmd= []
2507 for key in self.switch:
2508 if hasattr(self, 'get_cardcmd_for_%s' % key):
2509 cmd += getattr(self, 'get_cardcmd_for_%s' % key)(switch[key])
2510 return cmd
2511
2512
2514 """return the list of possible value for key"""
2515
2516 if hasattr(self, 'get_allowed_%s' % key):
2517 return getattr(self, 'get_allowed_%s' % key)()
2518 else:
2519 return ['ON', 'OFF']
2520
2521 - def default(self, line, raise_error=False):
2522 """Default action if line is not recognized"""
2523
2524 line=line.strip().replace('@', '__at__')
2525 if ';' in line:
2526 for l in line.split(';'):
2527 if l:
2528 out = self.default(l)
2529 return out
2530
2531 if '=' in line:
2532 base, value = line.split('=',1)
2533 base = base.strip()
2534 value = value.strip()
2535
2536 if base.isdigit() :
2537 try:
2538 base = self.to_control[int(base)-1][0]
2539 except:
2540 pass
2541 elif ' ' in line:
2542 base, value = line.split(' ', 1)
2543 elif hasattr(self, 'ans_%s' % line.lower()):
2544 base, value = line.lower(), None
2545 elif line.isdigit() and line in [`i` for i in range(1, len(self.to_control)+1)]:
2546
2547 base = self.to_control[int(line)-1][0].lower()
2548 return self.default(base)
2549 elif line.lower() in self.switch:
2550
2551 base = line.lower()
2552 try:
2553 cur = self.get_allowed(base).index(self.switch[base])
2554 except:
2555 if self.get_allowed(base):
2556 value = self.get_allowed(base)[0]
2557 else:
2558 logger.warning('Can not switch "%s" to another value via number', base)
2559 self.value='reask'
2560 return
2561 else:
2562 try:
2563 value = self.get_allowed(base)[cur+1]
2564 except IndexError:
2565 value = self.get_allowed(base)[0]
2566 if value == "OFF" and cur == 0:
2567 logger.warning("Invalid action: %s" % self.print_options(base))
2568 elif cur == 0:
2569 logger.warning("Can not change value for this parameter")
2570
2571
2572 elif line in ['', 'done', 'EOF', 'eof','0']:
2573 super(ControlSwitch, self).default(line)
2574 return self.answer
2575 elif line in 'auto':
2576 self.switch['dynamical'] = True
2577 return super(ControlSwitch, self).default(line)
2578 elif raise_error:
2579 raise NotValidInput('unknow command: %s' % line)
2580 else:
2581 logger.warning('unknow command: %s' % line)
2582 self.value = 'reask'
2583 return
2584
2585 self.value = 'reask'
2586 base = base.lower()
2587 if hasattr(self, 'ans_%s' % base):
2588 if value and not self.is_case_sensitive(base):
2589 value = value.lower()
2590 getattr(self, 'ans_%s' % base)(value)
2591 elif base in self.switch:
2592 self.set_switch(base, value)
2593 elif raise_error:
2594 raise NotValidInput('Not valid command: %s' % line)
2595 else:
2596 logger.warning('Not valid command: %s' % line)
2597
2599 """check if a key is case sensitive"""
2600
2601 case = self.case_sensitive
2602 if hasattr(self, 'case_%s' % key):
2603 case = getattr(self, 'case_%s' % key)
2604 return case
2605
2606 - def onecmd(self, line, **opt):
2611
2612 @property
2614
2615
2616 for key,_ in self.to_control:
2617 if not self.check_value(key, self.switch[key]):
2618 self.switch[key] = 'OFF'
2619
2620 if not self.inconsistent_keys:
2621 return self.switch
2622 else:
2623 out = dict(self.switch)
2624 out.update(self.inconsistent_keys)
2625 return out
2626
2627 - def postcmd(self, stop, line):
2628
2629
2630
2631 try:
2632 out = super(ControlSwitch,self).postcmd(stop, line)
2633 except AttributeError:
2634 pass
2635
2636 line = line.strip()
2637 if ';' in line:
2638 line= [l for l in line.split(';') if l][-1]
2639 if line in self.quit_on:
2640 return True
2641 self.create_question()
2642 return self.reask(True)
2643
2644
2646 """change a switch to a given value"""
2647
2648 assert key in self.switch
2649
2650 if hasattr(self, 'ans_%s' % key):
2651 if not self.is_case_sensitive(key):
2652 value = value.lower()
2653 return getattr(self, 'ans_%s' % key)(value)
2654
2655 if not self.is_case_sensitive(key) and value not in self.get_allowed(key):
2656 lower = [t.lower() for t in self.get_allowed(key)]
2657 try:
2658 ind = lower.index(value.lower())
2659 except ValueError:
2660 pass
2661 else:
2662 value = self.get_allowed(key)[ind]
2663
2664 check = self.check_value(key, value)
2665 if not check:
2666 logger.warning('"%s" not valid option for "%s"', value, key)
2667 return
2668 if isinstance(check, str):
2669 value = check
2670
2671 self.switch[key] = value
2672
2673 if user:
2674 self.check_consistency(key, value)
2675
2677
2678 if not keys:
2679 self.inconsistent_keys = {}
2680 self.inconsistent_details = {}
2681 elif isinstance(keys, list):
2682 for key in keys:
2683 if key in self.inconsistent_keys:
2684 del self.inconsistent_keys[keys]
2685 del self.inconsistent_details[keys]
2686 else:
2687 if keys in self.inconsistent_keys:
2688 del self.inconsistent_keys[keys]
2689 del self.inconsistent_details[keys]
2690
2692 """check the consistency of the new flag with the old ones"""
2693
2694
2695 if key in self.last_changed:
2696 self.last_changed.remove(key)
2697 self.last_changed.append(key)
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711 if hasattr(self, 'consistency_%s' % key):
2712 rules = dict([(key2, None) for key2 in self.switch])
2713 rules.update(getattr(self, 'consistency_%s' % key)(value, self.switch))
2714 else:
2715 rules = {}
2716 for key2,value2 in self.switch.items():
2717 if hasattr(self, 'consistency_%s_%s' % (key,key2)):
2718 rules[key2] = getattr(self, 'consistency_%s_%s' % (key,key2))(value, value2)
2719
2720
2721 if rules[key2] is not None and not self.check_value(key2, rules[key2]):
2722 if rules[key2] != 'OFF':
2723 logger.debug('consistency_%s_%s returns invalid output. Assume no conflict')
2724 rules[key2] = None
2725 else:
2726 rules[key2] = None
2727
2728
2729
2730
2731
2732 self.remove_inconsistency(key)
2733
2734 for key2 in self.switch:
2735 if rules[key2]:
2736 info = {'orig_value': self.switch[key2],
2737 'changed_key': key,
2738 'new_changed_key_val': value,
2739 'replacement': rules[key2]}
2740 if key2 in self.inconsistent_details:
2741 self.inconsistent_details[key2].append(info)
2742 else:
2743 self.inconsistent_details[key2] = [info]
2744
2745 if not self.inconsistent_details:
2746 return
2747
2748
2749 for key2 in dict(self.inconsistent_details):
2750 for conflict in list(self.inconsistent_details[key2]):
2751 keep_conflict = True
2752
2753 if conflict['orig_value'] != self.switch[key2]:
2754 keep_conflict = False
2755
2756 if self.switch[conflict['changed_key']] != conflict['new_changed_key_val']:
2757 keep_conflict = False
2758 if not keep_conflict:
2759 self.inconsistent_details[key2].remove(conflict)
2760 if not self.inconsistent_details[key2]:
2761 del self.inconsistent_details[key2]
2762
2763
2764
2765
2766 tmp_switch = dict(self.switch)
2767
2768
2769 to_check = [(c['changed_key'], c['new_changed_key_val']) \
2770 for k in self.inconsistent_details.values() for c in k
2771 if c['changed_key'] != key]
2772
2773 to_check.sort(lambda x, y: -1 if self.last_changed.index(x[0])>self.last_changed.index(y[0]) else 1)
2774
2775
2776 to_check = [(key, value)] + to_check
2777
2778 nstep = 0
2779 while len(to_check) and nstep < 50:
2780
2781 nstep +=1
2782 key2, value2 = to_check.pop(0)
2783 if hasattr(self, 'consistency_%s' % key2):
2784 rules = dict([(k, None) for k in self.switch])
2785 rules.update(getattr(self, 'consistency_%s' % key2)(value, tmp_switch))
2786 else:
2787 rules = self.check_consistency_with_all(key2)
2788
2789 for key, replacement in rules.items():
2790 if replacement:
2791 tmp_switch[key] = replacement
2792 to_check.append((key, replacement))
2793
2794
2795
2796 pos = {}
2797 for i, (key,value) in enumerate(to_check):
2798 pos[key] = i
2799 to_check_new = []
2800 for i, (key,value) in enumerate(to_check):
2801 if pos[key] == i:
2802 to_check_new.append((key,value))
2803 to_check = to_check_new
2804 if nstep >=50:
2805 logger.critical('Failed to find a consistent set of switch values.')
2806
2807
2808
2809 self.inconsistent_keys = {}
2810 for key2, value2 in tmp_switch.items():
2811 if value2 != self.switch[key2]:
2812
2813 if value2 == 'OFF' and not self.check_value(key2, 'OFF'):
2814 continue
2815 self.inconsistent_keys[key2] = value2
2816
2817
2819 rules = {}
2820 for key2,value2 in self.switch.items():
2821 if hasattr(self, 'consistency_%s_%s' % (key,key2)):
2822 rules[key2] = getattr(self, 'consistency_%s_%s' % (key,key2))(value, value2)
2823 else:
2824 rules[key2] = None
2825 return rules
2826
2827
2828
2829 green = '\x1b[32m%s\x1b[0m'
2830 yellow = '\x1b[33m%s\x1b[0m'
2831 red = '\x1b[31m%s\x1b[0m'
2832 bold = '\x1b[01m%s\x1b[0m'
2834
2835 if consistency and key in self.inconsistent_keys:
2836 return self.color_for_value(key, self.inconsistent_keys[key], consistency=False) +\
2837 u' \u21d0 '+ self.yellow % switch_value
2838
2839 if self.check_value(key, switch_value):
2840 if hasattr(self, 'color_for_%s' % key):
2841 return getattr(self, 'color_for_%s' % key)(switch_value)
2842 if switch_value in ['OFF']:
2843
2844 return self.red % switch_value
2845 else:
2846 return self.green % switch_value
2847 else:
2848 if ' ' in switch_value:
2849 return self.bold % switch_value
2850 else:
2851 return self.red % switch_value
2852
2854
2855 if hasattr(self, 'print_options_%s' % key) and not keep_default:
2856 return getattr(self, 'print_options_%s' % key)()
2857
2858
2859 try:
2860 ind = self.get_allowed(key).index(self.switch[key])
2861 except Exception, err:
2862 options = self.get_allowed(key)
2863 else:
2864 options = self.get_allowed(key)[ind:]+ self.get_allowed(key)[:ind]
2865
2866 info = '|'.join([v for v in options if v != self.switch[key]])
2867 if info == '':
2868 info = 'Please install module'
2869 return info
2870
2871 - def do_help(self, line, list_command=False):
2872 """dedicated help for the control switch"""
2873
2874 if line:
2875 return self.print_help_for_switch(line)
2876
2877
2878 logger.info(" ")
2879 logger.info(" In order to change a switch you can:")
2880 logger.info(" - type 'NAME = VALUE' to set the switch NAME to a given value.")
2881 logger.info(" - type 'ID = VALUE' to set the switch correspond to the line ID to a given value.")
2882 logger.info(" - type 'ID' where ID is the value of the line to pass from one value to the next.")
2883 logger.info(" - type 'NAME' to set the switch NAME to the next value.")
2884 logger.info("")
2885 logger.info(" You can type 'help NAME' for more help on a given switch")
2886 logger.info("")
2887 logger.info(" Special keyword:", '$MG:BOLD')
2888 logger.info(" %s" % '\t'.join([p[4:] for p in dir(self) if p.startswith('ans_')]) )
2889 logger.info(" type 'help XXX' for more information")
2890 if list_command:
2891 super(ControlSwitch, self).do_help(line)
2892
2893
2895 """ """
2896
2897 arg = line.split()[0]
2898
2899 if hasattr(self, 'help_%s' % arg):
2900 return getattr(self, 'help_%s' % arg)('')
2901
2902 if hasattr(self, 'ans_%s' % arg):
2903 return getattr(self, 'help_%s' % arg).__doc__
2904
2905 if arg in self.switch:
2906 logger.info(" information for switch %s: ", arg, '$MG:BOLD')
2907 logger.info(" allowed value:")
2908 logger.info(" %s", '\t'.join(self.get_allowed(arg)))
2909 if hasattr(self, 'help_text_%s' % arg):
2910 logger.info("")
2911 for line in getattr(self, 'help_text_%s' % arg):
2912 logger.info(line)
2913
2914
2915
2916
3087
3089 """ create the question with correct formatting"""
3090
3091
3092
3093 try:
3094 nb_rows, nb_col = os.popen('stty size', 'r').read().split()
3095 nb_rows, nb_col = int(nb_rows), int(nb_col)
3096 except Exception,error:
3097 nb_rows, nb_col = 20, 80
3098
3099
3100 max_len_description = 0
3101 max_len_switch = 0
3102 max_len_name = 0
3103 max_len_add_info = 0
3104 max_len_potential_switch = 0
3105 max_nb_key = 1 + int(math.log10(len(self.to_control)))
3106
3107
3108 for key, descrip in self.to_control:
3109 if key in self.hide_line:
3110 continue
3111
3112 if len(descrip) > max_len_description: max_len_description = len(descrip)
3113 if len(key) > max_len_name: max_len_name = len(key)
3114 if key in self.inconsistent_keys:
3115 to_display = '%s < %s' % (self.switch[key], self.inconsistent_keys[key])
3116 else:
3117 to_display = self.switch[key]
3118 if len(to_display) > max_len_switch: max_len_switch=len(to_display)
3119
3120 info = self.print_options(key)
3121 if len(info)> max_len_add_info: max_len_add_info = len(info)
3122
3123 if self.get_allowed(key):
3124 max_k = max(len(k) for k in self.get_allowed(key))
3125 else:
3126 max_k = 0
3127 if max_k > max_len_potential_switch: max_len_potential_switch = max_k
3128
3129 upper_line, lower_line, f1, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3130 max_len_name, max_len_add_info,
3131 max_len_potential_switch, max_nb_key)
3132 f3 = 0
3133
3134 text = \
3135 ["The following switches determine which programs are run:",
3136 upper_line
3137 ]
3138
3139
3140
3141 for i,(key, descrip) in enumerate(self.to_control):
3142
3143 if key in self.hide_line and not __debug__:
3144 continue
3145
3146 data_to_format = {'nb': i+1,
3147 'descrip': descrip,
3148 'name': key,
3149 'switch': self.color_for_value(key,self.switch[key]),
3150 'add_info': self.print_options(key),
3151 'switch_nc': self.switch[key],
3152 'strike_switch': u'\u0336'.join(' %s ' %self.switch[key].upper()) + u'\u0336',
3153 }
3154
3155 hidden_line = False
3156 if __debug__ and key in self.hide_line:
3157 data_to_format['descrip'] = '\x1b[32m%s\x1b[0m' % data_to_format['descrip']
3158 data_to_format['add_info'] = '\x1b[32m%s\x1b[0m' % data_to_format['add_info']
3159 data_to_format['name'] = '\x1b[32m%s\x1b[0m' % data_to_format['name']
3160 hidden_line=True
3161
3162 if key in self.inconsistent_keys:
3163
3164 _,_,_, f2 = self.question_formatting(nb_col, max_len_description, max_len_switch,
3165 max_len_name, max_len_add_info,
3166 max_len_potential_switch, max_nb_key,
3167 key=key)
3168
3169 data_to_format['conflict_switch_nc'] = self.inconsistent_keys[key]
3170 data_to_format['conflict_switch'] = self.color_for_value(key,self.inconsistent_keys[key], consistency=False)
3171
3172 if hidden_line:
3173 f2 = re.sub('%(\((?:name|descrip|add_info)\)-?)(\d+)s',
3174 lambda x: '%%%s%ds' % (x.group(1),int(x.group(2))+9),
3175 f2)
3176 text.append(f2 % data_to_format)
3177 elif hidden_line:
3178 if not f3:
3179 f3 = re.sub('%(\((?:name|descrip|add_info)\)-?)(\d+)s',
3180 lambda x: '%%%s%ds' % (x.group(1),int(x.group(2))+9),
3181 f1)
3182 text.append(f3 % data_to_format)
3183 else:
3184 text.append(f1 % data_to_format)
3185
3186
3187 text.append(lower_line)
3188
3189
3190 example = None
3191 for key in self.switch:
3192 if len(self.get_allowed(key)) > 1:
3193 for val in self.get_allowed(key):
3194 if val != self.switch[key]:
3195 example = (key, val)
3196 break
3197 else:
3198 continue
3199 break
3200
3201 if not example:
3202 example = ('KEY', 'VALUE')
3203
3204 if help_text:
3205 text += \
3206 ["Either type the switch number (1 to %s) to change its setting," % len(self.to_control),
3207 "Set any switch explicitly (e.g. type '%s=%s' at the prompt)" % example,
3208 "Type 'help' for the list of all valid option",
3209 "Type '0', 'auto', 'done' or just press enter when you are done."]
3210
3211
3212 if len(text) > nb_rows:
3213
3214 to_remove = [ -2,
3215 -5,
3216 -4,
3217 -3,
3218 -1,
3219 ]
3220 to_remove = to_remove[:min(len(to_remove), len(text)-nb_rows)]
3221 text = [t for i,t in enumerate(text) if i-len(text) not in to_remove]
3222
3223 self.question = "\n".join(text)
3224 return self.question
3225
3226
3227
3228
3229
3230 -class CmdFile(file):
3231 """ a class for command input file -in order to debug cmd \n problem"""
3232
3239
3241 """readline method treating correctly a line whithout \n at the end
3242 (add it)
3243 """
3244 if self.lines:
3245 line = self.lines.pop(0)
3246 else:
3247 return ''
3248
3249 if line.endswith('\n'):
3250 return line
3251 else:
3252 return line + '\n'
3253
3256
3259