~maddevelopers/mg5amcnlo/WWW5_caching

« back to all changes in this revision

Viewing changes to users/mardelcourt/PROC_242195/PROC_242195/bin/internal/extended_cmd.py

  • Committer: John Doe
  • Date: 2013-03-25 20:27:02 UTC
  • Revision ID: john.doe@gmail.com-20130325202702-5sk3t1r8h33ca4p4
first clean version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
################################################################################
 
2
#
 
3
# Copyright (c) 2011 The MadGraph Development team and Contributors
 
4
#
 
5
# This file is a part of the MadGraph 5 project, an application which 
 
6
# automatically generates Feynman diagrams and matrix elements for arbitrary
 
7
# high-energy processes in the Standard Model and beyond.
 
8
#
 
9
# It is subject to the MadGraph license which should accompany this 
 
10
# distribution.
 
11
#
 
12
# For more information, please visit: http://madgraph.phys.ucl.ac.be
 
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') # for stdout
 
36
logger_stderr = logging.getLogger('fatalerror') # for stderr
 
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
pjoin = os.path.join
 
50
 
 
51
class TimeOutError(Exception):
 
52
    """Class for run-time error"""
 
53
 
 
54
def debug(debug_only=True):
 
55
 
 
56
    def deco_debug(f):
 
57
        
 
58
        if debug_only and not __debug__:
 
59
            return f
 
60
        
 
61
        def deco_f(*args, **opt):
 
62
            try:
 
63
                return f(*args, **opt)
 
64
            except Exception, error:
 
65
                logger.error(error)
 
66
                logger.error(traceback.print_exc(file=sys.stdout))
 
67
                return
 
68
        return deco_f
 
69
    return deco_debug
 
70
            
 
71
 
 
72
#===============================================================================
 
73
# CmdExtended
 
74
#===============================================================================
 
75
class BasicCmd(cmd.Cmd):
 
76
    """Simple extension for the readline"""
 
77
 
 
78
    def preloop(self):
 
79
        if readline and not 'libedit' in readline.__doc__:
 
80
            readline.set_completion_display_matches_hook(self.print_suggestions)
 
81
 
 
82
    def deal_multiple_categories(self, dico):
 
83
        """convert the multiple category in a formatted list understand by our
 
84
        specific readline parser"""
 
85
 
 
86
        if 'libedit' in readline.__doc__:
 
87
            # No parser in this case, just send all the valid options
 
88
            out = []
 
89
            for name, opt in dico.items():
 
90
                out += opt
 
91
            return out
 
92
 
 
93
        # That's the real work
 
94
        out = []
 
95
        valid=0
 
96
        # if the key starts with number order the key with that number.
 
97
        for name, opt in dico.items():
 
98
            if not opt:
 
99
                continue
 
100
            name = name.replace(' ', '_')
 
101
            valid += 1
 
102
            out.append(opt[0].rstrip()+'@@'+name+'@@')
 
103
            # Remove duplicate
 
104
            d = {}
 
105
            for x in opt:
 
106
                d[x] = 1    
 
107
            opt = list(d.keys())
 
108
            opt.sort()
 
109
            out += opt
 
110
 
 
111
            
 
112
        if valid == 1:
 
113
            out = out[1:]
 
114
        return out
 
115
    
 
116
    @debug()
 
117
    def print_suggestions(self, substitution, matches, longest_match_length) :
 
118
        """print auto-completions by category"""
 
119
        longest_match_length += len(self.completion_prefix)
 
120
        try:
 
121
            if len(matches) == 1:
 
122
                self.stdout.write(matches[0]+' ')
 
123
                return
 
124
            self.stdout.write('\n')
 
125
            l2 = [a[-2:] for a in matches]
 
126
            if '@@' in l2:
 
127
                nb_column = self.getTerminalSize()//(longest_match_length+1)
 
128
                pos=0
 
129
                for val in self.completion_matches:
 
130
                    if val.endswith('@@'):
 
131
                        category = val.rsplit('@@',2)[1]
 
132
                        category = category.replace('_',' ')
 
133
                        self.stdout.write('\n %s:\n%s\n' % (category, '=' * (len(category)+2)))
 
134
                        start = 0
 
135
                        pos = 0
 
136
                        continue
 
137
                    elif pos and pos % nb_column ==0:
 
138
                        self.stdout.write('\n')
 
139
                    self.stdout.write(self.completion_prefix + val + \
 
140
                                      ' ' * (longest_match_length +1 -len(val)))
 
141
                    pos +=1
 
142
                self.stdout.write('\n')
 
143
            else:
 
144
                # nb column
 
145
                nb_column = self.getTerminalSize()//(longest_match_length+1)
 
146
                for i,val in enumerate(matches):
 
147
                    if i and i%nb_column ==0:
 
148
                        self.stdout.write('\n')
 
149
                    self.stdout.write(self.completion_prefix + val + \
 
150
                                     ' ' * (longest_match_length +1 -len(val)))
 
151
                self.stdout.write('\n')
 
152
    
 
153
            self.stdout.write(self.prompt+readline.get_line_buffer())
 
154
            self.stdout.flush()
 
155
        except Exception, error:
 
156
            if __debug__:
 
157
                logger.error(error)
 
158
            
 
159
    def getTerminalSize(self):
 
160
        def ioctl_GWINSZ(fd):
 
161
            try:
 
162
                import fcntl, termios, struct
 
163
                cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
 
164
                                                     '1234'))
 
165
            except Exception:
 
166
                return None
 
167
            return cr
 
168
        cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
 
169
        if not cr:
 
170
            try:
 
171
                fd = os.open(os.ctermid(), os.O_RDONLY)
 
172
                cr = ioctl_GWINSZ(fd)
 
173
                os.close(fd)
 
174
            except Exception:
 
175
                pass
 
176
        if not cr:
 
177
            try:
 
178
                cr = (os.environ['LINES'], os.environ['COLUMNS'])
 
179
            except Exception:
 
180
                cr = (25, 80)
 
181
        return int(cr[1])
 
182
    
 
183
    def complete(self, text, state):
 
184
        """Return the next possible completion for 'text'.
 
185
         If a command has not been entered, then complete against command list.
 
186
         Otherwise try to call complete_<command> to get list of completions.
 
187
        """
 
188
 
 
189
        if state == 0:
 
190
            import readline
 
191
            origline = readline.get_line_buffer()
 
192
            line = origline.lstrip()
 
193
            stripped = len(origline) - len(line)
 
194
            begidx = readline.get_begidx() - stripped
 
195
            endidx = readline.get_endidx() - stripped
 
196
            
 
197
            if ';' in line:
 
198
                begin, line = line.rsplit(';',1)
 
199
                begidx = begidx - len(begin) - 1
 
200
                endidx = endidx - len(begin) - 1
 
201
                if line[:begidx] == ' ' * begidx:
 
202
                    begidx=0
 
203
 
 
204
            if begidx>0:
 
205
                cmd, args, foo = self.parseline(line)
 
206
                if cmd == '':
 
207
                    compfunc = self.completedefault
 
208
                else:
 
209
                    try:
 
210
                        compfunc = getattr(self, 'complete_' + cmd)
 
211
                    except AttributeError:
 
212
                        compfunc = self.completedefault
 
213
            else:
 
214
                compfunc = self.completenames
 
215
                
 
216
            # correct wrong splittion with '\ '
 
217
            if line and begidx > 2 and line[begidx-2:begidx] == '\ ':
 
218
                Ntext = line.split(os.path.sep)[-1]
 
219
                self.completion_prefix = Ntext.rsplit('\ ', 1)[0] + '\ '
 
