Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 1 | """distutils.fancy_getopt |
| 2 | |
| 3 | Wrapper around the standard getopt module that provides the following |
| 4 | additional features: |
| 5 | * short and long options are tied together |
| 6 | * options have help strings, so fancy_getopt could potentially |
| 7 | create a complete usage summary |
| 8 | * options set attributes of a passed-in object |
| 9 | """ |
| 10 | |
| 11 | # created 1999/03/03, Greg Ward |
| 12 | |
| 13 | __rcsid__ = "$Id$" |
| 14 | |
| 15 | import string, re |
| 16 | from types import * |
| 17 | import getopt |
| 18 | from distutils.errors import * |
| 19 | |
| 20 | # Much like command_re in distutils.core, this is close to but not quite |
| 21 | # the same as a Python NAME -- except, in the spirit of most GNU |
| 22 | # utilities, we use '-' in place of '_'. (The spirit of LISP lives on!) |
| 23 | # The similarities to NAME are again not a coincidence... |
| 24 | longopt_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9-]*)$') |
| 25 | |
| 26 | # This is used to translate long options to legitimate Python identifiers |
| 27 | # (for use as attributes of some object). |
| 28 | longopt_xlate = string.maketrans ('-', '_') |
| 29 | |
| 30 | |
| 31 | def fancy_getopt (options, object, args): |
| 32 | |
| 33 | # The 'options' table is a list of 3-tuples: |
| 34 | # (long_option, short_option, help_string) |
| 35 | # if an option takes an argument, its long_option should have '=' |
| 36 | # appended; short_option should just be a single character, no ':' in |
| 37 | # any case. If a long_option doesn't have a corresponding |
| 38 | # short_option, short_option should be None. All option tuples must |
| 39 | # have long options. |
| 40 | |
| 41 | # Build the short_opts string and long_opts list, remembering how |
| 42 | # the two are tied together |
| 43 | |
| 44 | short_opts = [] # we'll join 'em when done |
| 45 | long_opts = [] |
| 46 | short2long = {} |
| 47 | attr_name = {} |
| 48 | takes_arg = {} |
| 49 | |
| 50 | for (long, short, help) in options: |
| 51 | # Type-check the option names |
| 52 | if type (long) is not StringType or len (long) < 2: |
| 53 | raise DistutilsGetoptError, \ |
| 54 | "long option must be a string of length >= 2" |
| 55 | |
| 56 | if (not ((short is None) or |
| 57 | (type (short) is StringType and len (short) == 1))): |
| 58 | raise DistutilsGetoptError, \ |
| 59 | "short option must be None or string of length 1" |
| 60 | |
| 61 | long_opts.append (long) |
| 62 | |
| 63 | if long[-1] == '=': # option takes an argument? |
| 64 | if short: short = short + ':' |
| 65 | long = long[0:-1] |
| 66 | takes_arg[long] = 1 |
| 67 | else: |
| 68 | takes_arg[long] = 0 |
| 69 | |
| 70 | # Now enforce some bondage on the long option name, so we can later |
| 71 | # translate it to an attribute name in 'object'. Have to do this a |
| 72 | # bit late to make sure we've removed any trailing '='. |
| 73 | if not longopt_re.match (long): |
| 74 | raise DistutilsGetoptError, \ |
| 75 | ("invalid long option name '%s' " + |
| 76 | "(must be letters, numbers, hyphens only") % long |
| 77 | |
| 78 | attr_name[long] = string.translate (long, longopt_xlate) |
| 79 | if short: |
| 80 | short_opts.append (short) |
| 81 | short2long[short[0]] = long |
| 82 | |
| 83 | # end loop over 'options' |
| 84 | |
| 85 | short_opts = string.join (short_opts) |
| 86 | try: |
| 87 | (opts, args) = getopt.getopt (args, short_opts, long_opts) |
| 88 | except getopt.error, msg: |
| 89 | raise DistutilsArgError, msg |
| 90 | |
| 91 | for (opt, val) in opts: |
| 92 | if len (opt) == 2 and opt[0] == '-': # it's a short option |
| 93 | opt = short2long[opt[1]] |
| 94 | |
| 95 | elif len (opt) > 2 and opt[0:2] == '--': |
| 96 | opt = opt[2:] |
| 97 | |
| 98 | else: |
| 99 | raise RuntimeError, "getopt lies! (bad option string '%s')" % \ |
| 100 | opt |
| 101 | |
| 102 | attr = attr_name[opt] |
| 103 | if takes_arg[opt]: |
| 104 | setattr (object, attr, val) |
| 105 | else: |
| 106 | if val == '': |
| 107 | setattr (object, attr, 1) |
| 108 | else: |
| 109 | raise RuntimeError, "getopt lies! (bad value '%s')" % value |
| 110 | |
| 111 | # end loop over options found in 'args' |
| 112 | |
| 113 | return args |
| 114 | |
| 115 | # end fancy_getopt() |