| """distutils.fancy_getopt |
| |
| Wrapper around the standard getopt module that provides the following |
| additional features: |
| * short and long options are tied together |
| * options have help strings, so fancy_getopt could potentially |
| create a complete usage summary |
| * options set attributes of a passed-in object |
| """ |
| |
| # created 1999/03/03, Greg Ward |
| |
| __rcsid__ = "$Id$" |
| |
| import string, re |
| from types import * |
| import getopt |
| from distutils.errors import * |
| |
| # Much like command_re in distutils.core, this is close to but not quite |
| # the same as a Python NAME -- except, in the spirit of most GNU |
| # utilities, we use '-' in place of '_'. (The spirit of LISP lives on!) |
| # The similarities to NAME are again not a coincidence... |
| longopt_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9-]*)$') |
| |
| # This is used to translate long options to legitimate Python identifiers |
| # (for use as attributes of some object). |
| longopt_xlate = string.maketrans ('-', '_') |
| |
| |
| def fancy_getopt (options, object, args): |
| |
| # The 'options' table is a list of 3-tuples: |
| # (long_option, short_option, help_string) |
| # if an option takes an argument, its long_option should have '=' |
| # appended; short_option should just be a single character, no ':' in |
| # any case. If a long_option doesn't have a corresponding |
| # short_option, short_option should be None. All option tuples must |
| # have long options. |
| |
| # Build the short_opts string and long_opts list, remembering how |
| # the two are tied together |
| |
| short_opts = [] # we'll join 'em when done |
| long_opts = [] |
| short2long = {} |
| attr_name = {} |
| takes_arg = {} |
| |
| for (long, short, help) in options: |
| # Type-check the option names |
| if type (long) is not StringType or len (long) < 2: |
| raise DistutilsGetoptError, \ |
| "long option must be a string of length >= 2" |
| |
| if (not ((short is None) or |
| (type (short) is StringType and len (short) == 1))): |
| raise DistutilsGetoptError, \ |
| "short option must be None or string of length 1" |
| |
| long_opts.append (long) |
| |
| if long[-1] == '=': # option takes an argument? |
| if short: short = short + ':' |
| long = long[0:-1] |
| takes_arg[long] = 1 |
| else: |
| takes_arg[long] = 0 |
| |
| # Now enforce some bondage on the long option name, so we can later |
| # translate it to an attribute name in 'object'. Have to do this a |
| # bit late to make sure we've removed any trailing '='. |
| if not longopt_re.match (long): |
| raise DistutilsGetoptError, \ |
| ("invalid long option name '%s' " + |
| "(must be letters, numbers, hyphens only") % long |
| |
| attr_name[long] = string.translate (long, longopt_xlate) |
| if short: |
| short_opts.append (short) |
| short2long[short[0]] = long |
| |
| # end loop over 'options' |
| |
| short_opts = string.join (short_opts) |
| try: |
| (opts, args) = getopt.getopt (args, short_opts, long_opts) |
| except getopt.error, msg: |
| raise DistutilsArgError, msg |
| |
| for (opt, val) in opts: |
| if len (opt) == 2 and opt[0] == '-': # it's a short option |
| opt = short2long[opt[1]] |
| |
| elif len (opt) > 2 and opt[0:2] == '--': |
| opt = opt[2:] |
| |
| else: |
| raise RuntimeError, "getopt lies! (bad option string '%s')" % \ |
| opt |
| |
| attr = attr_name[opt] |
| if takes_arg[opt]: |
| setattr (object, attr, val) |
| else: |
| if val == '': |
| setattr (object, attr, 1) |
| else: |
| raise RuntimeError, "getopt lies! (bad value '%s')" % value |
| |
| # end loop over options found in 'args' |
| |
| return args |
| |
| # end fancy_getopt() |