220
                to_rm = len(self.completion_prefix) - 1
 
221
                Nbegidx = len(line.rsplit(os.path.sep, 1)[0]) + 1
 
222
                data = compfunc(Ntext.replace('\ ', ' '), line, Nbegidx, endidx)
 
223
                self.completion_matches = [p[to_rm:] for p in data 
 
224
                                              if len(p)>to_rm]                
 
225
            # correct wrong splitting with '-'
 
226
            elif line and line[begidx-1] == '-':
 
227
             try:    
 
228
                Ntext = line.split()[-1]
 
229
                self.completion_prefix = Ntext.rsplit('-',1)[0] +'-'
 
230
                to_rm = len(self.completion_prefix)
 
231
                Nbegidx = len(line.rsplit(None, 1)[0])
 
232
                data = compfunc(Ntext, line, Nbegidx, endidx)
 
233
                self.completion_matches = [p[to_rm:] for p in data 
 
234
                                              if len(p)>to_rm]
 
235
             except Exception, error:
 
236
                 print error
 
237
            else:
 
238
                self.completion_prefix = ''
 
239
                self.completion_matches = compfunc(text, line, begidx, endidx)
 
240
        #print self.completion_matches
 
241
 
 
242
        self.completion_matches = [ (l[-1] in [' ','@','=',os.path.sep] 
 
243
                      and l or (l+' ')) for l in self.completion_matches if l]
 
244
        
 
245
        try:
 
246
            return self.completion_matches[state]
 
247
        except IndexError, error:
 
248
            # if __debug__:
 
249
            #    logger.error('\n Completion ERROR:')
 
250
            #    logger.error( error)
 
251
            return None    
 
252
        
 
253
    @staticmethod
 
254
    def split_arg(line):
 
255
        """Split a line of arguments"""
 
256
        
 
257
        split = line.split()
 
258
        out=[]
 
259
        tmp=''
 
260
        for data in split:
 
261
            if data[-1] == '\\':
 
262
                tmp += data[:-1]+' '
 
263
            elif tmp:
 
264
                tmp += data
 
265
                tmp = os.path.expanduser(os.path.expandvars(tmp))
 
266
                out.append(tmp)
 
267
            else:
 
268
                out.append(data)
 
269
        return out
 
270
    
 
271
    @staticmethod
 
272
    def list_completion(text, list, line=''):
 
273
        """Propose completions of text in list"""
 
274
 
 
275
        if not text:
 
276
            completions = list
 
277
        else:
 
278
            completions = [ f
 
279
                            for f in list
 
280
                            if f.startswith(text)
 
281
                            ]
 
282
            
 
283
        return completions
 
284
            
 
285
 
 
286
    @staticmethod
 
287
    def path_completion(text, base_dir = None, only_dirs = False, 
 
288
                                                                 relative=True):
 
289
        """Propose completions of text to compose a valid path"""
 
290
 
 
291
        if base_dir is None:
 
292
            base_dir = os.getcwd()
 
293
        base_dir = os.path.expanduser(os.path.expandvars(base_dir))
 
294
        
 
295
        if text == '~':
 
296
            text = '~/'
 
297
        prefix, text = os.path.split(text)
 
298
        prefix = os.path.expanduser(os.path.expandvars(prefix))
 
299
        base_dir = os.path.join(base_dir, prefix)
 
300
        if prefix:
 
301
            prefix += os.path.sep
 
302
 
 
303
        if only_dirs:
 
304
            completion = [prefix + f
 
305
                          for f in os.listdir(base_dir)
 
306
                          if f.startswith(text) and \
 
307
                          os.path.isdir(os.path.join(base_dir, f)) and \
 
308
                          (not f.startswith('.') or text.startswith('.'))
 
309
                          ]
 
310
        else:
 
311
            completion = [ prefix + f
 
312
                          for f in os.listdir(base_dir)
 
313
                          if f.startswith(text) and \
 
314
                          os.path.isfile(os.path.join(base_dir, f)) and \
 
315
                          (not f.startswith('.') or text.startswith('.'))
 
316
                          ]
 
317
 
 
318
            completion = completion + \
 
319
                         [prefix + f + os.path.sep
 
320
                          for f in os.listdir(base_dir)
 
321
                          if f.startswith(text) and \
 
322
                          os.path.isdir(os.path.join(base_dir, f)) and \
 
323
                          (not f.startswith('.') or text.startswith('.'))
 
324
                          ]
 
325
 
 
326
        if relative:
 
327
            completion += [prefix + f for f in ['.'+os.path.sep, '..'+os.path.sep] if \
 
328
                       f.startswith(text) and not prefix.startswith('.')]
 
329
        
 
330
        completion = [a.replace(' ','\ ') for a in completion]
 
331
        return completion
 
332
 
 
333
 
 
334
 
 
335
 
 
336
class CheckCmd(object):
 
337
    """Extension of the cmd object for only the check command"""
 
338
 
 
339
    def check_history(self, args):
 
340
        """check the validity of line"""
 
341
        
 
342
        if len(args) > 1:
 
343
            self.help_history()
 
344
            raise self.InvalidCmd('\"history\" command takes at most one argument')
 
345
        
 
346
        if not len(args):
 
347
            return
 
348
        
 
349
        if args[0] =='.':
 
350
            if not self._export_dir:
 
351
                raise self.InvalidCmd("No default directory is defined for \'.\' option")
 
352
        elif args[0] != 'clean':
 
353
                dirpath = os.path.dirname(args[0])
 
354
                if dirpath and not os.path.exists(dirpath) or \
 
355
                       os.path.isdir(args[0]):
 
356
                    raise self.InvalidCmd("invalid path %s " % dirpath)
 
357
    
 
358
    def check_save(self, args):
 
359
        """check that the line is compatible with save options"""
 
360
        
 
361
        if len(args) > 2:
 
362
            self.help_save()
 
363
            raise self.InvalidCmd, 'too many arguments for save command.'
 
364
        
 
365
        if len(args) == 2:
 
366
            if args[0] != 'options':
 
367
                self.help_save()
 
368
                raise self.InvalidCmd, '\'%s\' is not recognized as first argument.' % \
 
369
                                                args[0]
 
370
            else:
 
371
                args.pop(0)           
 
372
 
 
373
class HelpCmd(object):
 
374
    """Extension of the cmd object for only the help command"""
 
375
 
 
376
    def help_quit(self):
 
377
        logger.info("-- terminates the application",'$MG:color:BLUE')
 
378
        logger.info("syntax: quit",'$MG:color:BLACK')
 
379
    
 
380
    help_EOF = help_quit
 
381
 
 
382
    def help_history(self):
 
383
        logger.info("-- interact with the command history.",'$MG:color:BLUE')
 
384
        logger.info("syntax: history [FILEPATH|clean|.] ",'$MG:color:BLACK')
 
385
        logger.info(" > If FILEPATH is \'.\' and \'output\' is done,")
 
386
        logger.info("   Cards/proc_card_mg5.dat will be used.")
 
387
        logger.info(" > If FILEPATH is omitted, the history will be output to stdout.")
 
388
        logger.info("   \"clean\" will remove all entries from the history.")
 
389
        
 
390
    def help_help(self):
 
391
        logger.info("-- access to the in-line help",'$MG:color:BLUE')
 
392
        logger.info("syntax: help",'$MG:color:BLACK')
 
393
 
 
394
    def help_save(self):
 
395
        """help text for save"""
 
396
        logger.info("-- save options configuration to filepath.",'$MG:color:BLUE')
 
397
        logger.info("syntax: save [options]  [FILEPATH]",'$MG:color:BLACK') 
 
