NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

fancy_getopt.py (9222B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\distutils\fancy_getopt.py
      2 __revision__ = '$Id: fancy_getopt.py 82110 2010-06-20 13:38:51Z kristjan.jonsson $'
      3 import sys
      4 import string
      5 import re
      6 import getopt
      7 from distutils.errors import DistutilsGetoptError, DistutilsArgError
      8 longopt_pat = '[a-zA-Z](?:[a-zA-Z0-9-]*)'
      9 longopt_re = re.compile('^%s$' % longopt_pat)
     10 neg_alias_re = re.compile('^(%s)=!(%s)$' % (longopt_pat, longopt_pat))
     11 longopt_xlate = string.maketrans('-', '_')
     12 
     13 class FancyGetopt():
     14 
     15     def __init__(self, option_table = None):
     16         self.option_table = option_table
     17         self.option_index = {}
     18         if self.option_table:
     19             self._build_index()
     20         self.alias = {}
     21         self.negative_alias = {}
     22         self.short_opts = []
     23         self.long_opts = []
     24         self.short2long = {}
     25         self.attr_name = {}
     26         self.takes_arg = {}
     27         self.option_order = []
     28 
     29     def _build_index(self):
     30         self.option_index.clear()
     31         for option in self.option_table:
     32             self.option_index[option[0]] = option
     33 
     34     def set_option_table(self, option_table):
     35         self.option_table = option_table
     36         self._build_index()
     37 
     38     def add_option(self, long_option, short_option = None, help_string = None):
     39         if long_option in self.option_index:
     40             raise DistutilsGetoptError, "option conflict: already an option '%s'" % long_option
     41         else:
     42             option = (long_option, short_option, help_string)
     43             self.option_table.append(option)
     44             self.option_index[long_option] = option
     45 
     46     def has_option(self, long_option):
     47         return long_option in self.option_index
     48 
     49     def get_attr_name(self, long_option):
     50         return string.translate(long_option, longopt_xlate)
     51 
     52     def _check_alias_dict(self, aliases, what):
     53         for alias, opt in aliases.items():
     54             if alias not in self.option_index:
     55                 raise DistutilsGetoptError, "invalid %s '%s': option '%s' not defined" % (what, alias, alias)
     56             if opt not in self.option_index:
     57                 raise DistutilsGetoptError, "invalid %s '%s': aliased option '%s' not defined" % (what, alias, opt)
     58 
     59     def set_aliases(self, alias):
     60         self._check_alias_dict(alias, 'alias')
     61         self.alias = alias
     62 
     63     def set_negative_aliases(self, negative_alias):
     64         self._check_alias_dict(negative_alias, 'negative alias')
     65         self.negative_alias = negative_alias
     66 
     67     def _grok_option_table(self):
     68         self.long_opts = []
     69         self.short_opts = []
     70         self.short2long.clear()
     71         self.repeat = {}
     72         for option in self.option_table:
     73             if len(option) == 3:
     74                 long, short, help = option
     75                 repeat = 0
     76             elif len(option) == 4:
     77                 long, short, help, repeat = option
     78             else:
     79                 raise ValueError, 'invalid option tuple: %r' % (option,)
     80             if not isinstance(long, str) or len(long) < 2:
     81                 raise DistutilsGetoptError, "invalid long option '%s': must be a string of length >= 2" % long
     82             if not (short is None or isinstance(short, str) and len(short) == 1):
     83                 raise DistutilsGetoptError, "invalid short option '%s': must a single character or None" % short
     84             self.repeat[long] = repeat
     85             self.long_opts.append(long)
     86             if long[-1] == '=':
     87                 if short:
     88                     short = short + ':'
     89                 long = long[0:-1]
     90                 self.takes_arg[long] = 1
     91             else:
     92                 alias_to = self.negative_alias.get(long)
     93                 if alias_to is not None:
     94                     if self.takes_arg[alias_to]:
     95                         raise DistutilsGetoptError, "invalid negative alias '%s': aliased option '%s' takes a value" % (long, alias_to)
     96                     self.long_opts[-1] = long
     97                     self.takes_arg[long] = 0
     98                 else:
     99                     self.takes_arg[long] = 0
    100             alias_to = self.alias.get(long)
    101             if alias_to is not None:
    102                 if self.takes_arg[long] != self.takes_arg[alias_to]:
    103                     raise DistutilsGetoptError, "invalid alias '%s': inconsistent with aliased option '%s' (one of them takes a value, the other doesn't" % (long, alias_to)
    104             if not longopt_re.match(long):
    105                 raise DistutilsGetoptError, ("invalid long option name '%s' " + '(must be letters, numbers, hyphens only') % long
    106             self.attr_name[long] = self.get_attr_name(long)
    107             if short:
    108                 self.short_opts.append(short)
    109                 self.short2long[short[0]] = long
    110 
    111     def getopt(self, args = None, object = None):
    112         if args is None:
    113             args = sys.argv[1:]
    114         if object is None:
    115             object = OptionDummy()
    116             created_object = 1
    117         else:
    118             created_object = 0
    119         self._grok_option_table()
    120         short_opts = string.join(self.short_opts)
    121         try:
    122             opts, args = getopt.getopt(args, short_opts, self.long_opts)
    123         except getopt.error as msg:
    124             raise DistutilsArgError, msg
    125 
    126         for opt, val in opts:
    127             if len(opt) == 2 and opt[0] == '-':
    128                 opt = self.short2long[opt[1]]
    129             else:
    130                 opt = opt[2:]
    131             alias = self.alias.get(opt)
    132             if alias:
    133                 opt = alias
    134             if not self.takes_arg[opt]:
    135                 alias = self.negative_alias.get(opt)
    136                 if alias:
    137                     opt = alias
    138                     val = 0
    139                 else:
    140                     val = 1
    141             attr = self.attr_name[opt]
    142             if val and self.repeat.get(attr) is not None:
    143                 val = getattr(object, attr, 0) + 1
    144             setattr(object, attr, val)
    145             self.option_order.append((opt, val))
    146 
    147         if created_object:
    148             return (args, object)
    149         else:
    150             return args
    151 
    152     def get_option_order(self):
    153         if self.option_order is None:
    154             raise RuntimeError, "'getopt()' hasn't been called yet"
    155         else:
    156             return self.option_order
    157 
    158     def generate_help(self, header = None):
    159         max_opt = 0
    160         for option in self.option_table:
    161             long = option[0]
    162             short = option[1]
    163             l = len(long)
    164             if long[-1] == '=':
    165                 l = l - 1
    166             if short is not None:
    167                 l = l + 5
    168             if l > max_opt:
    169                 max_opt = l
    170 
    171         opt_width = max_opt + 2 + 2 + 2
    172         line_width = 78
    173         text_width = line_width - opt_width
    174         big_indent = ' ' * opt_width
    175         if header:
    176             lines = [header]
    177         else:
    178             lines = ['Option summary:']
    179         for option in self.option_table:
    180             long, short, help = option[:3]
    181             text = wrap_text(help, text_width)
    182             if long[-1] == '=':
    183                 long = long[0:-1]
    184             if short is None:
    185                 if text:
    186                     lines.append('  --%-*s  %s' % (max_opt, long, text[0]))
    187                 else:
    188                     lines.append('  --%-*s  ' % (max_opt, long))
    189             else:
    190                 opt_names = '%s (-%s)' % (long, short)
    191                 if text:
    192                     lines.append('  --%-*s  %s' % (max_opt, opt_names, text[0]))
    193                 else:
    194                     lines.append('  --%-*s' % opt_names)
    195             for l in text[1:]:
    196                 lines.append(big_indent + l)
    197 
    198         return lines
    199 
    200     def print_help(self, header = None, file = None):
    201         if file is None:
    202             file = sys.stdout
    203         for line in self.generate_help(header):
    204             file.write(line + '\n')
    205 
    206 
    207 def fancy_getopt(options, negative_opt, object, args):
    208     parser = FancyGetopt(options)
    209     parser.set_negative_aliases(negative_opt)
    210     return parser.getopt(args, object)
    211 
    212 
    213 WS_TRANS = string.maketrans(string.whitespace, ' ' * len(string.whitespace))
    214 
    215 def wrap_text(text, width):
    216     if text is None:
    217         return []
    218     if len(text) <= width:
    219         return [text]
    220     text = string.expandtabs(text)
    221     text = string.translate(text, WS_TRANS)
    222     chunks = re.split('( +|-+)', text)
    223     chunks = filter(None, chunks)
    224     lines = []
    225     while chunks:
    226         cur_line = []
    227         cur_len = 0
    228         while chunks:
    229             l = len(chunks[0])
    230             if cur_len + l <= width:
    231                 cur_line.append(chunks[0])
    232                 del chunks[0]
    233                 cur_len = cur_len + l
    234             else:
    235                 if cur_line and cur_line[-1][0] == ' ':
    236                     del cur_line[-1]
    237                 break
    238 
    239         if chunks:
    240             if cur_len == 0:
    241                 cur_line.append(chunks[0][0:width])
    242                 chunks[0] = chunks[0][width:]
    243             if chunks[0][0] == ' ':
    244                 del chunks[0]
    245         lines.append(string.join(cur_line, ''))
    246 
    247     return lines
    248 
    249 
    250 def translate_longopt(opt):
    251     return string.translate(opt, longopt_xlate)
    252 
    253 
    254 class OptionDummy():
    255 
    256     def __init__(self, options = []):
    257         for opt in options:
    258             setattr(self, opt, None)