1# -*- coding: utf-8 -*- 2 3# ============================================================================== 4# COPYRIGHT (C) 1991 - 2015 EDF R&D WWW.CODE-ASTER.ORG 5# THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY 6# IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY 7# THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR 8# (AT YOUR OPTION) ANY LATER VERSION. 9# 10# THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT 11# WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF 12# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU 13# GENERAL PUBLIC LICENSE FOR MORE DETAILS. 14# 15# YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE 16# ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER, 17# 1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE. 18# ============================================================================== 19 20""" 21This class define a 'light' modified parser : 22 - change exit method which exits using run.Sortie method 23 - add an action 'store_const_once' to the parser. 24""" 25 26import os 27from optparse import OptionParser, SUPPRESS_HELP, Option, OptionError, OptionValueError 28 29from asrun.common.i18n import _ 30from asrun.__pkginfo__ import version, copyright 31from asrun.mystring import convert 32from asrun.core import magic 33 34 35class AsRunOption(Option): 36 """Add 'store_const_once' action, it works like 'store_const' except that 37 a value can be stored only once, next occurences will raise an error. 38 """ 39 ACTIONS = Option.ACTIONS + ("store_const_once",) 40 STORE_ACTIONS = Option.STORE_ACTIONS + ("store_const_once",) 41 TYPED_ACTIONS = Option.TYPED_ACTIONS + ("store_const_once",) 42 43 def take_action (self, action, dest, opt, value, values, parser): 44 """Uses 'store_const_once' or standard actions. 45 """ 46 if action == "store_const_once": 47 # ----- store_const_once 48 if not hasattr(values, dest) or not getattr(values, dest): 49 setattr(values, dest, getattr(self, 'const')) 50 else: 51 raise OptionValueError("%r is invalid because '%s' previously occurs" \ 52 % (getattr(self, 'const'), dest)) 53 else: 54 # ----- standard actions 55 Option.take_action(self, action, dest, opt, value, values, parser) 56 57 def _check_const (self): 58 if self.action != "store_const" and self.action != "store_const_once" \ 59 and getattr(self, 'const') is not None: 60 raise OptionError( 61 "'const' must not be supplied for action %r" % self.action, self) 62 63 # ----- because of changes to private method _check_conf 64 CHECK_METHODS = [Option._check_action, 65 Option._check_type, 66 Option._check_choice, 67 Option._check_dest, 68 _check_const, 69 Option._check_nargs, 70 Option._check_callback] 71 72 73class AsRunParser(OptionParser): 74 """Modify lightly the standard parser. 75 """ 76 def __init__(self, run, *args, **kwargs): 77 """Initialization.""" 78 self.run = run 79 # set option_class = AsRunOption here 80 OptionParser.__init__(self, option_class=AsRunOption, *args, **kwargs) 81 82 83 def exit(self, status=0, msg=None): 84 """Call 'run.Sortie' method instead of 'sys.exit'.""" 85 if msg: 86 magic.get_stderr().write(convert(msg)) 87 self.run.PrintExitCode = False 88 self.run.Sortie(status) 89 90 91 #def get_usage(self): 92 #return to_unicode(OptionParser.get_usage(self)) 93 def print_usage(self, file=magic.get_stdout()): 94 """Print the usage message for the current program""" 95 if self.usage: 96 print(self.get_usage(), file=file) 97 98 99# values used if arguments are not parsed (when using AsRunFactory for example) 100default_options = { 101 'verbose' : False, 102 'silent' : False, 103 'num_job' : str(os.getpid()), 104} 105 106 107def define_parser(run): 108 """Build argument parser. 109 """ 110 p = AsRunParser(run, 111 usage="""%prog action [options] [arguments] 112 113 Functions : 114""", 115 version="""as_run %s 116%s""" % (version, copyright)) 117 p.add_option('-v', '--verbose', 118 action='store_true', dest='verbose', default=default_options['verbose'], 119 help=_('increase verbosity')) 120 p.add_option('--silent', 121 action='store_true', dest='silent', default=default_options['silent'], 122 help=_('run as silent as possible')) 123 p.add_option('-g', '--debug', 124 action='store_true', dest='debug', default=False, 125 help=_('print debugging information')) 126 p.add_option('--stdout', 127 action='store', dest='stdout', default=None, metavar='FILE', 128 help=_('allow to redirect messages usually written on sys.stdout')) 129 p.add_option('--stderr', 130 action='store', dest='stderr', default=None, metavar='FILE', 131 help=_('allow to redirect messages usually written on sys.stderr ' 132 '(only asrun messages)')) 133 p.add_option('--log_progress', 134 action='store', dest='log_progress', default=None, metavar='FILE', 135 help=_('redirect progress informations to a file instead of sys.stderr')) 136 p.add_option('--nodebug_stderr', 137 action='store_false', dest='debug_stderr', default=True, 138 help=_('disable printing of debugging information to stderr')) 139 p.add_option('-f', '--force', 140 action='store_true', dest='force', default=False, 141 help=_('force operations which can be cached (download, ' \ 142 'compilation...)')) 143 p.add_option('--num_job', 144 action='store', dest='num_job', default=default_options['num_job'], 145 help=SUPPRESS_HELP) 146 p.add_option('--display', 147 action='store', dest='display', default=None, 148 help=_('value of DISPLAY variable (NOTE : some functions read it from a file)')) 149 p.add_option('--rcdir', 150 action='store', dest='rcdir', default=None, metavar='DIR', 151 help=_("use resources directory $HOME/'DIR' (default is .astkrc). " 152 "Avoid absolute path because it will be passed to remote servers.")) 153 # options which override the server configuration 154 #XXX howto to merge with SSHServer and co ? 155 p.add_option('--remote_shell_protocol', 156 action='store', dest='remote_shell_protocol', default='SSH', 157 help=_('remote protocol used for shell commands')) 158 p.add_option('--remote_copy_protocol', 159 action='store', dest='remote_copy_protocol', default='SCP', 160 help=_('remote protocol used to copy files and directories')) 161 162 return p 163 164 165def get_option_value(args_list, opt, default=None, action="store"): 166 """Parse the arguments 'args_list' and return value of the option named 'opt'.""" 167 def fpass(err, *args, **kwargs): 168 """do not exit""" 169 raise 170 if not type(opt) in (list, tuple): 171 opt = [opt,] 172 kwargs = { "dest" : "var", "action" : action } 173 parser = OptionParser() 174 parser.error = fpass 175 parser.add_option(*opt, **kwargs) 176 value = None 177 if action == "store_true": 178 value = False 179 l_args = [] 180 # --help would raise print_help of the working parser 181 if "-h" not in args_list and "--help" not in args_list: 182 for arg in args_list: 183 l_args.append(arg) 184 try: 185 options, args = parser.parse_args(l_args) 186 value = options.var 187 except Exception: 188 l_args.pop(-1) 189 if value is None: 190 value = default 191 return value 192