398
        
 
399
    def help_display(self):
 
400
        """help for display command"""
 
401
        logger.info("-- display a the status of various internal state variables",'$MG:color:BLUE')          
 
402
        logger.info("syntax: display " + "|".join(self._display_opts),'$MG:color:BLACK')
 
403
        
 
404
class CompleteCmd(object):
 
405
    """Extension of the cmd object for only the complete command"""
 
406
 
 
407
    def complete_display(self,text, line, begidx, endidx):        
 
408
        args = self.split_arg(line[0:begidx])
 
409
        # Format
 
410
        if len(args) == 1:
 
411
            return self.list_completion(text, self._display_opts)
 
412
        
 
413
    def complete_history(self, text, line, begidx, endidx):
 
414
        "Complete the history command"
 
415
 
 
416
        args = self.split_arg(line[0:begidx])
 
417
 
 
418
        # Directory continuation
 
419
        if args[-1].endswith(os.path.sep):
 
420
            return self.path_completion(text,
 
421
                                        os.path.join('.',*[a for a in args \
 
422
                                                    if a.endswith(os.path.sep)]))
 
423
 
 
424
        if len(args) == 1:
 
425
            return self.path_completion(text)
 
426
 
 
427
    def complete_save(self, text, line, begidx, endidx):
 
428
        "Complete the save command"
 
429
 
 
430
        args = self.split_arg(line[0:begidx])
 
431
 
 
432
        # Format
 
433
        if len(args) == 1:
 
434
            return self.list_completion(text, ['options'])
 
435
 
 
436
        # Directory continuation
 
437
        if args[-1].endswith(os.path.sep):
 
438
            return self.path_completion(text,
 
439
                                        pjoin('.',*[a for a in args if a.endswith(os.path.sep)]),
 
440
                                        only_dirs = True)
 
441
 
 
442
        # Filename if directory is not given
 
443
        if len(args) == 2:
 
444
            return self.path_completion(text)
 
445
 
 
446
class Cmd(CheckCmd, HelpCmd, CompleteCmd, BasicCmd):
 
447
    """Extension of the cmd.Cmd command line.
 
448
    This extensions supports line breaking, history, comments,
 
449
    internal call to cmdline, path completion,...
 
450
    this class should be MG5 independent"""
 
451
 
 
452
    #suggested list of command
 
453
    next_possibility = {} # command : [list of suggested command]
 
454
    history_header = ""
 
455
    
 
456
    _display_opts = ['options','variable']
 
457
    
 
458
    class InvalidCmd(Exception):
 
459
        """expected error for wrong command"""
 
460
        pass    
 
461
    
 
462
    ConfigurationError = InvalidCmd
 
463
 
 
464
    debug_output = 'debug'
 
465
    error_debug = """Please report this bug to developers\n
 
466
           More information is found in '%(debug)s'.\n
 
467
           Please attach this file to your report."""
 
468
    config_debug = error_debug
 
469
           
 
470
    keyboard_stop_msg = """stopping all current operation
 
471
            in order to quit the program please enter exit"""
 
472
 
 
473
    
 
474
    def __init__(self, *arg, **opt):
 
475
        """Init history and line continuation"""
 
476
        
 
477
        self.log = True
 
478
        self.history = []
 
479
        self.save_line = '' # for line splitting
 
480
        cmd.Cmd.__init__(self, *arg, **opt)
 
481
        self.__initpos = os.path.abspath(os.getcwd())
 
482
        self.child = None # sub CMD interface call from this one
 
483
        self.mother = None #This CMD interface was called from another one
 
484
        self.inputfile = None # input file (in non interactive mode)
 
485
        self.haspiping = not sys.stdin.isatty() # check if mg5 is piped 
 
486
        self.stored_line = '' # for be able to treat answer to question in input file 
 
487
                              # answer which are not required.
 
488
        if not hasattr(self, 'helporder'):
 
489
            self.helporder = ['Documented commands']
 
490
        
 
491
        
 
492
    def precmd(self, line):
 
493
        """ A suite of additional function needed for in the cmd
 
494
        this implement history, line breaking, comment treatment,...
 
495
        """
 
496
        
 
497
        if not line:
 
498
            return line
 
499
        line = line.lstrip()
 
500
 
 
501
        # Check if we are continuing a line:
 
502
        if self.save_line:
 
503
            line = self.save_line + line 
 
504
            self.save_line = ''
 
505
        
 
506
        # Check if the line is complete
 
507
        if line.endswith('\\'):
 
508
            self.save_line = line[:-1]
 
509
            return '' # do nothing   
 
510
                
 
511
        # Remove comment
 
512
        if '#' in line:
 
513
            line = line.split('#')[0]
 
514
 
 
515
        # Deal with line splitting
 
516
        if ';' in line: 
 
517
            lines = line.split(';')
 
518
            for subline in lines:
 
519
                if not (subline.startswith("history") or subline.startswith('help') \
 
520
                        or subline.startswith('#*')): 
 
521
                    self.history.append(subline)           
 
522
                stop = self.onecmd(subline)
 
523
                stop = self.postcmd(stop, subline)
 
524
            return ''
 
525
            
 
526
        # execute the line command
 
527
        self.history.append(line) 
 
528
        return line
 
529
 
 
530
    def postcmd(self,stop, line):
 
531
        """ finishing a command
 
532
        This looks if the command add a special post part."""
 
533
 
 
534
        if line.strip():
 
535
            try:
 
536
                cmd, subline = line.split(None, 1)
 
537
            except ValueError:
 
538
                pass
 
539
            else:
 
540
                if hasattr(self,'post_%s' %cmd):
 
541
                    stop = getattr(self, 'post_%s' % cmd)(stop, subline)
 
542
        return stop
 
543
 
 
544
    def define_child_cmd_interface(self, obj_instance, interface=True):
 
545
        """Define a sub cmd_interface"""
 
546
 
 
547
        # We are in a file reading mode. So we need to redirect the cmd
 
548
        self.child = obj_instance
 
549
        self.child.mother = self
 
550
 
 
551
        if self.use_rawinput and interface:
 
552
            # We are in interactive mode -> simply call the child
 
553
            obj_instance.cmdloop()
 
554
            stop = obj_instance.postloop()
 
555
            return stop
 
556
        if self.inputfile:
 
557
            # we are in non interactive mode -> so pass the line information
 
558
            obj_instance.inputfile = self.inputfile
 
559
        
 
560
        if not interface:
 
561
            return self.child
 
562
 
 
563
    #===============================================================================
 
564
    # Ask a question with nice options handling
 
565
    #===============================================================================    
 
566
    def ask(self, question, default, choices=[], path_msg=None, 
 
567
            timeout = True, fct_timeout=None, ask_class=None, **opt):
 
568
        """ ask a question with some pre-define possibility
 
569
            path info is
 
570
        """
 
571
        if path_msg:
 
572
            path_msg = [path_msg]
 
573
        else:
 
574
            path_msg = []
 
575
            
 
576
        if timeout:
 
577
            try:
 
578
                timeout = self.options['timeout']
 
579
            except Exception:
 
580
                pass
 
581
                    
 
582
        # add choice info to the question
 
583
        if choices + path_msg:
 
584
            question += ' ['
 
585
            question += "\033[%dm%s\033[0m, " % (4, default)    
 
586
            for data in choices[:9] + path_msg:
 
587
                if default == data:
 
588
                    continue
 
589
                else:
 
590
                    question += "%s, " % data
 
591
                    
 
592
            if len(choices) > 9:
 
593
                question += '... , ' 
 
594
            question = question[:-2]+']'
 
595
        else:
 
596
            question += "[\033[%dm%s\033[0m] " % (4, default)    
 
597
        if ask_class:
 
598
            obj = ask_class  
 
599
        elif path_msg:
 
600
            obj = OneLinePathCompletion
 
601
        else:
 
602
            obj = SmartQuestion
 
603
 
 
604
        question_instance = obj(question, allow_arg=choices, default=default, 
 
605
                                                   mother_interface=self, **opt)
 
606
 
 
607
        answer = self.check_answer_in_input_file(question_instance, default, path_msg)
 
608
        if answer is not None:
 
609
            if ask_class:
 
610
                answer = question_instance.default(answer)
 
611
            return answer
 
612
        
 
613
        question = question_instance.question
 
614
        value =   Cmd.timed_input(question, default, timeout=timeout,
 
615
                                 fct=question_instance, fct_timeout=fct_timeout)
 
616
 
 
617
        if value == default and ask_class:
 
618
            value = question_instance.default(default)
 
619
        return value
 
620
 
 
621
    
 
622
    def check_answer_in_input_file(self, question_instance, default, path=False):
 
623
        """Questions can have answer in output file (or not)"""
 
624
 
 
625
        if not self.inputfile:
 
626
            return None# interactive mode
 
627
 
 
628
        line = self.get_stored_line()
 
629
        # line define if a previous answer was not answer correctly 
 
630
        if not line:
 
631
            try:
 
632
                line = self.inputfile.next()
 
633
            except StopIteration:
 
634
                if self.haspiping:
 
635
                    logger.debug('piping')
 
636
                    self.store_line(line)
 
637
                    return None # print the question and use the pipe
 
638
                logger.info(question_instance.question)
 
639
                logger.warning('The answer to the previous question is not set in your input file')
 
640
                logger.warning('Use %s value' % default)
 
641
                return str(default)
 
642
        
 
643
        line = line.replace('\n','').strip()
 
644
        if '#' in line: 
 
645
            line = line.split('#')[0]
 
646
        if not line:
 
647
            # Comment or empty line, pass to the next one
 
648
            return self.check_answer_in_input_file(question_instance, default, path)
 
649
        options = question_instance.allow_arg
 
650
        if line in options:
 
651
            return line
 
652
        elif hasattr(question_instance, 'do_%s' % line.split()[0]):
 
653
            #This is a command line, exec it and check next line
 
654
            logger.info(line)
 
655
            fct = getattr(question_instance, 'do_%s' % line.split()[0])
 
656
            fct(' '.join(line.split()[1:]))
 
657
            return self.check_answer_in_input_file(question_instance, default, path)
 
658
        elif path:
 
659
            line = os.path.expanduser(os.path.expandvars(line))
 
660
            if os.path.exists(line):
 
661
                return line
 
662
        # No valid answer provides
 
663
        if self.haspiping:
 
664
            self.store_line(line)
 
665
            return None # print the question and use the pipe
 
666
        else:
 
667
            logger.info(question_instance.question)
 
668
            logger.warning('The answer to the previous question is not set in your input file')
 
669
            logger.warning('Use %s value' % default)
 
670
            self.store_line(line)
 
671
            return str(default)
 
672
 
 
673
    def store_line(self, line):
 
674
        """store a line of the input file which should be executed by the higher mother"""
 
675
        
 
676
        if self.mother:
 
677
            self.mother.store_line(line)
 
678
        else:
 
679
            self.stored_line = line
 
680
 
 
681
    def get_stored_line(self):
 
682
        """return stored line and clean it"""
 
683
        if self.mother:
 
684
            value = self.mother.get_stored_line()
 
685
            self.mother.stored_line = None
 
686
        else:
 
687
            value = self.stored_line
 
688
            self.stored_line = None    
 
689
        return value
 
690
 
 
691
 
 
692
 
 
693
    def nice_error_handling(self, error, line):
 
694
        """ """ 
 
695
        # Make sure that we are at the initial position
 
696
        if self.child:
 
697
            return self.child.nice_error_handling(error, line)
 
698
        
 
699
        os.chdir(self.__initpos)
 
700
        # Create the debug files
 
701
        self.log = False
 
702
        if os.path.exists(self.debug_output):
 
703
            os.remove(self.debug_output)
 
704
        try:
 
705
            cmd.Cmd.onecmd(self, 'history %s' % self.debug_output.replace(' ', '\ '))
 
706
        except Exception, error:
 
707
           logger.error(error)
 
708
            
 
709
        debug_file = open(self.debug_output, 'a')
 
710
        traceback.print_exc(file=debug_file)
 
711
        # Create a nice error output
 
712
        if self.history and line == self.history[-1]:
 
713
            error_text = 'Command \"%s\" interrupted with error:\n' % line
 
714
        elif self.history:
 
715
            error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
 
716
            error_text += '\"%s\" with error:\n' % self.history[-1]
 
717
        else:
 
718
            error_text = ''
 
719
        error_text += '%s : %s\n' % (error.__class__.__name__, 
 
720
                                            str(error).replace('\n','\n\t'))
 
721
        error_text += self.error_debug % {'debug':self.debug_output}
 
722
        logger_stderr.critical(error_text)
 
723
        
 
724
                
 
725
        # Add options status to the debug file
 
726
        try:
 
727
            self.do_display('options', debug_file)
 
728
        except Exception, error:
 
729
            debug_file.write('Fail to write options with error %s' % error)
 
730
 
 
731
        debug_file.close()
 
732
        text =  open(self.debug_output).read()        
 
733
 
 
734
        #stop the execution if on a non interactive mode
 
735
        if self.use_rawinput == False:
 
736
            return True 
 
737
        return False
 
738
 
 
739
 
 
740
 
 
741
    def nice_user_error(self, error, line):
 
742
        if self.child:
 
743
            return self.child.nice_user_error(error, line)
 
744
        # Make sure that we are at the initial position
 
745
        os.chdir(self.__initpos)
 
746
        if line == self.history[-1]:
 
747
            error_text = 'Command \"%s\" interrupted with error:\n' % line
 
748
        else:
 
749
            error_text = 'Command \"%s\" interrupted in sub-command:\n' %line
 
750
            error_text += '\"%s\" with error:\n' % self.history[-1] 
 
751
        error_text += '%s : %s' % (error.__class__.__name__, 
 
752
                                                str(error).replace('\n','\n\t'))
 
753
        logger_stderr.error(error_text)
 
754
        #stop the execution if on a non interactive mode
 
755
        if self.use_rawinput == False:
 
756
            return True
 
757
        # Remove failed command from history
 
758
        self.history.pop()
 
759
        return False
 
760
    
 
761
    def nice_config_error(self, error, line):
 
762
        if self.child:
 
763
            return self.child.nice_user_error(error, line)
 
764
        # Make sure that we are at the initial position                                 
 
765
        os.chdir(self.__initpos)
 
766
        if not self.history or line == self.history[-1]:
 
767
            error_text = 'Error detected in \"%s\"\n' % line
 
768
        else:
 
769
            error_text = 'Error detected in sub-command %s\n' % self.history[-1]
 
770
        error_text += 'write debug file %s \n' % self.debug_output
 
771
        self.log = False
 
772
        cmd.Cmd.onecmd(self, 'history %s' % self.debug_output)
 
773
        debug_file = open(self.debug_output, 'a')
 
774
        traceback.print_exc(file=debug_file)
 
775
        error_text += self.config_debug % {'debug' :self.debug_output}
 
776
        error_text += '%s : %s' % (error.__class__.__name__,
 
777
                                                str(error).replace('\n','\n\t'))
 
778
        logger_stderr.error(error_text)
 
779
        
 
780
        # Add options status to the debug file
 
781
        try:
 
782
            self.do_display('options', debug_file)
 
783
        except Exception, error:
 
784
            debug_file.write('Fail to write options with error %s' % error)
 
785
        #stop the execution if on a non interactive mode                                
 
786
        if self.use_rawinput == False:
 
787
            return True
 
788
        # Remove failed command from history                                            
 
789
        if self.history:
 
790
            self.history.pop()
 
791
        return False
 
792
    
 
793
    def onecmd_orig(self, line, **opt):
 
794
        """Interpret the argument as though it had been typed in response
 
795
        to the prompt.
 
796
 
 
797
        The return value is a flag indicating whether interpretation of
 
798
        commands by the interpreter should stop.
 
799
        
 
800
        This allow to pass extra argument for internal call.
 
801
        """
 
802
        if '~/' in line and os.environ.has_key('HOME'):
 
803
            line = line.replace('~/', '%s/' % os.environ['HOME'])
 
804
        line = os.path.expandvars(line)
 
805
        cmd, arg, line = self.parseline(line)
 
806
        if not line:
 
807
            return self.emptyline()
 
808
        if cmd is None:
 
809
            return self.default(line)
 
810
        self.lastcmd = line
 
811
        if cmd == '':
 
812
            return self.default(line)
 
813
        else:
 
814
            try:
 
815
                func = getattr(self, 'do_' + cmd)
 
816
            except AttributeError:
 
817
                return self.default(line)
 
818
            return func(arg, **opt)
 
819
 
 
820
 
 
821
    def onecmd(self, line, **opt):
 
822
        """catch all error and stop properly command accordingly"""
 
823
        
 
824
        try:
 
825
            return self.onecmd_orig(line, **opt)
 
826
        except self.InvalidCmd as error:            
 
827
            if __debug__:
 
828
                self.nice_error_handling(error, line)
 
829
                self.history.pop()
 
830
            else:
 
831
                self.nice_user_error(error, line)
 
832
        except self.ConfigurationError as error:
 
833
            self.nice_config_error(error, line)
 
834
        except Exception as error:
 
835
            self.nice_error_handling(error, line)
 
836
            if self.mother:
 
837
                self.do_quit('')
 
838
        except KeyboardInterrupt as error:
 
839
            self.stop_on_keyboard_stop()
 
840
            if __debug__:
 
841
                self.nice_config_error(error, line)
 
842
            logger.error(self.keyboard_stop_msg)
 
843
    
 
844
    def stop_on_keyboard_stop(self):
 
845
        """action to perform to close nicely on a keyboard interupt"""
 
846
        pass # dummy function
 
847
            
 
848
    def exec_cmd(self, line, errorhandling=False, printcmd=True, 
 
849
                                     precmd=False, postcmd=True, **opt):
 
850
        """for third party call, call the line with pre and postfix treatment
 
851
        without global error handling """
 
852
 
 
853
        if printcmd:
 
854
            logger.info(line)
 
855
        if self.child:
 
856
            current_interface = self.child
 
857
        else:
 
858
            current_interface = self
 
859
        
 
860
        if precmd:
 
861
            line = current_interface.precmd(line)
 
862
        if errorhandling:
 
863
            stop = current_interface.onecmd(line, **opt)
 
864
        else:
 
865
            stop = Cmd.onecmd_orig(current_interface, line, **opt)
 
866
        if postcmd:
 
867
            stop = current_interface.postcmd(stop, line)
 
868
        return stop      
 
869
 
 
870
    def run_cmd(self, line):
 
871
        """for third party call, call the line with pre and postfix treatment
 
872
        with global error handling"""
 
873
        
 
874
        return self.exec_cmd(line, errorhandling=True, precmd=True)
 
875
    
 
876
    def emptyline(self):
 
877
        """If empty line, do nothing. Default is repeat previous command."""
 
878
        pass
 
879
    
 
880
    def default(self, line):
 
881
        """Default action if line is not recognized"""
 
882
 
 
883
        # Faulty command
 
884
        logger.warning("Command \"%s\" not recognized, please try again" % \
 
885
                                                                line.split()[0])
 
886
        if line.strip() in ['q', '.q', 'stop']:
 
887
            logger.info("If you want to quit mg5 please type \"exit\".")
 
888
 
 
889
        if self.history and self.history[-1] == line:        
 
890
            self.history.pop()
 
891
        
 
892
 
 
893
 
 
894
 
 
895
     
 
896
    # Write the list of command line use in this session
 
897
    def do_history(self, line):
 
898
        """write in a file the suite of command that was used"""
 
899
        
 
900
        args = self.split_arg(line)
 
901
        # Check arguments validity
 
902
        self.check_history(args)
 
903
 
 
904
        if len(args) == 0:
 
905
            logger.info('\n'.join(self.history))
 
906
            return
 
907
        elif args[0] == 'clean':
 
908
            self.history = []
 
909
            logger.info('History is cleaned')
 
910
            return
 
911
        elif args[0] == '.':
 
912
            output_file = os.path.join(self._export_dir, 'Cards', \
 
913
                                       'proc_card_mg5.dat')
 
914
            output_file = open(output_file, 'w')
 
915
        else:
 
916
            output_file = open(args[0], 'w')
 
917
            
 
918
        # Create the command file
 
919
        text = self.get_history_header()
 
920
        text += ('\n'.join(self.history) + '\n') 
 
921
        
 
922
        #write this information in a file
 
923
        output_file.write(text)
 
924
        output_file.close()
 
925
 
 
926
        if self.log:
 
927
            logger.info("History written to " + output_file.name)
 
928
 
 
929
    def avoid_history_duplicate(self, line, no_break=[]):
 
930
        """remove all line in history (but the last) starting with line.
 
931
        up to the point when a line didn't start by something in no_break.
 
932
        (reading in reverse order)"""
 
933
        
 
934
        new_history = []
 
935
        for i in range(1, len(self.history)+1):
 
936
            cur_line = self.history[-i]
 
937
            if i == 1:
 
938
                new_history.append(cur_line)
 
939
            elif not any((cur_line.startswith(text) for text in no_break)):
 
940
                to_add = self.history[:-i+1]
 
941
                to_add.reverse()
 
942
                new_history += to_add
 
943
                break
 
944
            elif cur_line.startswith(line):
 
945
                continue
 
946
            else:
 
947
                new_history.append(cur_line)
 
948
            
 
949
        new_history.reverse()
 
950
        self.history[:] = new_history
 
951
        
 
952
                        
 
953
    def import_command_file(self, filepath):
 
954
        # remove this call from history
 
955
        if self.history:
 
956
            self.history.pop()
 
957
        
 
958
        # Read the lines of the file and execute them
 
959
        if isinstance(filepath, str):
 
960
            commandline = open(filepath).readlines()
 
961
        else:
 
962
            commandline = filepath
 
963
        oldinputfile = self.inputfile
 
964
        oldraw = self.use_rawinput
 
965
        self.inputfile = (l for l in commandline) # make a generator
 
966
        self.use_rawinput = False
 
967
        # Note using "for line in open(filepath)" is not safe since the file
 
968
        # filepath can be overwritten during the run (leading to weird results)
 
969
        # Note also that we need a generator and not a list.
 
970
        for line in self.inputfile:
 
971
            #remove pointless spaces and \n
 
972
            line = line.replace('\n', '').strip()
 
973
            # execute the line
 
974
            if line:
 
975
                self.exec_cmd(line, precmd=True)
 
976
            stored = self.get_stored_line()
 
977
            while stored:
 
978
                line = stored
 
979
                self.exec_cmd(line, precmd=True)
 
980
                stored = self.get_stored_line()
 
981
 
 
982
        # If a child was open close it
 
983
        if self.child:
 
984
            self.child.exec_cmd('quit')        
 
985
        self.inputfile = oldinputfile
 
986
        self.use_rawinput = oldraw       
 
987
        return
 
988
    
 
989
    def get_history_header(self):
 
990
        """Default history header"""
 
991
        
 
992
        return self.history_header
 
993
    
 
994
    def postloop(self):
 
995
        """ """
 
996
        
 
997
        args = self.split_arg(self.lastcmd)
 
998
        if args and args[0] in ['quit','exit']:
 
999
            if 'all' in args:
 
1000
                return True
 
1001
            if len(args) >1 and args[1].isdigit():
 
1002
                if args[1] not in  ['0', '1']:
 
1003
                    return True
 
1004
        return False
 
1005
        
 
1006
    #===============================================================================
 
1007
    # Ask a question with a maximum amount of time to answer
 
1008
    #===============================================================================    
 
1009
    @staticmethod
 
1010
    def timed_input(question, default, timeout=None, noerror=True, fct=None,
 
1011
                    fct_timeout=None):
 
1012
        """ a question with a maximal time to answer take default otherwise"""
 
1013
    
 
1014
        def handle_alarm(signum, frame): 
 
1015
            raise TimeOutError
 
1016
        
 
1017
        signal.signal(signal.SIGALRM, handle_alarm)
 
1018
    
 
1019
        if fct is None:
 
1020
            fct = raw_input
 
1021
        
 
1022
        if timeout:
 
1023
            signal.alarm(timeout)
 
1024
            question += '[%ss to answer] ' % (timeout)    
 
1025
        try:
 
1026
            result = fct(question)
 
1027
        except TimeOutError:
 
1028
            if noerror:
 
1029
                logger.info('\nuse %s' % default)
 
1030
                if fct_timeout:
 
1031
                    fct_timeout(True)
 
1032
                return default
 
1033
            else:
 
1034
                signal.alarm(0)
 
1035
                raise
 
1036
        finally:
 
1037
            signal.alarm(0)
 
1038
        if fct_timeout:
 
1039
            fct_timeout(False)
 
1040
        return result
 
1041
 
 
1042
 
 
1043
 
 
1044
        
 
1045
 
 
1046
 
 
1047
    # Quit
 
1048
    def do_quit(self, line):
 
1049
        """Not in help: exit the mainloop() """
 
1050
        
 
1051
        if self.child:
 
1052
            self.child.exec_cmd('quit ' + line, printcmd=False)
 
1053
            return
 
1054
        elif self.mother:
 
1055
            self.mother.child = None
 
1056
            if line == 'all':
 
1057
                pass
 
1058
            elif line:
 
1059
                level = int(line) - 1
 
1060
                if level:
 
1061
                    self.mother.lastcmd = 'quit %s' % level
 
1062
        logger.info(' ')
 
1063
        return True
 
1064
 
 
1065
    # Aliases
 
1066
    do_EOF = do_quit
 
1067
    do_exit = do_quit
 
1068
 
 
1069
    def do_help(self, line):
 
1070
        """Not in help: propose some usefull possible action """
 
1071
                
 
1072
        # if they are an argument use the default help
 
1073
        if line:
 
1074
            return cmd.Cmd.do_help(self, line)
 
1075
        
 
1076
        
 
1077
        names = self.get_names()
 
1078
        cmds = {}
 
1079
        names.sort()
 
1080
        # There can be duplicates if routines overridden
 
1081
        prevname = ''
 
1082
        for name in names:
 
1083
            if name[:3] == 'do_':
 
1084
                if name == prevname:
 
1085
                    continue
 
1086
                prevname = name
 
1087
                cmdname=name[3:]
 
1088
                try:
 
1089
                    doc = getattr(self.cmd, name).__doc__
 
1090
                except Exception:
 
1091
                    doc = None
 
1092
                if not doc:
 
1093
                    doc = getattr(self, name).__doc__
 
1094
                if not doc:
 
1095
                    tag = "Documented commands"
 
1096
                elif ':' in doc:
 
1097
                    tag = doc.split(':',1)[0]
 
1098
                else:
 
1099
                    tag = "Documented commands"
 
1100
                if tag in cmds:
 
1101
                    cmds[tag].append(cmdname)
 
1102
                else:
 
1103
                    cmds[tag] = [cmdname] 
 
1104
                    
 
1105
        self.stdout.write("%s\n"%str(self.doc_leader))
 
1106
        for tag in self.helporder:
 
1107
            if tag not in cmds:
 
1108
                continue
 
1109
            header = "%s (type help <topic>):" % tag
 
1110
            self.print_topics(header, cmds[tag],   15,80)
 
1111
        for name, item in cmds.items():
 
1112
            if name in self.helporder:
 
1113
                continue
 
1114
            if name == "Not in help":
 
1115
                continue
 
1116
            header = "%s (type help <topic>):" % name
 
1117
            self.print_topics(header, item,   15,80)
 
1118
 
 
1119
 
 
1120
        ## Add contextual help
 
1121
        if len(self.history) == 0:
 
1122
            last_action_2 = last_action = 'start'
 
1123
        else:
 
1124
            last_action_2 = last_action = 'none'
 
1125
        
 
1126
        pos = 0
 
1127
        authorize = self.next_possibility.keys() 
 
1128
        while last_action_2  not in authorize and last_action not in authorize:
 
1129
            pos += 1
 
1130
            if pos > len(self.history):
 
1131
                last_action_2 = last_action = 'start'
 
1132
                break
 
1133
            
 
1134
            args = self.history[-1 * pos].split()
 
1135
            last_action = args[0]
 
1136
            if len(args)>1: 
 
1137
                last_action_2 = '%s %s' % (last_action, args[1])
 
1138
            else: 
 
1139
                last_action_2 = 'none'
 
1140
        
 
1141
        logger.info('Contextual Help')
 
1142
        logger.info('===============')
 
1143
        if last_action_2 in authorize:
 
1144
            options = self.next_possibility[last_action_2]
 
1145
        elif last_action in authorize:
 
1146
            options = self.next_possibility[last_action]
 
1147
        else:
 
1148
            return
 
1149
        text = 'The following command(s) may be useful in order to continue.\n'
 
1150
        for option in options:
 
1151
            text+='\t %s \n' % option      
 
1152
        logger.info(text)
 
1153
 
 
1154
    def do_display(self, line, output=sys.stdout):
 
1155
        """Advanced commands: basic display"""
 
1156
        
 
1157
        args = self.split_arg(line)
 
1158
        #check the validity of the arguments
 
1159
        
 
1160
        if len(args) == 0:
 
1161
            self.help_display()
 
1162
            raise self.InvalidCmd, 'display require at least one argument'
 
1163
        
 
1164
        if args[0] == "options":
 
1165
            outstr = "Value of current Options:\n" 
 
1166
            for key, value in self.options.items():
 
1167
                outstr += '%25s \t:\t%s\n' %(key,value)
 
1168
 
 
1169
            
 
1170
        elif args[0] == "variable":
 
1171
            outstr = "Value of Internal Variable:\n"
 
1172
            try:
 
1173
                var = eval(args[1])
 
1174
            except Exception:
 
1175
                outstr += 'GLOBAL:\nVariable %s is not a global variable\n' % args[1]
 
1176
            else:
 
1177
                outstr += 'GLOBAL:\n' 
 
1178
                outstr += misc.nice_representation(var, nb_space=4)
 
1179
               
 
1180
            try:
 
1181
                var = eval('self.%s' % args[1])
 
1182
            except Exception:
 
1183
                outstr += 'LOCAL:\nVariable %s is not a local variable\n' % args[1]
 
1184
            else:
 
1185
                outstr += 'LOCAL:\n'
 
1186
                outstr += misc.nice_representation(var, nb_space=4)                
 
1187
            
 
1188
            if output == sys.stdout:
 
1189
                pydoc.pager(outstr)
 
1190
        output.write(outstr)
 
1191
    
 
1192
    
 
1193
    def do_save(self, line, check=True):
 
1194
        """Save the configuration file"""
 
1195
        
 
1196
        args = self.split_arg(line)
 
1197
        # Check argument validity
 
1198
        if check:
 
1199
            Cmd.check_save(self, args)
 
1200
            
 
1201
        # find base file for the configuration
 
1202
        if'HOME' in os.environ and os.environ['HOME']  and \
 
1203
        os.path.exists(pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')):
 
1204
            base = pjoin(os.environ['HOME'], '.mg5', 'mg5_configuration.txt')
 
1205
            if hasattr(self, 'me_dir'):
 
1206
                basedir = self.me_dir
 
1207
            elif not MADEVENT:
 
1208
                basedir = MG5DIR
 
1209
            else:
 
1210
                basedir = os.getcwd()
 
1211
        elif MADEVENT:
 
1212
            # launch via ./bin/madevent
 
1213
            base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
 
1214
            basedir = self.me_dir
 
1215
        else:
 
1216
            if hasattr(self, 'me_dir'):
 
1217
                base = pjoin(self.me_dir, 'Cards', 'me5_configuration.txt')
 
1218
                if len(args) == 0 and os.path.exists(base):
 
1219
                    self.write_configuration(base, base, self.me_dir)
 
1220
            base = pjoin(MG5DIR, 'input', 'mg5_configuration.txt')
 
1221
            basedir = MG5DIR
 
1222
            
 
1223
        if len(args) == 0:
 
1224
            args.append(base)
 
1225
        self.write_configuration(args[0], base, basedir, self.options)
 
1226
        
 
1227
    def write_configuration(self, filepath, basefile, basedir, to_keep):
 
1228
        """Write the configuration file"""
 
1229
        # We use the default configuration file as a template.
 
1230
        # to ensure that all configuration information are written we 
 
1231
        # keep track of all key that we need to write.
 
1232
 
 
1233
        logger.info('save configuration file to %s' % filepath)
 
1234
        to_write = to_keep.keys()
 
1235
        text = ""
 
1236
        # Use local configuration => Need to update the path
 
1237
        for line in file(basefile):
 
1238
            if '=' in line:
 
1239
                data, value = line.split('=',1)
 
1240
            else: 
 
1241
                text += line
 
1242
                continue
 
1243
            data = data.strip()
 
1244
            if data.startswith('#'):
 
1245
                key = data[1:].strip()
 
1246
            else: 
 
1247
                key = data 
 
1248
            if '#' in value:
 
1249
                value, comment = value.split('#',1)
 
1250
            else:
 
1251
                comment = ''    
 
1252
            if key in to_keep:
 
1253
                value = str(to_keep[key])
 
1254
            else:
 
1255
                text += line
 
1256
                continue
 
1257
            try:
 
1258
                to_write.remove(key)
 
1259
            except Exception:
 
1260
                pass
 
1261
            if '_path' in key:       
 
1262
                # special case need to update path
 
1263
                # check if absolute path
 
1264
                if not os.path.isabs(value):
 
1265
                    value = os.path.realpath(os.path.join(basedir, value))
 
1266
            text += '%s = %s # %s \n' % (key, value, comment)
 
1267
        for key in to_write:
 
1268
            if key in to_keep:
 
1269
                text += '%s = %s \n' % (key, to_keep[key])
 
1270
        
 
1271
        if not MADEVENT:
 
1272
            text += """\n# MG5 MAIN DIRECTORY\n"""
 
1273
            text += "mg5_path = %s\n" % MG5DIR         
 
1274
        
 
1275
        writer = open(filepath,'w')
 
1276
        writer.write(text)
 
1277
        writer.close()
 
1278
                       
 
1279
 
 
1280
    
 
1281
 
 
1282
class CmdShell(Cmd):
 
1283
    """CMD command with shell activate"""
 
1284
 
 
1285
    # Access to shell
 
1286
    def do_shell(self, line):
 
1287
        "Run a shell command"
 
1288
 
 
1289
        if line.strip() is '':
 
1290
            self.help_shell()
 
1291
        else:
 
1292
            logging.info("running shell command: " + line)
 
1293
            subprocess.call(line, shell=True)
 
1294
    
 
1295
    def complete_shell(self, text, line, begidx, endidx):
 
1296
        """ add path for shell """
 
1297
 
 
1298
        # Filename if directory is given
 
1299
        #
 
1300
        if len(self.split_arg(line[0:begidx])) > 1 and line[begidx - 1] == os.path.sep:
 
1301
            if not text:
 
1302
                text = ''
 
1303
            output = self.path_completion(text,
 
1304
                                        base_dir=\
 
1305
                                          self.split_arg(line[0:begidx])[-1])
 
1306
        else:
 
1307
            output = self.path_completion(text)
 
1308
        return output
 
1309
 
 
1310
    def help_shell(self):
 
1311
        """help for the shell"""
 
1312
        logger.info("-- run the shell command CMD and catch output",'$MG:color:BLUE')        
 
1313
        logger.info("syntax: shell CMD (or ! CMD)",'$MG:color:BLACK')
 
1314
 
 
1315
 
 
1316
 
 
1317
 
 
1318
#===============================================================================
 
1319
# Question with auto-completion
 
1320
#===============================================================================
 
1321
class SmartQuestion(BasicCmd):
 
1322
    """ a class for answering a question with the path autocompletion"""
 
1323
 
 
1324
    def preloop(self):
 
1325
        """Initializing before starting the main loop"""
 
1326
        self.prompt = '>'
 
1327
        self.value = None
 
1328
        BasicCmd.preloop(self)
 
1329
        
 
1330
 
 
1331
    def __init__(self, question, allow_arg=[], default=None, 
 
1332
                                            mother_interface=None, *arg, **opt):
 
1333
        self.question = question
 
1334
        self.wrong_answer = 0 # forbids infinite loop
 
1335
        self.allow_arg = [str(a) for a in allow_arg]
 
1336
        self.history_header = ''
 
1337
        self.default_value = str(default)
 
1338
        self.mother_interface = mother_interface
 
1339
        cmd.Cmd.__init__(self, *arg, **opt)
 
1340
 
 
1341
    def __call__(self, question, reprint_opt=True, **opts):
 
1342
        
 
1343
        self.question = question
 
1344
        for key,value in opts:
 
1345
            setattr(self, key, value)
 
1346
        if reprint_opt:
 
1347
            print question
 
1348
        return self.cmdloop()
 
1349
        
 
1350
 
 
1351
    def completenames(self, text, line, *ignored):
 
1352
        prev_timer = signal.alarm(0) # avoid timer if any
 
1353
        if prev_timer:
 
1354
            nb_back = len(line)
 
1355
            self.stdout.write('\b'*nb_back + '[timer stopped]\n')
 
1356
            self.stdout.write(line)
 
1357
            self.stdout.flush()
 
1358
        try:
 
1359
            out = {}
 
1360
            out[' Options'] = Cmd.list_completion(text, self.allow_arg)
 
1361
            out[' Recognized command'] = BasicCmd.completenames(self, text)
 
1362
            
 
1363
            return self.deal_multiple_categories(out)
 
1364
        except Exception, error:
 
1365
            print error
 
1366
            
 
1367
            
 
1368
    def reask(self, reprint_opt=True):
 
1369
        pat = re.compile('\[(\d*)s to answer\]')
 
1370
        prev_timer = signal.alarm(0) # avoid timer if any
 
1371
        
 
1372
        if prev_timer:     
 
1373
            if pat.search(self.question):
 
1374
                timeout = int(pat.search(self.question).groups()[0])
 
1375
            else:
 
1376
                timeout=20
 
1377
            print
 
1378
            signal.alarm(timeout)
 
1379
        if reprint_opt:
 
1380
            if not prev_timer:
 
1381
                self.question = pat.sub('',self.question)
 
1382
            print self.question
 
1383
        return False
 
1384
        
 
1385
    def default(self, line):
 
1386
        """Default action if line is not recognized"""
 
1387
 
 
1388
        if line.strip() == '' and self.default_value is not None:
 
1389
            self.value = self.default_value
 
1390
        else:
 
1391
            self.value = line
 
1392
 
 
1393
    def emptyline(self):
 
1394
        """If empty line, return default"""
 
1395
        
 
1396
        if self.default_value is not None:
 
1397
            self.value = self.default_value
 
1398
 
 
1399
 
 
1400
    def postcmd(self, stop, line):
 
1401
        
 
1402
        try:    
 
1403
            if self.value in self.allow_arg:
 
1404
                return True
 
1405
            elif str(self.value) == 'EOF':
 
1406
                self.value = self.default_value
 
1407
                return True
 
1408
            elif line and hasattr(self, 'do_%s' % line.split()[0]):
 
1409
                return self.reask()
 
1410
            elif self.value == 'repeat':
 
1411
                return self.reask()
 
1412
            elif len(self.allow_arg)==0:
 
1413
                return True
 
1414
            else: 
 
1415
                raise Exception
 
1416
        except Exception,error:
 
1417
            if self.wrong_answer < 100:
 
1418
                self.wrong_answer += 1
 
1419
                logger.warning("""%s not valid argument. Valid argument are in (%s).""" \
 
1420
                          % (self.value,','.join(self.allow_arg)))
 
1421
                logger.warning('please retry')
 
1422
                return False
 
1423
            else:
 
1424
                self.value = self.default_value
 
1425
                return True
 
1426
                
 
1427
    def cmdloop(self, intro=None):
 
1428
        cmd.Cmd.cmdloop(self, intro)
 
1429
        return self.value
 
1430
    
 
1431
# a function helper
 
1432
def smart_input(input_text, allow_arg=[], default=None):
 
1433
    print input_text
 
1434
    obj = SmartQuestion(allow_arg=allow_arg, default=default)
 
1435
    return obj.cmdloop()
 
1436
 
 
1437
#===============================================================================
 
1438
# Question in order to return a path with auto-completion
 
1439
#===============================================================================
 
1440
class OneLinePathCompletion(SmartQuestion):
 
1441
    """ a class for answering a question with the path autocompletion"""
 
1442
    
 
1443
 
 
1444
    def completenames(self, text, line, begidx, endidx):
 
1445
        prev_timer = signal.alarm(0) # avoid timer if any
 
1446
        if prev_timer:
 
1447
            nb_back = len(line)
 
1448
            self.stdout.write('\b'*nb_back + '[timer stopped]\n')
 
1449
            self.stdout.write(line)
 
1450
            self.stdout.flush()
 
1451
        try:
 
1452
            out = {}
 
1453
            out[' Options'] = Cmd.list_completion(text, self.allow_arg)
 
1454
            out[' Path from ./'] = Cmd.path_completion(text, only_dirs = False)
 
1455
            out[' Recognized command'] = BasicCmd.completenames(self, text)
 
1456
            
 
1457
            return self.deal_multiple_categories(out)
 
1458
        except Exception, error:
 
1459
            print error
 
1460
            
 
1461
    def precmd(self, *args):
 
1462
        """ """
 
1463
        
 
1464
        signal.alarm(0)
 
1465
        return SmartQuestion.precmd(self, *args)
 
1466
        
 
1467
    def completedefault(self,text, line, begidx, endidx):
 
1468
        prev_timer = signal.alarm(0) # avoid timer if any
 
1469
        if prev_timer:
 
1470
            nb_back = len(line)
 
1471
            self.stdout.write('\b'*nb_back + '[timer stopped]\n')
 
1472
            self.stdout.write(line)
 
1473
            self.stdout.flush()
 
1474
        try:
 
1475
            args = Cmd.split_arg(line[0:begidx])
 
1476
        except Exception, error:
 
1477
            print error
 
1478
 
 
1479
        # Directory continuation                 
 
1480
        if args[-1].endswith(os.path.sep):
 
1481
 
 
1482
            return Cmd.path_completion(text,
 
1483
                                        os.path.join('.',*[a for a in args \
 
1484
                                               if a.endswith(os.path.sep)]))
 
1485
        self.completenames(line+text)
 
1486
 
 
1487
 
 
1488
    def postcmd(self, stop, line):
 
1489
        try:    
 
1490
            if self.value in self.allow_arg: 
 
1491
                return True
 
1492
            elif self.value and os.path.isfile(self.value):
 
1493
                return os.path.relpath(self.value)
 
1494
            elif self.value and str(self.value) == 'EOF':
 
1495
                self.value = self.default_value
 
1496
                return True
 
1497
            elif line and hasattr(self, 'do_%s' % line.split()[0]):
 
1498
                # go to retry
 
1499
                reprint_opt = True 
 
1500
            elif self.value == 'repeat':
 
1501
                reprint_opt = True         
 
1502
            else:
 
1503
                raise Exception
 
1504
        except Exception, error:            
 
1505
            print """not valid argument. Valid argument are file path or value in (%s).""" \
 
1506
                          % ','.join(self.allow_arg)
 
1507
            print 'please retry'
 
1508
            reprint_opt = False 
 
1509
            
 
1510
        return self.reask(reprint_opt)
 
1511
 
 
1512
            
 
1513
# a function helper
 
1514
def raw_path_input(input_text, allow_arg=[], default=None):
 
1515
    print input_text
 
1516
    obj = OneLinePathCompletion(allow_arg=allow_arg, default=default )
 
1517
    return obj.cmdloop()
 
1518
 
 
1519
#===============================================================================
 
1520
 
1521
#===============================================================================
 
1522
class CmdFile(file):
 
1523
    """ a class for command input file -in order to debug cmd \n problem"""
 
1524
    
 
1525
    def __init__(self, name, opt='rU'):
 
1526
        
 
1527
        file.__init__(self, name, opt)
 
1528
        self.text = file.read(self)
 
1529
        self.close()
 
1530
        self.lines = self.text.split('\n')
 
1531
    
 
1532
    def readline(self, *arg, **opt):
 
1533
        """readline method treating correctly a line whithout \n at the end
 
1534
           (add it)
 
1535
        """
 
1536
        if self.lines:
 
1537
            line = self.lines.pop(0)
 
1538
        else:
 
1539
            return ''
 
1540
        
 
1541
        if line.endswith('\n'):
 
1542
            return line
 
1543
        else:
 
1544
            return line + '\n'
 
1545
    
 
1546
    def __next__(self):
 
1547
        return self.lines.__next__()    
 
1548
 
 
1549
    def __iter__(self):
 
1550
        return self.lines.__iter__()
 
1551
 
 
1552
 
 
1553
 
 
1554